1.概要

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

また、Springのhttps://docs.spring.io/spring-security-oauth2-boot/docs/current-SNAPSHOT/api/org/springframework/boot/autoconfigure/を使用して

Principal



Authorities

の両方を抽出する方法も示します。 security/oauth2/resource/PrincipalExtractor.html[

PrincipalExtractor

]およびhttps://docs.spring.io/spring-security-oauth2-boot/docs/current/api/org/springframework/boot/autoconfigure/security/oauth2/resource/AuthoritiesExtractor.html[

AuthoritiesExtractor

]インターフェース。

Spring Security OAuth2の紹介については、https://www.baeldung.com/spring-security-oauth[these]の記事を参照してください。

2. Mavenの依存関係

始めるには、https://search.maven.org/classic/#search%7C1%7Cg%3A%22org.springframework.security.oauth.boot%22%20AND%20a%3A%を追加する必要があります。 22spring-security-oauth2-autoconfigure%22[

spring-security-oauth2-autoconfigure

]私たちの

pom.xml

への依存関係:

<dependency>
    <groupId>org.springframework.security.oauth.boot</groupId>
    <artifactId>spring-security-oauth2-autoconfigure</artifactId>
    <version>2.0.1.RELEASE</version>
</dependency>

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


お入りください
。ユーザーデータを取得する – 取得するために取得したOAuthトークンを使用します

ユーザーのデータ

ユーザーのデータを取得すると、

Springはユーザーの

Principal

および

Authorities


を自動的に作成できます。

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

そうするために、** Springは、デフォルトの動作を上書きするために使用できる2つのインタフェースを提供します。


  • PrincipalExtractor

    – カスタムを提供するために使用できるインタフェース

Principalを抽出するロジック
**

AuthoritiesExtractor



PrincipalExtractor

に似ていますが、

代わりに

Authorities

抽出をカスタマイズするために使用されます

デフォルトでは、


Springは2つのコンポーネントを提供します –


FixedPrincipalExtractor


および


FixedAuthoritiesExtractor

これらのインターフェースを実装し、私たちのためにそれらを作成するための事前定義された戦略を持っている





_ –

_

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

私たちの場合、Githubのユーザーデータがどのように見えるか、そして私たちが自分たちに従ってそれらを調整するために使用できるものを知っていますニーズ。

そのため、Springのデフォルトコンポーネントをオーバーライドするには、これらのインタフェースも実装する2つの

Beans

を作成するだけです。

私たちのアプリケーションの

Principal

では、単にユーザーのGithubユーザー名を使用します。

public class GithubPrincipalExtractor
  implements PrincipalExtractor {

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

ユーザーのGithubサブスクリプションに応じて(無料、それ以外の場合は)、

GITHUB

USER

SUBSCRIBED

または

GITHUB

USER

FREE

の権限を付与します。

public class GithubAuthoritiesExtractor
  implements AuthoritiesExtractor {
    List<GrantedAuthority> GITHUB__FREE__AUTHORITIES
     = AuthorityUtils.commaSeparatedStringToAuthorityList(
     "GITHUB__USER,GITHUB__USER__FREE");
    List<GrantedAuthority> GITHUB__SUBSCRIBED__AUTHORITIES
     = AuthorityUtils.commaSeparatedStringToAuthorityList(
     "GITHUB__USER,GITHUB__USER__SUBSCRIBED");

    @Override
    public List<GrantedAuthority> extractAuthorities
      (Map<String, Object> 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. カスタム認証サーバを使用する

サードパーティに頼るのではなく、ユーザー用に独自の承認サーバーを使用することもできます。

使用することを決定した認証サーバーにもかかわらず、

Principal



Authorities

の両方をカスタマイズするために必要なコンポーネントは同じままです:


PrincipalExtractor





AuthoritiesExtractor


私たちは、

user-info-uri

エンドポイントによって返されるデータを** 認識し、適切であると思うようにそれを使用するだけです。


この

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

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 BaeldungPrincipalExtractor
  implements PrincipalExtractor {

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

権限に関しては、私たちのAuthorization Serverはすでにそれらをその

user-info-uri

のデータに入れています。

そのため、私たちはそれらを抽出し、充実させます。

public class BaeldungAuthoritiesExtractor
  implements AuthoritiesExtractor {

    @Override
    public List<GrantedAuthority> extractAuthorities
      (Map<String, Object> map) {
        return AuthorityUtils
          .commaSeparatedStringToAuthorityList(asAuthorities(map));
    }

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

それから、Beanを

SecurityConfig

クラスに追加します。

@Configuration
@EnableOAuth2Sso
public class SecurityConfig extends WebSecurityConfigurerAdapter {

   //...

    @Bean
    public PrincipalExtractor baeldungPrincipalExtractor() {
        return new BaeldungPrincipalExtractor();
    }

    @Bean
    public AuthoritiesExtractor baeldungAuthoritiesExtractor() {
        return new BaeldungAuthoritiesExtractor();
    }
}

5.まとめ

この記事では、ユーザー認証をサードパーティとカスタム認証サーバーに委任するアプリケーションを実装し、

Principal



Authorities

の両方をカスタマイズする方法を示しました。

いつものように、この例の実装はhttps://github.com/eugenp/tutorials/tree/master/spring-5-security-oauth[over on Github]にあります。

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

localhostで:8082