Spring Security OAuthでJWTを使用する

Spring Security OAuthでJWTを使用する

1. 概要

このチュートリアルでは、Spring SecurityOAuth2の実装でJSONWebトークンを利用する方法について説明します。

また、このOAuthシリーズのthe previous articleの上に構築を続けています。

参考文献:

OAuthで保護されたアプリケーションでのログアウト

JWTを使用してSpring Security OAuth2アプリケーションにログアウトを実装する方法についての実用的な詳細。

OAuth2リフレッシュトークンで記憶する

Spring SecurityとOAuth2で保護されたアプリケーションのために、Angularフロントエンドでremember-me機能を実装する方法を学びます。

Spring REST APIのOAuth2 – AngularJSで更新トークンを処理する

更新トークンをAngularJSクライアントアプリに保存する方法、期限切れのアクセストークンを更新する方法、およびZuulプロキシを活用する方法を学びました。

 

始める前に-1つの重要な注意事項。 the Spring Security core team is in the process of implementing a new OAuth2 stack –いくつかの側面はすでに出ており、いくつかはまだ進行中であることに注意してください。

これは、その取り組みに関するコンテキストを提供する簡単なビデオです。

 

さて、すぐに飛び込みましょう。

2. Mavenの構成

まず、pom.xmlspring-security-jwt依存関係を追加する必要があります。


    org.springframework.security
    spring-security-jwt

承認サーバーとリソースサーバーの両方にspring-security-jwt依存関係を追加する必要があることに注意してください。

3. 認可サーバー

次に、次のように、JwtTokenStoreを使用するように認証サーバーを構成します。

@Configuration
@EnableAuthorizationServer
public class OAuth2AuthorizationServerConfig extends AuthorizationServerConfigurerAdapter {
    @Override
    public void configure(AuthorizationServerEndpointsConfigurer endpoints)
      throws Exception {
        endpoints.tokenStore(tokenStore())
                 .accessTokenConverter(accessTokenConverter())
                 .authenticationManager(authenticationManager);
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        defaultTokenServices.setSupportRefreshToken(true);
        return defaultTokenServices;
    }
}

トークンに署名するためにJwtAccessTokenConvertersymmetric keyを使用したことに注意してください。つまり、ResourcesServerにも同じ正確なキーを使用する必要があります。

4. リソースサーバー

それでは、リソースサーバーの構成を見てみましょう。これは承認サーバーの構成と非常によく似ています。

@Configuration
@EnableResourceServer
public class OAuth2ResourceServerConfig extends ResourceServerConfigurerAdapter {
    @Override
    public void configure(ResourceServerSecurityConfigurer config) {
        config.tokenServices(tokenServices());
    }

    @Bean
    public TokenStore tokenStore() {
        return new JwtTokenStore(accessTokenConverter());
    }

    @Bean
    public JwtAccessTokenConverter accessTokenConverter() {
        JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
        converter.setSigningKey("123");
        return converter;
    }

    @Bean
    @Primary
    public DefaultTokenServices tokenServices() {
        DefaultTokenServices defaultTokenServices = new DefaultTokenServices();
        defaultTokenServices.setTokenStore(tokenStore());
        return defaultTokenServices;
    }
}

これら2つのサーバーは、完全に分離され、独立してデプロイ可能であると定義していることに注意してください。 これが、新しい構成で同じBeanのいくつかをここで再度宣言する必要がある理由です。

5. トークンのカスタムクレーム

次に、いくつかのcustom claims in the Access Tokenを追加できるようにインフラストラクチャを設定しましょう。 フレームワークによって提供される標準的な主張はすべて良好ですが、ほとんどの場合、クライアント側で利用するためにトークンにいくつかの追加情報が必要になります。

TokenEnhancerを定義して、これらの追加のクレームでアクセストークンをカスタマイズします。

次の例では、アクセストークンにフィールド「organization」を追加します–このCustomTokenEnhancerを使用します。

public class CustomTokenEnhancer implements TokenEnhancer {
    @Override
    public OAuth2AccessToken enhance(
      OAuth2AccessToken accessToken,
      OAuth2Authentication authentication) {
        Map additionalInfo = new HashMap<>();
        additionalInfo.put(
          "organization", authentication.getName() + randomAlphabetic(4));
        ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(
          additionalInfo);
        return accessToken;
    }
}

次に、それを次のようにAuthorization Server構成に配線します。

@Override
public void configure(
  AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
    TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
    tokenEnhancerChain.setTokenEnhancers(
      Arrays.asList(tokenEnhancer(), accessTokenConverter()));

    endpoints.tokenStore(tokenStore())
             .tokenEnhancer(tokenEnhancerChain)
             .authenticationManager(authenticationManager);
}

@Bean
public TokenEnhancer tokenEnhancer() {
    return new CustomTokenEnhancer();
}

この新しい構成が稼働していると、トークントークンペイロードは次のようになります。

{
    "user_name": "john",
    "scope": [
        "foo",
        "read",
        "write"
    ],
    "organization": "johnIiCh",
    "exp": 1458126622,
    "authorities": [
        "ROLE_USER"
    ],
    "jti": "e0ad1ef3-a8a5-4eef-998d-00b26bc2c53f",
    "client_id": "fooClientIdPassword"
}

5.1. JSクライアントでアクセストークンを使用する

最後に、AngualrJSクライアントアプリケーションでトークン情報を利用したいと思います。 そのためにangular-jwtライブラリを使用します。

したがって、これから行うことは、index.htmlの「organization」クレームを利用することです。