咱们以前的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里面能够查看到对应的信息。