Spring Security+OAuth 2+JWT認証及び携帯ユーザ情報


Spring Boot、Spring SecurityはOAuth 2+JWT認証を実現します.
この文を読んで、JWTとOAuth 2に対して一定の理解がある子供用の靴を望みます.
JWT認証は、対称暗号化と非対称性の実現を提供する.
ソースの内容
ソースに関する二つのサービス
spring-book-oauth-jwt-server
spring-book-oauth-jwt-resource-server
認証サービス
認証・授権サービスを提供する
実現方式は、主にAuthortionServer Configrer Adapterを複写して実現します.
認証サービス1-対称暗号化方式
対称暗号化は、認証サーバと認証クライアントの共有鍵を表します.
実装
  • Access Token変換器-tokenを定義する生成方式は、ここでJWTを使用してtokenを生成し、対称暗号化はkeyなどの他の情報(カスタム)を加えるだけでよい.
  •           @Bean
              public JwtAccessTokenConverter accessTokenConverter() {
                  JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
                  converter.setSigningKey("123");
                  return converter;
              }
  • spring security tokenの生成方式
  • を教えます.
            @Override
                public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
                    endpoints.tokenStore(tokenStore())
                             .accessTokenConverter(accessTokenConverter())
                             .authenticationManager(authenticationManager);
                }
    以上対称的に暗号化されたJWT方式の認証サービスはOKです.後に対応するリソースサービスの内容があります.
    認証サービス2-非対称暗号化方式(公開鍵)
    サーバは、公開鍵と鍵を生成し、各クライアントは、取得した公開鍵を使用して認証を行う.したがって、まず証明書を生成し、公開鍵をエクスポートして、その後のステップを実行します.
    実装
  • は、JKSファイル
    keytool -genkeypair -alias mytest -keyalg RSA -keypass mypass -keystore mytest.jks -storepass mypass
    
  • を生成する.
    具体的なパラメータの意味は別に説明しません.
  • は、公開鍵
    keytool -list -rfc --keystore mytest.jks | openssl x509 -inform pem -pubkey
    
  • を導出する.
  • は、公開鍵テキスト
    -----BEGIN PUBLIC KEY-----
    MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAhAF1qpL+8On3rF2M77lR
    +l3WXKpGXIc2SwIXHwQvml/4SG7fJcupYVOkiaXj4f8g1e7qQCU4VJGvC/gGJ7sW
    fn+L+QKVaRhs9HuLsTzHcTVl2h5BeawzZoOi+bzQncLclhoMYXQJJ5fULnadRbKN
    HO7WyvrvYCANhCmdDKsDMDKxHTV9ViCIDpbyvdtjgT1fYLu66xZhubSHPowXXO15
    LGDkROF0onqc8j4V29qy5iSnx8I9UIMEgrRpd6raJftlAeLXFa7BYlE2hf7cL+oG
    hY+q4S8CjHRuiDfebKFC1FJA3v3G9p9K4slrHlovxoVfe6QdduD8repoH07jWULu
    qQIDAQAB
    -----END PUBLIC KEY-----
    
  • を生成する.
    public.txtとして保存します.mystest.jksとpublic.txtをreourceディレクトリの下に入れます.
  • ここでJwtAccess TokenCoverterを修正して、証明書を
  • に導入します.
            @Bean
            public TokenEnhancer accessTokenConverter() {
                final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
                KeyStoreKeyFactory keyStoreKeyFactory =
                        new KeyStoreKeyFactory(new ClassPathResource("mytest.jks"), "mypass".toCharArray());
                converter.setKeyPair(keyStoreKeyFactory.getKeyPair("mytest"));
    
                converter.setAccessTokenConverter(new CustomerAccessTokenConverter());
                return converter;
            }
    以上で非対称暗号化が可能になりました.
    追加情報(この部分の情報は暗号化方式に関係しない)
  • .tokenが携帯する情報を独自に生成する
  • .
    tokenの戻りに追加の情報が必要な場合もありますが、この部分はカスタムできます.token Enhancer Token Enhancerインターフェースをカスタマイズして、enhance(OAuth 2 Access Token var 1、OAuth 2 Authentication var 2)の方法を提供します.
    ここではユーザーの授権情報に参加しました.
                @Override
                public OAuth2AccessToken enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication) {
                    final Map additionalInfo = new HashMap<>();
                    User user = (User) authentication.getUserAuthentication().getPrincipal();
                    additionalInfo.put("username", user.getUsername());
                    additionalInfo.put("authorities", user.getAuthorities());
                    ((DefaultOAuth2AccessToken) accessToken).setAdditionalInformation(additionalInfo);
                    return accessToken;
                }
    同様にspring securityに教えます.このTokenEnhancerをToken Enhancerチェーンに入れます.
            //    token    
            TokenEnhancerChain tokenEnhancerChain = new TokenEnhancerChain();
            tokenEnhancerChain.setTokenEnhancers(Arrays.asList(customerEnhancer(), accessTokenConverter()));
            endpoints.tokenEnhancer(tokenEnhancerChain);
  • カスタムtoken情報に追加された情報
  • JWTでは、tokenに追加の情報を携帯する必要があり、サービス間で部分的なユーザ情報を共有することができ、spring securityはJWTのtokenにデフォルトでuser_を加入している.nameは、追加の情報が必要であれば、この部分をカスタマイズする必要があります.
    JwtAccess TokenCoverterは私達がtokenを生成するためのコンバータです.だから、この中の一部の情報を設定して私達の目的を達成する必要があります.Jwt Access Token CoverterはデフォルトでDefault Access Token Coverterを使ってtokenの生成、入れ換え、取得を処理します.Default Access TokenCoverterでは、UserAuthentication Coverterを使用して、tokenとuserinfoの取得、変換に対応しています.ですから、私たちはUserAuthentication Coverterの対応する変換方法を書き換える必要があります.
            @Override
            public Map convertUserAuthentication(Authentication authentication) {
                LinkedHashMap response = new LinkedHashMap();
                response.put("user_name", authentication.getName());
                response.put("name", ((User) authentication.getPrincipal()).getName());
                response.put("id", ((User) authentication.getPrincipal()).getId());
                response.put("createAt", ((User) authentication.getPrincipal()).getCreateAt());
                if (authentication.getAuthorities() != null && !authentication.getAuthorities().isEmpty()) {
                    response.put("authorities", AuthorityUtils.authorityListToSet(authentication.getAuthorities()));
                }
    
                return response;
            }
    JwtAccess TokenCoverterに教えて、私達の方式をデフォルトの方式に変えます.
            @Bean
            public TokenEnhancer accessTokenConverter() {
                final JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
                converter.setSigningKey("123");
                converter.setAccessTokenConverter(new CustomerAccessTokenConverter());
                return converter;
            }
    資源のサービス
    実現方式は、主にResource Server Configrer Adapterを複写して実現します.
    リソースサービス1-対称暗号化方式
    ここでの構成は認証サービスとほぼ一致しています.リソースサーバの構成はResource Server Configrer Adapterで構成されています.他のソースコードを見てください.
    リソースサービス2-非対称暗号化方式(公開鍵)
    public.txtをreourceディレクトリに入れてJwtAccess Token Coverterを修正します.
            @Bean
            public JwtAccessTokenConverter accessTokenConverter() {
                JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
                Resource resource = new ClassPathResource("public.txt");
                String publicKey = null;
                try {
                    publicKey = inputStream2String(resource.getInputStream());
                } catch (final IOException e) {
                    throw new RuntimeException(e);
                }
                converter.setVerifierKey(publicKey);
                converter.setAccessTokenConverter(new CustomerAccessTokenConverter());
                return converter;
            }
    そして走ることができます.
    効果の検証
    token取得
    code取得:
    http://127.0.0.1:8081/oauth/authorize?client_id=clientId&response_type=code&redirect_uri=http://127.0.0.1:8082/login/my
    redirect_.uri:認証サーバに配置されているものと一致する必要があります.clientid:client_IDも事前認証サーバーにあります.ここはデータベースに保存されているレスポンスです.type:デッドコードを書く
    ブラウザがログインした後のページです.
    アカウントのパスワードを入力して、これもデータベースに保存して、デフォルトはメモリに保存します.
    授権後にコードを取得することができます.
    http://127.0.0.1:8082/login/my?code=rTKETX
    このコードによってPOSTでtokenを取得します.
    http://127.0.0.1:8081/oauth/token?grant_type=authorization_code&code=rTKETX&redirect_uri=http://127.0.0.1:8082/login/my&client_id=clientId&client_secret=secret
    grant.type:ここでauthorizationを書きます.code code:上からもらったrTKETX redict_uri:同上不変client_id:同上不変client_secret:対応するパスワード
    結果は次の通りです.
    token検証
    http://127.0.0.1:8081/oauth/check_token?token=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9...
    
    ユーザ情報取得
    資源は実務に従うと展示しないです.