Spring Security OAuthを使用した主体と権限の抽出

Spring Security OAuthを使用したプリンシパルと権限の抽出

1. 概要

このチュートリアルでは、SpringBootとSpringSecurity OAuthを使用して、ユーザー認証をサードパーティとカスタム認証サーバーに委任するアプリケーションを作成する方法を説明します。

また、we’ll demonstrate how to extract both Principal and Authorities using Spring’s PrincipalExtractor and AuthoritiesExtractor interfaces.

Spring Security OAuth2の概要については、theseの記事を参照してください。

2. Mavenの依存関係

開始するには、pom.xmlspring-security-oauth2-autoconfigureの依存関係を追加する必要があります。


    org.springframework.security.oauth.boot
    spring-security-oauth2-autoconfigure
    2.0.1.RELEASE

3. Githubを使用したOAuth認証

次に、アプリケーションのセキュリティ構成を作成しましょう。

@Configuration
@EnableOAuth2Sso
public class SecurityConfig
  extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http)
      throws Exception {

        http.antMatcher("/**")
          .authorizeRequests()
          .antMatchers("/login**")
          .permitAll()
          .anyRequest()
          .authenticated()
          .and()
          .formLogin().disable();
    }
}

つまり、誰でも/loginエンドポイントにアクセスでき、他のすべてのエンドポイントにはユーザー認証が必要になるということです。

また、構成クラスに@EnableOAuthSsoアノテーションを付けました。これにより、アプリケーションがOAuthクライアントに変換され、そのように動作するために必要なコンポーネントが作成されます。

Springはデフォルトでほとんどのコンポーネントを作成しますが、いくつかのプロパティを設定する必要があります:

security.oauth2.client.client-id=89a7c4facbb3434d599d
security.oauth2.client.client-secret=9b3b08e4a340bd20e866787e4645b54f73d74b6a
security.oauth2.client.access-token-uri=https://github.com/login/oauth/access_token
security.oauth2.client.user-authorization-uri=https://github.com/login/oauth/authorize
security.oauth2.client.scope=read:user,user:email
security.oauth2.resource.user-info-uri=https://api.github.com/user

ユーザーアカウント管理を扱う代わりに、サードパーティ(この場合はGithub)に委任しているため、アプリケーションのロジックに集中できます。

4. プリンシパルと権限の抽出

OAuthクライアントとして機能し、サードパーティを介してユーザーを認証する場合、次の3つのステップを考慮する必要があります。

  1. ユーザー認証-ユーザーはサードパーティで認証します

  2. ユーザー承認–認証に続き、ユーザーがアプリケーションに代わって特定の操作を実行することを許可したときです。ここでscopesが登場します

  3. ユーザーデータの取得–取得したOAuthトークンを使用してユーザーのデータを取得します

ユーザーのデータを取得したら、Spring is able to automatically create the user’s Principal and Authorities

それは受け入れられるかもしれませんが、多くの場合、私たちはそれらを完全に制御したいシナリオで自分自身を見つけます。

これを行うには、Spring gives us two interfaces we can use to override its default behavior

  • PrincipalExtractorPrincipalを抽出するためのカスタムロジックを提供するために使用できるインターフェース

  • AuthoritiesExtractorPrincipalExtractorに似ていますが、代わりにAuthorities抽出をカスタマイズするために使用されます

デフォルトでは、これらのインターフェースを実装し、それらを作成するための事前定義された戦略を持つSpring provides two components – FixedPrincipalExtractor and FixedAuthoritiesExtractor 

4.1. Githubの認証のカスタマイズ

私たちの場合、Githubのユーザーデータがlikeにどのように見えるか、そしてニーズに応じてそれらを調整するために何を使用できるかを認識しています。

そのため、Springのデフォルトのコンポーネントをオーバーライドするには、これらのインターフェイスも実装する2つのBeansを作成する必要があります。

アプリケーションのPrincipalには、ユーザーのGithubユーザー名を使用するだけです。

public class GithubPrincipalExtractor
  implements PrincipalExtractor {

    @Override
    public Object extractPrincipal(Map map) {
        return map.get("login");
    }
}

ユーザーのGithubサブスクリプション(無料またはその他)に応じて、GITHUB_USER_SUBSCRIBEDまたはGITHUB_USER_FREEの権限をユーザーに付与します。

public class GithubAuthoritiesExtractor
  implements AuthoritiesExtractor {
    List GITHUB_FREE_AUTHORITIES
     = AuthorityUtils.commaSeparatedStringToAuthorityList(
     "GITHUB_USER,GITHUB_USER_FREE");
    List GITHUB_SUBSCRIBED_AUTHORITIES
     = AuthorityUtils.commaSeparatedStringToAuthorityList(
     "GITHUB_USER,GITHUB_USER_SUBSCRIBED");

    @Override
    public List extractAuthorities
      (Map map) {

        if (Objects.nonNull(map.get("plan"))) {
            if (!((LinkedHashMap) map.get("plan"))
              .get("name")
              .equals("free")) {
                return GITHUB_SUBSCRIBED_AUTHORITIES;
            }
        }
        return GITHUB_FREE_AUTHORITIES;
    }
}

次に、これらのクラスを使用してBeanも作成する必要があります。

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // ...

    @Bean
    public PrincipalExtractor githubPrincipalExtractor() {
        return new GithubPrincipalExtractor();
    }

    @Bean
    public AuthoritiesExtractor githubAuthoritiesExtractor() {
        return new GithubAuthoritiesExtractor();
    }
}

4.2. カスタム認証サーバーの使用

サードパーティに依存する代わりに、ユーザー用に独自の承認サーバーを使用することもできます。

使用することを決定した認証サーバーにもかかわらず、PrincipalAuthoritiesの両方をカスタマイズするために必要なコンポーネントは同じままです:PrincipalExtractorAuthoritiesExtractor

be aware of the data returned by the user-info-uri endpointを実行し、適切と思われる方法で使用する必要があります。

thisの記事で説明されている承認サーバーを使用してユーザーを認証するようにアプリケーションを変更しましょう。

security.oauth2.client.client-id=SampleClientId
security.oauth2.client.client-secret=secret
security.oauth2.client.access-token-uri=http://localhost:8081/auth/oauth/token
security.oauth2.client.user-authorization-uri=http://localhost:8081/auth/oauth/authorize
security.oauth2.resource.user-info-uri=http://localhost:8081/auth/user/me

承認サーバーを指定しているので、両方のエクストラクターを作成する必要があります。この場合、PrincipalExtractorは、nameキーを使用して、MapからPrincipalを抽出します。

public class examplePrincipalExtractor
  implements PrincipalExtractor {

    @Override
    public Object extractPrincipal(Map map) {
        return map.get("name");
    }
}

権限については、承認サーバーがすでにuser-info-uriのデータに配置しています。

そのため、それらを抽出して強化します。

public class exampleAuthoritiesExtractor
  implements AuthoritiesExtractor {

    @Override
    public List extractAuthorities
      (Map map) {
        return AuthorityUtils
          .commaSeparatedStringToAuthorityList(asAuthorities(map));
    }

    private String asAuthorities(Map map) {
        List authorities = new ArrayList<>();
        authorities.add("example_USER");
        List> authz =
          (List>) map.get("authorities");
        for (LinkedHashMap entry : authz) {
            authorities.add(entry.get("authority"));
        }
        return String.join(",", authorities);
    }
}

次に、BeanをSecurityConfigクラスに追加します。

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    // ...

    @Bean
    public PrincipalExtractor examplePrincipalExtractor() {
        return new examplePrincipalExtractor();
    }

    @Bean
    public AuthoritiesExtractor exampleAuthoritiesExtractor() {
        return new exampleAuthoritiesExtractor();
    }
}

5. 結論

この記事では、ユーザー認証をサードパーティとカスタム認証サーバーに委任するアプリケーションを実装し、PrincipalAuthoritiesの両方をカスタマイズする方法を示しました。

いつものように、この例の実装はover on Githubにあります。

ローカルで実行している場合は、localhost:8082でアプリケーションを実行してテストできます。