本文簡要分析了UAA的認證機制和部分源碼功能。
UAA全稱User Account and Authentication。
相關源碼都是通過Jhipster生成,包括UAA,Gateway,Identity。Jhipster簡介請參考這里。
1 OAuth2認證模式
1.1 密碼模式
密碼模式(Resource Owner Password Credentials)中,用戶向客戶端提供自己的用戶名和密碼。客戶端使用這些信息,向"認證服務器"進行認證。在這種模式中,用戶必須把自己的密碼給客戶端,但是客戶端不得儲存密碼。
流程如下:
a, 用戶向客戶端提供用戶名和密碼。
b, 客戶端將用戶名和密碼發給認證服務器,向后者請求令牌。
c, 認證服務器確認無誤后,向客戶端提供訪問令牌。
d, 客戶端之后所有訪問都會傳遞令牌。
1.2 客戶端模式
客戶端模式(Client Credentials)指客戶端以服務自身的名義,而不是以用戶的名義,向"認證服務器"進行認證。
流程如下:
a, 客戶端從配置文件或者數據庫獲取認證信息。
b, 客戶端將認證信息發給認證服務器,並請求返回一個訪問令牌。
c, 認證服務器確認認證信息無誤后,向客戶端提供訪問令牌。
d, 客戶端之后的所有訪問不會傳遞這個令牌。
2 UAA認證方式
2.1 用戶調用
oauth2認證模式: 密碼模式
配置文件相關內容
oauth2:
web-client-configuration:
#change client secret in production, keep in sync with UAA configuration
client-id: web_app
secret: changeit
時序圖

說明:這種認證方式是用在用戶訪問的場景,也就是服務間調用時總是帶着用戶名和密碼信息。
2.2 機器調用
oauth2認證模式: 密碼模式
配置文件相關內容
jhipster:
security:
client-authorization:
client-id: internal
client-secret: internal
時序圖

說明:這種認證方式是用在內部服務之間調用的場景,也就是服務間調用時是沒有用戶名和密碼信息的。JHipster生成的UAA是沒有這部分的代碼的,需要自己實現,參見JHipster技術棧定制 - 基於UAA的微服務之間安全調用
3 源碼分析
3.1 UAA
com.yourcompany.uaa.config.UaaConfiguration
注冊為認證服務器,注冊用戶調用客戶端(web_app)和機器調用客戶端(internal)。目前都是寫死的,如果需要保存所有客戶端到數據庫,需要修改方法configure(ClientDetailsServiceConfigurer clients)。
com.yourcompany.uaa.config.UaaProperties
uaa相關配置屬性和值。
com.yourcompany.uaa.config.UaaWebSecurityConfiguration
配置不需要認證的url。
com.yourcompany.uaa.security.DomainUserDetailsService
查詢數據庫返回包含完整用戶信息的對象。
com.yourcompany.uaa.security.IatTokenEnhancer
添加iat到token中,即token創建時間。
com.yourcompany.uaa.security.SecurityUtils
spring security 工具類,獲取當前線程用戶的登錄名,判斷當前登錄用戶是否認證過,判斷當前用戶是否具有指定的權限。
com.yourcompany.uaa.security.SpringSecurityAuditorAware
獲取當前線程用戶的登錄名,調用SecurityUtils的方法。
com.yourcompany.uaa.security.TokenProvider
創建token工具類。
org.springframework.security.core.userdetails.User
內置用戶類,保存用戶名,密碼,賬號是否過期,賬號是否鎖定,賬號憑證是否過期,是否可用。
org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter
內置過濾器,調用AuthenticationManager校驗form表單提交的用戶名密碼。
org.springframework.security.oauth2.provider.endpoint.TokenEndpoint
內置端點,接受客戶端請求,認證后返回token。
org.springframework.security.oauth2.provider.endpoint.TokenKeyEndpoint
內置端點,接受客戶端請求,返回驗證公鑰。
3.2 Gateway
com.yourcompany.gateway.web.filter.RefreshTokenFilter
過濾器,過濾傳入的請求並刷新到期之前的訪問令牌。
com.yourcompany.gateway.web.filter.RefreshTokenFilterConfigurer
配置類,配置refreshtokenfilter到工程里。
com.yourcompany.gateway.config.MicroserviceSecurityConfiguration
注冊為資源服務器,保護/api/和/management/等資源。
com.yourcompany.gateway.config.oauth2.OAuth2AuthenticationConfiguration
注冊為oauth2的資源服務器,保護/auth/logout, 注冊RefreshTokenFilterConfigurer到應用過濾鏈中。
com.yourcompany.gateway.config.oauth2.OAuth2JwtAccessTokenConverter
access token解碼器,將token解碼為身份對象;獲取uaa公鑰並配置為密鑰簽名保存在內存中。
com.yourcompany.gateway.config.oauth2.OAuth2Properties
保存配置文件中oauth2部分的屬性。
com.yourcompany.gateway.security.AuthoritiesConstants
對應uaa數據表jhi_authority。
com.yourcompany.gateway.security.SecurityUtils
spring security 工具類,獲取當前登錄用戶的登錄名,判斷當前登錄用戶是否認證過,判斷當前用戶是否具有指定的權限。
com.yourcompany.gateway.security.oauth2.CookieTokenExtractor
從cookie中解析出access token,使用了OAuth2CookeiHelper。
com.yourcompany.gateway.security.oauth2.OAuth2CookieHelper
cookie幫助類。 getClaim()方法可以從token中獲取明文信息。
com.yourcompany.gateway.security.oauth2.OAuth2AuthenticationService
管理OAuth2的身份驗證情況,保存(更新)access token和refresh token的Cookie。
com.yourcompany.gateway.security.oauth2.OAuth2Cookies
保存access token和refresh token。
com.yourcompany.gateway.security.oauth2.CookiesHttpServletRequestWrapper
請求映射器,用於修改原始請求中的cookie。
com.yourcompany.gateway.security.oauth2.CookieCollection
允許修改的Cookie集合,與單純的數組不同。
com.yourcompany.gateway.security.oauth2.OAuth2SignatureVerifierClient
接口, 定義方法getSignatureVerifier(), 表示創建一個SignatureVerifier,用於獲取公鑰並驗證JWT令牌。
com.yourcompany.gateway.security.oauth2.UaaSignatureVerifierClient
客戶端從UAA獲取公鑰並返回SignatureVerifier。實現了OAuth2SignatureVerifierClient接口的getSignatureVerifier()方法。
com.yourcompany.gateway.security.oauth2.OAuth2TokenEndpointClient
接口, 作為客戶端與OAuth2授權服務器的令牌終端通信。2個重要方法: sendPasswordGrant()和sendRefreshGrant()。
com.yourcompany.gateway.security.oauth2.OAuth2TokenEndpointClientAdapter
抽象類, 實現了OAuth2TokenEndpointClient的2個重要方法。定義了一個給請求頭中添加身份信息的抽象方法addAuthentication()。
com.yourcompany.gateway.security.oauth2.UaaTokenEndpointClient
繼承OAuth2TokenEndpointClientAdapter,實現OAuth2TokenEndpointClient。 作為客戶端與UAA服務器的令牌終端通信,實現了addAuthentication()方法,從配置文件中獲取如下配置,並放到請求頭中:
oauth2:
web-client-configuration:
client-id: web_app
secret: changeit
注意:
- 如果用戶登錄沒有勾選“記住我”,cookie里面的刷新令牌的key為: cookie_token;如果勾選了“記住我”,cookie里面的刷新令牌的key為: refresh_token
- 如果要嚴格判斷登出時間,需要通過緩存中間件保存logout登出信息。
3.3 Identity
com.yourcompany.identity.client.AuthorizedFeignClient
注解。 為機器調用添加認證信息。默認注冊攔截器OAuth2FeignRequestInterceptor。
com.yourcompany.identity.client.AuthorizedUserFeignClient
注解。為用戶調用添加認證信息。默認注冊攔截器UserFeignClientInterceptor
com.yourcompany.identity.client.OAuth2InterceptedFeignConfiguration
注冊Oauth2RequestInterceptor。
com.yourcompany.identity.client.OAuth2UserClientFeignConfiguration
注冊UserFeignClientInterceptor。
com.yourcompany.identity.client.UserFeignClientInterceptor
攔截器, 給resttemplate的請求頭中添加認證信息。
com.yourcompany.identity.config.MicroserviceSecurityConfiguration
注冊為資源服務器,保護/api/和/management/等資源。
com.yourcompany.identity.security.oauth2.OAuth2SignatureVerifierClient
接口, 定義方法getSignatureVerifier(), 表示創建一個SignatureVerifier,用於獲取公鑰並驗證JWT令牌。
com.yourcompany.identity.security.oauth2.UaaSignatureVerifierClient
客戶端從UAA獲取公鑰並返回SignatureVerifier。實現了OAuth2SignatureVerifierClient接口的getSignatureVerifier()方法。
