Spring Security式言語アノテーションで使用するカスタムメソッドを作成する方法


92

アノテーションを介したメソッドベースの承認のために、Spring Security Expression Languageで使用するカスタムメソッドを追加するクラスを作成したいと思います。

たとえば、「customMethodReturningBoolean」のようなカスタムメソッドを作成して、次のように使用します。

  @PreAuthorize("customMethodReturningBoolean()")
  public void myMethodToSecure() { 
    // whatever
  }

私の質問はこれです。可能であれば、カスタムクラスを作成するためにどのクラスをサブクラス化する必要がありますか、Spring xml構成ファイルでそれを構成するにはどうすればよいですか?


1
今は答えを入力する時間はありませんが、このガイドに従い、見事に機能しました:baeldung.com/…Spring Security 5.1.1を使用しています。
ポール

回答:


35

2つのクラスをサブクラス化する必要があります。

まず、新しいメソッド式ハンドラを設定します

<global-method-security>
  <expression-handler ref="myMethodSecurityExpressionHandler"/>
</global-method-security>

myMethodSecurityExpressionHandlerのサブクラスDefaultMethodSecurityExpressionHandlerをオーバーライドしcreateEvaluationContext()、にサブクラスを設定するサブクラスMethodSecurityExpressionRootになりMethodSecurityEvaluationContextます。

例えば:

@Override
public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
    MethodSecurityEvaluationContext ctx = new MethodSecurityEvaluationContext(auth, mi, parameterNameDiscoverer);
    MethodSecurityExpressionRoot root = new MyMethodSecurityExpressionRoot(auth);
    root.setTrustResolver(trustResolver);
    root.setPermissionEvaluator(permissionEvaluator);
    root.setRoleHierarchy(roleHierarchy);
    ctx.setRootObject(root);

    return ctx;
}

うーん、いい考えのように聞こえますが、DefaultMethodSecurityExpressionHandlerのすべてのプロパティはアクセサなしでプライベートなので、醜い反射なしにクラスを拡張する方法に興味がありました。ありがとう。
ジョセフラスト

1
trustResolverなどですか?これらのすべては、参照してください(少なくとも、春のセキュリティ3.0の)DefaultMethodSecurityExpressionHandlerでセッターを持っている:static.springsource.org/spring-security/site/apidocs/org/...
sourcedelica

3
@ericacmどのように周りを取得んMethodSecurityExpressionRootというパッケージのプライベート
C.ロス

175

言及された手法はどれも機能しなくなります。ユーザーがSecurityExpressionRootをオーバーライドできないようにするために、Springは長い時間をかけてきたようです。

編集11/19/14セキュリティ注釈を使用するようにSpringを設定します:

<beans ... xmlns:sec="http://www.springframework.org/schema/security" ... >
...
<sec:global-method-security pre-post-annotations="enabled" />

次のようなBeanを作成します。

@Component("mySecurityService")
public class MySecurityService {
    public boolean hasPermission(String key) {
        return true;
    }
}

次に、jspで次のようにします。

<sec:authorize access="@mySecurityService.hasPermission('special')">
    <input type="button" value="Special Button" />
</sec:authorize>

または、メソッドに注釈を付けます。

@PreAuthorize("@mySecurityService.hasPermission('special')")
public void doSpecialStuff() { ... }

さらに、アノテーションでSpring式言語@PreAuthorizeを使用して、現在の認証やメソッドの引数にアクセスできます。

例えば:

@Component("mySecurityService")
public class MySecurityService {
    public boolean hasPermission(Authentication authentication, String foo) { ... }
}

次に@PreAuthorize、新しいメソッドシグネチャと一致するようにを更新します。

@PreAuthorize("@mySecurityService.hasPermission(authentication, #foo)")
public void doSpecialStuff(String foo) { ... }

6
@BoshをhasPermissionメソッドで使用Authentication auth = SecurityContextHolder.getContext().getAuthentication();すると、現在の認証トークンを取得できます。
James Watkins

2
ジェームス、あなたの答えをありがとう。春の構成ファイルでmySecurityServiceを定義する必要がありますか?
WowBow 2013年

2
サービスが含まれているパッケージのコンポーネントスキャン設定がある場合は、XMLファイルでmySecurityServiceを定義する必要はありません。一致するコンポーネントスキャンがない場合は、XML Bean定義を使用する必要があります。@PreAuthorizeはorg.springframework.securityから取得
James Watkins

3
次のように、アノテーションにBeanの名前を指定する必要がある場合があります:@Component( "mySecurityService")または@Namedアノテーションを使用する。
James Watkins、2013

1
@VJS私が行った編集を見てください。これらのアノテーションを使用するには、Springを構成する必要があります。この重要な欠落した詳細について他の誰も不満を言っていないことに驚きます:)
James Watkins

14

ericacmに感謝しますが、いくつかの理由で機能しません:

  • DefaultMethodSecurityExpressionHandlerのプロパティはプライベートです(反射の可視性が望ましくない)
  • 少なくとも私のEclipseでは、MethodSecurityEvaluationContextオブジェクトを解決できません

違いは、既存のcreateEvaluationContextメソッドを呼び出してから、カスタムルートオブジェクトを追加することです。最後に、MethodSecurityEvaluationContextがコンパイラーで解決されないため(どちらも同じインターフェースから)、StandardEvaluationContextオブジェクトタイプを返しました。これは、私が現在運用しているコードです。

作るMethodSecurityExpressionHandlerは、当社独自のルートを使用します。

public class CustomMethodSecurityExpressionHandler extends DefaultMethodSecurityExpressionHandler  {

    // parent constructor
    public CustomMethodSecurityExpressionHandler() {
        super();
    }

    /**
     * Custom override to use {@link CustomSecurityExpressionRoot}
     * 
     * Uses a {@link MethodSecurityEvaluationContext} as the <tt>EvaluationContext</tt> implementation and
     * configures it with a {@link MethodSecurityExpressionRoot} instance as the expression root object.
     */
    @Override
    public EvaluationContext createEvaluationContext(Authentication auth, MethodInvocation mi) {
        // due to private methods, call original method, then override it's root with ours
        StandardEvaluationContext ctx = (StandardEvaluationContext) super.createEvaluationContext(auth, mi);
        ctx.setRootObject( new CustomSecurityExpressionRoot(auth) );
        return ctx;
    }
}

これは、SecurityExpressionRootを拡張することにより、デフォルトのルートを置き換えます。ここで、hasRoleの名前をhasEntitlementに変更しました。

public class CustomSecurityExpressionRoot extends SecurityExpressionRoot  {

    // parent constructor
    public CustomSecurityExpressionRoot(Authentication a) {
        super(a);
    }

    /**
     * Pass through to hasRole preserving Entitlement method naming convention
     * @param expression
     * @return boolean
     */
    public boolean hasEntitlement(String expression) {
        return hasRole(expression);
    }

}

最後に、securityContext.xmlを更新します(applcationContext.xmlから参照されていることを確認してください)。

<!-- setup method level security using annotations -->
<security:global-method-security
        jsr250-annotations="disabled"
        secured-annotations="disabled"
        pre-post-annotations="enabled">
    <security:expression-handler ref="expressionHandler"/>
</security:global-method-security>

<!--<bean id="expressionHandler" class="org.springframework.security.access.expression.method.DefaultMethodSecurityExpressionHandler">-->
<bean id="expressionHandler" class="com.yourSite.security.CustomMethodSecurityExpressionHandler" />

注: @Securedアノテーションは別の検証ハンドラーを通過するため、このオーバーライドを受け入れません。したがって、上記のxmlでは、後で混乱を防ぐためにそれらを無効にしました。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.