在oauth登录里面,我们使用密码模式来演示下登录,首先我们看看第一次登录:
我们再看看第二次登录的效果:
从两次登录的效果来看,我们可以看到登录的access_token是一样的,但是超时时间会减少,这是怎么回事呢?
这里其实就是因为用户第一次登录之后,给予了授权的token,然后也给了一个过期时间,后面我们每次登录的时候只需要取缓存即可,但是过期时间的话,随着时间的推移会慢慢减少(例如过期时间是今晚23点,第一次登录是下午1点登录,那么过期时间就还剩10个小时,第二次登录是下午5点,那么过期时间还剩6个小时)。
那么试想一下,如果我们是多客户端的模式来登录,首先我们在设备A上登录,此时生成一个token-a,返回给了设备A,过期时间是9:00,然后我们再设备B上登录,此时会直接返回token-a给设备B,过期时间也是9:00,那么在8点45的时候,设备A上刷新了token,此时token就变成了token-b。设备B还在使用token-a进行请求,此时就请求不通了,那么就去刷新token,此时token就变成了token-c,哪些设备A上的token-b也失效了,设备A继续刷,然后设备B就会失效,如此循环就会出问题,那么此时怎么办呢?有没有一种办法,设备A上登录返回的就是token-a,设备B上登录返回的是token-b,大家互不影响。这样是不是就好了。
这种解决方法在spring boot security oauth2上是有的,我们首先自定义一个类,这个类必须要集成自DefaultAuthenticationKeyGenerator,然后我们在这里进行key拼接即可,例如这里我们添加了一个device_type,代码示例如下:
package org.shop.oauth.server.rule; import java.util.LinkedHashMap; import java.util.Map; import java.util.TreeSet; import org.apache.commons.lang3.StringUtils; import org.springframework.security.oauth2.common.util.OAuth2Utils; import org.springframework.security.oauth2.provider.OAuth2Authentication; import org.springframework.security.oauth2.provider.OAuth2Request; import org.springframework.security.oauth2.provider.token.DefaultAuthenticationKeyGenerator; /** * @ClassName: CustomAuthenticationKeyGenerator * @Description: 自定义token生成规则 * * 这里主要是面对不同的端,设置不同的token,这样可以很方便的管理多端 */ public class CustomAuthenticationKeyGenerator extends DefaultAuthenticationKeyGenerator { private static final String SCOPE = "scope"; private static final String USERNAME = "username"; private static final String DEVICE_TYPE = "device_type"; @Override public String extractKey(OAuth2Authentication authentication) { Map<String, String> values = new LinkedHashMap<String, String>(); OAuth2Request authorizationRequest = authentication.getOAuth2Request(); if (!authentication.isClientOnly()) { values.put(USERNAME, authentication.getName()); } if (authorizationRequest.getScope() != null) { values.put(SCOPE, OAuth2Utils.formatParameterList(new TreeSet<String>(authorizationRequest.getScope()))); } String deviceType = authorizationRequest.getRequestParameters().get(DEVICE_TYPE); //不同的端不同的类别 if (StringUtils.isNotBlank(deviceType)) { values.put(DEVICE_TYPE, deviceType); } return generateKey(values); } }
然后我们在redis的缓存key里面设置下AuthenticationKeyGenerator即可,示例代码如下:
@Bean public TokenStore getJdbcTokenStore(){ RedisTokenStore tokenStore = new RedisTokenStore(connectionFactory); tokenStore.setAuthenticationKeyGenerator(new CustomAuthenticationKeyGenerator ()); return tokenStore; }
然后在public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception{}方法里面设置下tokenStore即可。
public void configure(AuthorizationServerEndpointsConfigurer endpoints) throws Exception { endpoints.userDetailsService(userService) .authenticationManager(authenticationManager) .tokenStore(this.getJdbcTokenStore()); }
此时我们在授权登录的时候,添加一个device_type的参数即可,例如:
然后我们换一个device_type
可以看到生成了不同的客户端。非常的方便。
最后按照惯例,附上本案例的源码,登录后即可下载
还没有评论,来说两句吧...