概要概要
システムがOAuth2認証トークン情報を2つのカテゴリに返した後:不透明トークン(不透明トークン)と透明トークン(不透明トークンではない)。
不透明なトークンは、読み取り不可能なトークンの一種であり、一般的に言えば、通常のUUID文字列です。不透明なトークンを使用すると、リソースサービスはトークンが何であり、誰を表すかを認識しないため、システムのパフォーマンスと可用性が低下し、遅延が増加します。認証サーバーを呼び出して、トークンが誰であるかを知るためのユーザー情報インターフェイスを取得する必要があります。 。
以下は、リソースサーバーでの構成です。認証サーバーのインターフェイスアドレスを指定する必要があります。
security:
oauth2:
resource:
user-info-uri: http://localhost:5000/user/current/get
id: account-service
透過トークンの典型的な代表はJWTです。ユーザー情報はJWT文字列に格納されます。リソースサーバーはトークン自体を解析できるため、トークンを検証するために認証サーバーにアクセスする必要がなくなります。
前の章では、不透明なトークンaccess_tokenを使用しましたが、この集中型認証サービスがマイクロサービスシステムのボトルネックになることを考慮して、この章では、jwtを使用して前のaccess_token、特別な(zhuang)業界(bi)ポイントを置き換えます。分散化と呼ばれます。
jwtとは
Json Webトークン(JWT)は、JSONに基づくオープンスタンダード(RFC 7519)であり、Webアプリケーション環境間でクレームを転送するために実装されています。トークンはコンパクトで安全になるように設計されており、分散サイトのシングルサインオン(SSO)シナリオに特に適しています。JWT宣言は通常、認証されたユーザーID情報をIDプロバイダーとサービスプロバイダーの間で転送するために使用されます。これにより、リソースサーバーからリソースを取得したり、他のビジネスロジックに必要な宣言情報を追加したりできます。トークンは次のとおりです。また、認証に直接使用することも、暗号化することもできます。
簡単に言えば、これは固定形式の文字列であり、通常は暗号化されています。
ヘッダー、ペイロード、署名の3つの部分で構成され、これら3つの部分はすべてjson形式です。
- ヘッダー:JSONは、タイプや署名アルゴリズムなど、JWTの基本情報を記述します。Base64を使用して文字列としてエンコードする
- ペイロード:JWT情報はJSON形式で記述されます。標準の定義に加えて、カスタム情報を追加することもできます。また、Base64エンコーディングを文字列として使用します。
- iss:発行者
- サブ:ユーザー
- aud:レシーバー
- exp(expires):UNIXタイムスタンプで記述された有効期限
- iat(発行日):unixタイムスタンプで記述された発行時刻
- 署名:最初の2つの文字列を連結した後、ヘッダーで定義された暗号化アルゴリズムを使用し、キーを使用して署名し、署名情報を最後に追加します。
JWTは対称暗号化キーを使用できますが、非対称キーを使用する方が安全です。この記事では対称暗号化を使用します。
コードの変更
データベース
最初にaccess_tokenを使用したとき、oauth2に関連する7つのデータテーブルを作成しました
jwtを使用する場合は、クライアント情報をデータベースに保存するだけでよいため、データテーブルoauth_client_detailsを保持するだけで済みます。
他のデータテーブルは不要になり、削除できます。
認証サービスAuthorizationServerConfig
AuthorizationServerConfig
TokenStoreの構成を変更します
@Bean
public TokenStore tokenStore() {
//return new JdbcTokenStore(dataSource);
return new JwtTokenStore(jwtTokenEnhancer());
}
/**
* JwtAccessTokenConverter
* TokenEnhancer的子类,帮助程序在JWT编码的令牌值和OAuth身份验证信息之间进行转换。
*/
@Bean
public JwtAccessTokenConverter jwtTokenEnhancer(){
JwtAccessTokenConverter converter = new JwtAccessTokenConverter();
// 设置对称签名
converter.setSigningKey("javadaily");
return converter;
}
以前は、access_tokenをデータベースに保存していましたが、jwtを使用した後は、データベースに保存する必要がなくなったため、保存方法を変更する必要があります。
jwtは暗号化アルゴリズム署名を使用した情報を必要とします。ここでは、最初の対称秘密鍵(javadaily)を使用してトークンに署名します。もちろん、サーバーリソースも同じ秘密鍵を使用する必要がある対称秘密鍵です。
- 変更
configure(AuthorizationServerEndpointsConfigurer endpoints)
方法、構成jwt
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//如果需要使用refresh_token模式则需要注入userDetailService
endpoints.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailService)
.tokenStore(tokenStore())
.accessTokenConverter(jwtTokenEnhancer());
}
これは主にインジェクションaccessTokenConverter
、つまり上記で構成されたトークンコンバーターです。
上記の構成後、認証サーバーはすでにjwtトークンを生成できます。ここでは、最初にPostmanを使用して呼び出し、生成されたjwtトークンを確認します。
上の図から、jwtトークンが正常に生成されていることがわかり、生成されたjwtトークンをhttps://jwt.io/に移動して分析できます。
我々は非常に世代の理解されていない場合は、ロジックのトークンJWT、することができます
DefaultTokenServices#createAccessToken(OAuth2Authentication authentication)
し、JwtAccessTokenConverter#enhance(OAuth2AccessToken accessToken, OAuth2Authentication authentication)
上のブレークポイントを作成し、コード実行の効果を観察します。
删除认证服务器提供给资源服务器获取用户信息的接口
/**
* 获取授权的用户信息
* @param principal 当前用户
* @return 授权信息
*/@GetMapping("current/get")
public Principal user(Principal principal){
return principal;
}
透過トークンjwtトークンを使用した後、リソースサーバーはトークンを直接解析および検証でき、認証サーバーインターフェイスを呼び出す必要がなくなるため、ここで直接削除できます。
-
jwtトークンの有効期間を変更する(オプション)
デフォルトの期間は12時間のjwtトークンです。更新トークンは30日間有効です。デフォルトの時間
DefaultTokenServices
を変更する場合は、有効時間を挿入して変更できます。
@Primary
@Bean
public DefaultTokenServices tokenServices(){
DefaultTokenServices tokenServices = new DefaultTokenServices();
tokenServices.setTokenEnhancer(jwtTokenEnhancer());
tokenServices.setTokenStore(tokenStore());
tokenServices.setSupportRefreshToken(true);
//设置token有效期,默认12小时,此处修改为6小时 21600
tokenServices.setAccessTokenValiditySeconds(60 * 60 * 6);
//设置refresh_token的有效期,默认30天,此处修改为7天
tokenServices.setRefreshTokenValiditySeconds(60 * 60 * 24 * 7);
return tokenServices;
}
次にconfigure()
、tokenServicesメソッドを追加します
@Override
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception {
//如果需要使用refresh_token模式则需要注入userDetailService
endpoints.authenticationManager(this.authenticationManager)
.userDetailsService(userDetailService)
//注入自定义的tokenservice,如果不使用自定义的tokenService那么就需要将tokenServce里的配置移到这里
.tokenServices(tokenServices());
}
リソースサーバーResourceServerConfig
- リソースサーバーで構成されている認証サーバーのインターフェイスプロパティを削除します
user-info-uri
security:
oauth2:
resource:
id: account-service
- TokenStoreとJwtAccessTokenConverterを挿入します
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
@Bean
public JwtAccessTokenConverter jwtTokenEnhancer(){
JwtAccessTokenConverter jwtTokenEnhancer = new JwtAccessTokenConverter();
jwtTokenEnhancer.setSigningKey("javadaily");
return jwtTokenEnhancer;
}
注:対称暗号化アルゴリズムは、認証サーバーの秘密鍵と一致している必要があります。もちろん、構成ファイルに抽出することもできます。
configure(ResourceServerSecurityConfigurer resources)
メソッドの追加、トークン構成の追加
@Override
public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
resources.resourceId(resourceId)
.tokenStore(tokenStore());
}
質問:リソースサーバーがjwtを使用した後、トークンはどこで検証できますか?
アプリケーションに追加@EnableResourceServer
FilterChanを追加します春のセキュリティ注釈の後にOAuth2AuthenticationProcessingFilter
、OAuth2AuthenticationProcessingFilter
使用されるOAuth2AuthenticationManager
トークンを検証します。
検証ロジックの主なコード実行シーケンスは次のとおりです。
でOAuth2AuthenticationProcessingFilter#doFilter()
検証プロセスを体験するために休憩することをお勧めします。
ゲートウェイSecurityConfig
ReactiveJwtAuthenticationManager
tokenStoreからロードOAuth2AccessTokenを作成します
元のaccess_tokenはデータベースに保存されているためReactiveJdbcAuthenticationManager
、データベースからaccess_tokenを取得するように記述しました。現在はjwtです。同じReactiveJwtAuthenticationManager
コードの関連するクラスjwtも定義する必要があり、ReactiveJdbcAuthenticationManager
投稿されなくなりました。
- TokenStoreとJwtAccessTokenConverterを挿入します
@Bean
public TokenStore tokenStore() {
return new JwtTokenStore(jwtTokenEnhancer());
}
@Bean
public JwtAccessTokenConverter jwtTokenEnhancer(){
JwtAccessTokenConverter jwtTokenEnhancer = new JwtAccessTokenConverter();
jwtTokenEnhancer.setSigningKey("javadaily");
return jwtTokenEnhancer;
}
注:対称暗号化アルゴリズムは、認証サーバーの秘密鍵と一致している必要があります。もちろん、構成ファイルに抽出することもできます。
- 修正
SecurityConfig#SecurityWebFilterChain()
方法、交換ReactiveJdbcAuthenticationManager
ReactiveAuthenticationManager tokenAuthenticationManager
= new ReactiveJwtAuthenticationManager(tokenStore());
tokenStoreをコンストラクターに渡すだけです。
テスト
自分でテストしてください。
概要
jwtトークンとaccess_tokenの使用の最大の違いは、リソースサーバーがトークンを検証するためにサーバーを認証する必要がなくなったことです。これにより、システムの全体的なパフォーマンスが向上します。jwtを使用した後のプロジェクトのプロセスアーキテクチャは次のとおりです。
http://javadaily.cn/tags/SpringCloud
表示する前に記事の会場になりたい場合は、この一連の記事が最初の19になります。
jwtを使用すると、jwtの長所だけでなく短所も確認する必要があるため、実際のシーンに応じて自由に選択できます。jwtの2つの最大の短所は次のとおりです。
- Jwtは1回限りです。トークンが発行されると、有効期限が切れる前に有効になり、破棄することはできません。ユーザー権限を途中で変更して情報を更新する必要がある場合、再発行できるのはjwtのみですが、古いjwtは引き続き正常に使用でき、古いjwtを使用して取得した情報は古くなっています。
- jwtには認証情報が含まれています。リークされると、誰でもトークンのすべての権限を取得できます。流用を防ぐために、jwtの有効時間を長く設定しすぎないようにしてください。