咱們以前的token生成處理都是在Authentication Server裏面作的處理。 首先咱們須要修改咱們以前定義的Authentication Server:MyAuthorizationServerConfig以前是使用註解@EnableAuthorizationServer開啓默認的Spring Security OAuth的默認配置。咱們如今繼承:AuthorizationServerConfigurerAdapter,其有針對3個不一樣的默認的配置:
AuthorizationServerEndpointsConfigurer:端點配置
ClientDetailsServiceConfigurer:針對於第三方客戶端配置;所謂的客戶端就是有哪些應用會訪問咱們的系統,咱們的認證服務器會決定給哪些第三方應用client去發送令牌。若是這個配置後咱們以前配置文件中配置的clientId和clientSecret將不會起做用了 AuthorizationServerSecurityConfigurer:針對於安全性配置 前端
以前咱們進行認證時候,發送的/oauth/token請求剛好是發送到TokenEndpoint(他是處理咱們oauth請求的);AuthorizationServerEndpointsConfigurer的配置其實就是針對於TokenEndpoint作一些端點配置。對AuthorizationServerEndpointsConfigurer進行配置時候,須要有對象:AuthenticationManager、UserDetailsService。咱們本身不定義配置AuthorizationServerEndpointsConfigurer的時候,系統會默認去應用找到其對應的屬性:AuthenticationManager、UserDetailsService;當咱們想使用本身的邏輯時候,將其屬性設置成咱們本身定義的bean 本身覆蓋其配置。redis
@Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { /** * 系統端點配置:endpoints * 1.使用咱們本身的受權管理器(AuthenticationManager)和自定義的用戶詳情服務(UserDetailsService) */ endpoints.authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { /** * 系統第三方客戶端配置: * 所謂的客戶端就是有哪些應用會訪問咱們的系統, * 咱們的認證服務器會決定給哪些第三方應用client去發送令牌。 * 若是這個配置後咱們以前配置文件中配置的clientId和clientSecret將不會起做用了 */ //目前咱們的應用場景是在咱們的app和咱們的前端;咱們不容許第三方來註冊,因此用內存 clients.inMemory().withClient("yxm") .secret("yxmsecret") .accessTokenValiditySeconds(7200)//發出去的令牌,有效期是多少? 這裏設置爲2小時 .authorizedGrantTypes("refresh_token","password")//針對當前應用客戶端:yxm,所能支持的受權模式是哪些?以前設置有4種類加上刷新總共5種:這裏只支持配置的:"refresh_token","password"。 .scopes("all","read","write");//發出去的權限有哪些?以前前端請求攜帶了scoope,此配置的scope用來指定前端發送scope的值必須在配置的裏面或者不攜帶scope;默認爲此處配置的scope } }
而後咱們重啓服務:嘗試下發送請求的效果. spring
返回結果中:expires_in是7199,剛好是咱們配置的7200s以內。
scope返回的是咱們client端配置的:"all read write"數據庫
{ "access_token": "e9cc6ce9-d241-44d9-9df3-dcfbf5ab1181", "token_type": "bearer", "refresh_token": "996949f9-d2ba-4d26-8456-1b678c5b1cf2", "expires_in": 7199, "scope": "all read write" }
針對於client端配置的:authorizedGrantTypes("refresh_token","password")
咱們嘗試使用:implicit json
咱們發送下:scope在客戶端不存在的類型:xxx
數組
咱們不發送scope
安全
若是咱們除了給yxm對應的client端受權外,咱們還須要給其餘客戶端受權。直接在後面加上and拼接便可。
服務器
可是又回到咱們以前說的呢?咱們這個模塊應該是通用的模塊,只須要配置便可實現接入。
OAuth2ClientPropertiesapp
public class OAuth2ClientProperties { //咱們把:ClientDetailsServiceConfigurer相關配置加進來 private String clientId; private String clientSecret; private int accessTokenValiditySeconds; public String getClientId() { return clientId; } public void setClientId(String clientId) { this.clientId = clientId; } public String getClientSecret() { return clientSecret; } public void setClientSecret(String clientSecret) { this.clientSecret = clientSecret; } public int getAccessTokenValiditySeconds() { return accessTokenValiditySeconds; } public void setAccessTokenValiditySeconds(int accessTokenValiditySeconds) { this.accessTokenValiditySeconds = accessTokenValiditySeconds; } }
OAuth2Properties:ide
public class OAuth2Properties { private OAuth2ClientProperties[] clients = {};//默認空數組 public OAuth2ClientProperties[] getClients() { return clients; } public void setClients(OAuth2ClientProperties[] clients) { this.clients = clients; } }
而後將其加入到security的配置下去:SecurityProperties
此時咱們去除demo裏面以前的默認的spring security oauth2客戶端配置,改成對應的配置。
#security: # oauth2: # client: # clientId: yxm # client_secret: yxmsecret
認證服務器裏面修改爲配置:
@Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private SecurityProperties securityProperties; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { /** * 系統端點配置:endpoints * 1.使用咱們本身的受權管理器(AuthenticationManager)和自定義的用戶詳情服務(UserDetailsService) */ endpoints.authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { /** * 系統第三方客戶端配置: * 所謂的客戶端就是有哪些應用會訪問咱們的系統, * 咱們的認證服務器會決定給哪些第三方應用client去發送令牌。 * 若是這個配置後咱們以前配置文件中配置的clientId和clientSecret將不會起做用了 */ //目前咱們的應用場景是在咱們的app和咱們的前端;咱們不容許第三方來註冊,因此用內存 /* clients.inMemory().withClient("yxm") .secret("yxmsecret") .accessTokenValiditySeconds(7200)//發出去的令牌,有效期是多少? 這裏設置爲2小時 .authorizedGrantTypes("refresh_token","password")//針對當前應用客戶端:yxm,所能支持的受權模式是哪些?以前設置有4種類加上刷新總共5種:這裏只支持配置的:"refresh_token","password"。 .scopes("all","read","write")//發出去的權限有哪些?以前前端請求攜帶了scoope,此配置的scope用來指定前端發送scope的值必須在配置的裏面或者不攜帶scope;默認爲此處配置的scope .and() .withClient("startshineye") .secret("startshineyesecret") .accessTokenValiditySeconds(3600) .authorizedGrantTypes("password") .scopes("read");*/ InMemoryClientDetailsServiceBuilder builder = clients.inMemory(); if(ArrayUtils.isNotEmpty(securityProperties.getOauth2().getClients())) {//判斷咱們的配置是否爲空 for (OAuth2ClientProperties client:securityProperties.getOauth2().getClients()){ builder.withClient(client.getClientId()) .secret(client.getClientSecret()) .accessTokenValiditySeconds(client.getAccessTokenValiditySeconds()) .authorizedGrantTypes("refresh_token", "authorization_code", "password") .scopes("all"); } } } }
咱們如今使用第二次配置:startshineye,並將其accessTokenValiditySeconds配置
咱們如今使用第二次配置:startshineye,並將其accessTokenValiditySeconds不配置,返回的json對象中沒有令牌:
咱們如今的令牌是存儲到內存中的,一旦咱們服務重啓的話。內存中的令牌就丟失了,因此咱們須要將令牌存儲到持久化的數據庫或者redis中,因爲令牌是訪問比較頻繁的,因此咱們將其配置到redis中。使用redis你不用去維護表的結構而且過時時間自動設置且性能比數據庫快不少。
咱們以前將到過TokenStore,他是用來負責令牌的存取,如今咱們寫一個TokenStoreConfig配置類。
@Configuration public class TokenStoreConfig { @Autowired private RedisConnectionFactory redisConnectionFactory; @Bean public TokenStore redisTokenStore(){ return new RedisTokenStore(redisConnectionFactory); } }
在咱們的認證服務器上引入自定義TokenStore:
@Configuration @EnableAuthorizationServer public class MyAuthorizationServerConfig extends AuthorizationServerConfigurerAdapter { @Autowired private AuthenticationManager authenticationManager; @Autowired private UserDetailsService userDetailsService; @Autowired private SecurityProperties securityProperties; @Autowired private TokenStore redisTokenStore; @Override public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { /** * 系統端點配置:endpoints * 1.使用咱們本身的受權管理器(AuthenticationManager)和自定義的用戶詳情服務(UserDetailsService) */ endpoints.tokenStore(redisTokenStore) .authenticationManager(authenticationManager) .userDetailsService(userDetailsService); } @Override public void configure(ClientDetailsServiceConfigurer clients) throws Exception { /** * 系統第三方客戶端配置: * 所謂的客戶端就是有哪些應用會訪問咱們的系統, * 咱們的認證服務器會決定給哪些第三方應用client去發送令牌。 * 若是這個配置後咱們以前配置文件中配置的clientId和clientSecret將不會起做用了 */ //目前咱們的應用場景是在咱們的app和咱們的前端;咱們不容許第三方來註冊,因此用內存 InMemoryClientDetailsServiceBuilder builder = clients.inMemory(); if(ArrayUtils.isNotEmpty(securityProperties.getOauth2().getClients())) {//判斷咱們的配置是否爲空 for (OAuth2ClientProperties client:securityProperties.getOauth2().getClients()){ builder.withClient(client.getClientId()) .secret(client.getClientSecret()) .accessTokenValiditySeconds(client.getAccessTokenValiditySeconds()) .authorizedGrantTypes("refresh_token", "authorization_code", "password") .scopes("all"); } } } }
測試:
咱們從redis裏面能夠查看到對應的信息。