在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
可以看到生成了不同的客户端。非常的方便。
最后按照惯例,附上本案例的源码,登录后即可下载













还没有评论,来说两句吧...