java B2B2C springmvc mybatis電子商務平臺原始碼-Spring Cloud Security

weixin_33763244發表於2018-12-11

一、SpringCloud Security簡介
          Spring Cloud Security提供了一組原語,用於構建安全的應用程式和服務,而且操作簡便。可以在外部(或集中)進行大量配置的宣告性模型有助於實現大型協作的遠端元件系統,通常具有中央身份管理服務。它也非常易於在Cloud Foundry等服務平臺中使用。在Spring Boot和Spring Security OAuth2的基礎上,可以快速建立實現常見模式的系統,如單點登入,令牌中繼和令牌交換。願意瞭解原始碼的朋友直接求求交流分享技術:二一四七七七五六三三

功能:

從Zuul代理中的前端到後端服務中繼SSO令牌
資源伺服器之間的中繼令牌
使Feign客戶端表現得像OAuth2RestTemplate(獲取令牌等)的攔截器
在Zuul代理中配置下游身份驗證

二、SpringCloud Security知識點

封裝順序是這樣的:spring security及其各個模組=》spring cloud security=》spring boot autoconfigure的security部分,比如autoconfigure模組有個spring security的sso,是對spring security在oath2下的封裝

spring oauth2 authorizeserver,resourceserver,認證伺服器和資源伺服器是怎麼互動的,token_key,/oauth/token/ refresh/token

resourceserver就是業務系統,oauth client 就是邊緣業務系統,比如直接面向使用者的UI系統,或者UI系統直接呼叫的API介面這一層;

JWT和OAuth2的區別?看到好多人在比較這兩個東西,現在終結這個問題:JWT只是OAuth2中的token的一種型別。

jwt client(Resource Server或者Zuul等),使用jwt的業務系統在解碼acces_token的時候,需要一個toke_key,這個token-key就是JWT Client應用啟動的時候從Auth Server拉取的,介面是token/token_key

單點登入這種功能,好多javaee容器都自帶的,像websphere
spring Security完全將認證和授權分開了,資源只需要宣告自己是需要認證的,需要什麼樣的許可權,只管跟當前使用者要access_token。

授權的四種方式任意,只要拿到token就可以去讓資源去認證。

邊緣伺服器需要開啟@EnableOAuth2Sso,但是邊緣伺服器也是一個ResourceServer,邊緣伺服器如果是zuul的話,就不是一個ResourceServer了,只需要新增@EnableOAuth2Sso註解就可以了;

client_credentials模式下spring boot不會幫助spring Security構建ClientCredentialsResourceDetails 物件,需要開發者自己建立

favicon.icon,記得把這個東西過濾掉,奶奶的

在其中一個邊緣服務上,您可能需要啟用單點登入。

@EnableOAuthSso,只需要在邊緣伺服器指定沒用來引導未登入的使用者登入系統。@EnableOAuthSso將允許您將未經認證的使用者的自動重定向轉向授權伺服器,他們將能夠登入
EnableOAuth2Client,在中間中繼的時候用
ClientCredentialsTokenEndpointFilter,AS設定了allowFormAuthenticationForClients才會有,詳情看這裡面的AuthorizationServerSecurityConfigurer#configure(HttpSecurity http)邏輯,這點非常重要,ClientCredentialsTokenEndpointFilter是用來驗證clientid和client_secret的,使用clientid和client_secret換取下一步的東西;

TokenGranter,AuthorizationCodeTokenGranter,ClientCredentialsTokenGranter,RefreshTokenGranter,ImplicitTokenGranter,ResourceOwnerPasswordTokenGranter

TokenServices分為兩類,一個是用在AuthenticationServer端,AuthorizationServerTokenServices,ResourceServer端有自己的tokenServices介面,

BearerTokenExtractor,從其可以看出,token的獲取順序,Header,parameters(get/post)

spring security 保護自己的配置,作為ResourceServer的許可權配置和作為AuthorizationServer的配置都是在不同的地方

An OAuth 2 authentication token can contain two authentications: one for the client(OAuth2 Client) and one for the user. Since some OAuth authorization grants don’t require user authentication, the user authentication may be null.

jwt是不需要儲存access_toen的,jwt的機制就是將所有的資訊都存在了token裡面,從JwtTokenStore也可以看出來

OAuth2AuthenticationManager是密切與token認證相關的,而不是與獲取token密切相關的。這是真正認證的地方,一會重點debug,resourceIds

每一個ResourceServer在配置的時候,

ResourceServerConfiguration,需要配置一個resourceID,一個ResourceServer只能配置一個

oauth/token = 先驗證的是clientid和clientsecret,接著在驗證username和userpassword,都是用的ProvideManager,兩次驗證是兩個不同的請求,oauth2客戶端會使用RestTemplate請求伺服器的介面

ClientCredentialsTokenEndpointFilter用來驗證clientId和clientsecret的: 

OAuth2ClientAuthenticationProcessingFilter:OAuth2客戶端用來從OAuth2認證伺服器獲取access token,也可以從OAuth2認證伺服器載入authentication物件到OAuth2客戶端的SecurityContext物件中;裡面呼叫OAuth2AuthenticationManager#authenticate()方法使用DefaultTokenServices ,DefaultTokenServices 使用JwtTokenStore,JwtTokenStore使用JwtAccessTokenConverter來將JWT解密成Auth物件。 來從AuthServer請求授權資訊
accessToken被解密成如下的JWT物件: 

{“alg”:”RS256”,”typ”:”JWT”} {“exp”:1503758022,”user_name”:”admin”,”authorities”:[“ROLE_TRUSTED_CLIENT”,”ROLE_ADMIN”,”ROLE_USER”],”jti”:”d56f43d2-6c4a-46cf-85f3-050ee195a2bd”,”client_id”:”confidential”,”scope”:[“read”]} [128 crypto bytes]

AbstractSecurityInterceptor#befroeInvaction 是ResourceServer獲取認證資訊的地方

只要是需要驗證token有效性的都需要jwt.key-uri的配置

AffirmativeBased值得debug
 
TIPS

@Override
    public void configure(WebSecurity web) throws Exception {
        web.ignoring().antMatchers("/favicon.ico");
    }
 
    @Bean
    @Override
    protected UserDetailsService userDetailsService(){
        InMemoryUserDetailsManager manager = new InMemoryUserDetailsManager();
        manager.createUser(User.withUsername("user").password("password").roles("USER").authorities("USER").build());
        manager.createUser(User.withUsername("admin").password("password").roles("USER", "ADMIN", "TRUSTED_CLIENT").authorities("USER").build());
        return manager;
    }

這兩種方式有差別,牽扯到UsernamePasswordAuthenticationFilter和ClientCredentialsTokenEndpointFilter


security: 
  oauth2:
    client:
      client-id: confidential
      client-secret: secret
      access-token-uri: http://localhost:8080/oauth/token
      user-authorization-uri: http://localhost:8080/oauth/authorize
      use-current-uri: true
    resource: 
      jwt:
        key-uri: http://localhost:8080/oauth/token_key
      filter-order: 3  

client裡面的配置最終是用來生成OAuth2ProtectedResourceDetails的bean的,參看OAuth2ProtectedResourceDetailsConfiguration

整體程式碼結構如下:資料和原始碼來源 
20181210091941557

相關文章