Spring SecurityのカスタムAccessDecisionVoters

Spring SecurityのカスタムAccessDecisionVoters

1. 前書き

ほとんどの場合、Spring WebアプリケーションまたはREST APIを保護する場合、Spring Securityが提供するツールで十分ですが、より具体的な動作を求めている場合があります。

このチュートリアルでは、カスタムAccessDecisionVoterを作成し、それを使用してWebアプリケーションの承認ロジックを抽象化し、アプリケーションのビジネスロジックから分離する方法を示します。

2. Scenario

AccessDecisionVoterがどのように機能するかを示すために、USERADMIN,の2つのユーザータイプを使用してシナリオを実装します。このシナリオでは、USERは偶数番号でのみシステムにアクセスできます。分、ADMINは常にアクセスを許可されます。

3. AccessDecisionVoterの実装

最初に、承認の最終決定を行う際にカスタム投票者と一緒に参加する、Springによって提供されるいくつかの実装について説明します。 次に、カスタム投票者を実装する方法を見ていきます。

3.1. デフォルトのAccessDecisionVoter実装

Spring Securityは、いくつかのAccessDecisionVoter実装を提供します。 ここでは、それらのいくつかをセキュリティソリューションの一部として使用します。

これらのデフォルトの有権者の実装がいつどのように投票するかを見てみましょう。

AuthenticatedVoterは、Authenticationオブジェクトの認証レベルに基づいて投票します。具体的には、完全に認証されたプリンシパル、remember-meで認証されたプリンシパル、または最後に匿名のいずれかを探します。

構成属性のいずれかが文字列“ROLEで始まる場合、RoleVoterが投票します。_そうである場合、AuthenticationオブジェクトのGrantedAuthorityリストでロールを検索します。 。

WebExpressionVoterを使用すると、SpEL(Spring Expression Language)を使用して、@PreAuthorizeアノテーションを使用してリクエストを承認できます。

たとえば、Java構成を使用している場合:

@Override
protected void configure(final HttpSecurity http) throws Exception {
    ...
    .antMatchers("/").hasAnyAuthority("ROLE_USER")
    ...
}

または、XML構成を使用します–intercept-urlタグ内のhttpタグ内でSpELを使用できます。


    
    ...

3.2. カスタムAccessDecisionVoterの実装

次に、AccessDecisionVoterインターフェースを実装して、カスタム投票者を作成しましょう。

public class MinuteBasedVoter implements AccessDecisionVoter {
   ...
}

提供しなければならない3つのメソッドの最初は、voteメソッドです。 voteメソッドは、カスタム投票者の最も重要な部分であり、承認ロジックが使用される場所です。

voteメソッドは、次の3つの可能な値を返すことができます。

  • ACCESS_GRANTED –有権者が肯定的な回答をします

  • ACCESS_DENIED –有権者が否定的な回答をする

  • ACCESS_ABSTAIN –有権者は投票を控えます

voteメソッドを実装しましょう。

@Override
public int vote(
  Authentication authentication, Object object, Collection collection) {
    return authentication.getAuthorities().stream()
      .map(GrantedAuthority::getAuthority)
      .filter(r -> "ROLE_USER".equals(r)
        && LocalDateTime.now().getMinute() % 2 != 0)
      .findAny()
      .map(s -> ACCESS_DENIED)
      .orElseGet(() -> ACCESS_ABSTAIN);
}

voteメソッドでは、リクエストがUSERからのものかどうかを確認します。 その場合、偶数の分であればACCESS_GRANTEDを返し、そうでない場合はACCESS_DENIED.を返します。リクエストがUSER,からのものでない場合は、投票を棄権して%(t5 )s。

2番目のメソッドは、投票者が特定の構成属性をサポートしているかどうかを返します。 この例では、投票者はカスタム構成属性を必要としないため、trueを返します。

@Override
public boolean supports(ConfigAttribute attribute) {
    return true;
}

3番目のメソッドは、投票者が保護されたオブジェクトタイプに投票できるかどうかを返します。 投票者は保護されたオブジェクトタイプに関心がないため、trueを返します。

@Override
public boolean supports(Class clazz) {
    return true;
}

4. AccessDecisionManager

最終的な承認の決定は、AccessDecisionManagerによって処理されます。

AbstractAccessDecisionManagerには、AccessDecisionVotersのリストが含まれています。これらは互いに独立して投票する責任があります。

最も一般的なユースケースをカバーするために投票を処理するための3つの実装があります。

  • AffirmativeBasedAccessDecisionVotersのいずれかが賛成票を返した場合にアクセスを許可します

  • ConsensusBased –反対票よりも賛成票の方が多い場合にアクセスを許可します(棄権したユーザーを無視します)

  • UnanimousBased –すべての有権者が棄権するか、賛成票を返す場合にアクセスを許可します

もちろん、カスタムの意思決定ロジックを使用して独自のAccessDecisionManagerを実装できます。

5. 設定

チュートリアルのこの部分では、カスタムAccessDecisionVoterAccessDecisionManagerで構成するためのJavaベースおよびXMLベースのメソッドを見ていきます。

5.1. Java設定

Spring WebSecurityの構成クラスを作成しましょう。

@Configuration
@EnableWebSecurity
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
...
}

そして、カスタマイズされた投票者リストを使用して、UnanimousBasedマネージャーを使用するAccessDecisionManagerBeanを定義しましょう。

@Bean
public AccessDecisionManager accessDecisionManager() {
    List> decisionVoters
      = Arrays.asList(
        new WebExpressionVoter(),
        new RoleVoter(),
        new AuthenticatedVoter(),
        new MinuteBasedVoter());
    return new UnanimousBased(decisionVoters);
}

最後に、以前に定義したBeanをデフォルトのAccessDecisionManagerとして使用するようにSpringSecurityを構成しましょう。

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
    ...
    .anyRequest()
    .authenticated()
    .accessDecisionManager(accessDecisionManager());
}

5.2. XML構成

XML構成を使用している場合は、spring-security.xmlファイル(またはセキュリティ設定が含まれているファイル)を変更する必要があります。

まず、<http>タグを変更する必要があります。


  
  ...

次に、カスタム投票者用のBeanを追加します。

次に、AccessDecisionManagerのBeanを追加します。


    
        
            
            
            
            
        
    

シナリオをサポートする<authentication-manager>タグのサンプルを次に示します。


    
        
            
            
        
    

Java構成とXML構成の組み合わせを使用している場合、XMLを構成クラスにインポートできます。

@Configuration
@ImportResource({"classpath:spring-security.xml"})
public class XmlSecurityConfig {
    public XmlSecurityConfig() {
        super();
    }
}

6. Conclusion

このチュートリアルでは、AccessDecisionVotersを使用してSpringWebアプリケーションのセキュリティをカスタマイズする方法を検討しました。 Spring Securityが提供する有権者が私たちのソリューションに貢献したのを見ました。 次に、カスタムAccessDecisionVoterを実装する方法について説明しました。

次に、AccessDecisionManagerが最終的な承認決定を行う方法について説明し、すべての有権者が投票した後、Springが提供する実装を使用してこの決定を行う方法を示しました。

次に、JavaとXMLを使用して、AccessDecisionManagerAccessDecisionVotersのリストを構成しました。

実装はGithub projectにあります。

プロジェクトがローカルで実行されると、ログインページにアクセスできます。

http://localhost:8080/spring-security-custom-permissions/login

USERの資格情報は「user」と「pass」であり、ADMINの資格情報は「admin」と「pass」です。