问题复现
- 项目中使用了app+ pc+ 小程序,当用户同时登录app+pc时 其中一端会被挤下线。

出现原因
- 我们使用的是redis存储token,由于redis生token算法原因,多端登录返回同一个token,导致另外一端被挤下线,出现文章开头的情况。
- 下图就是security基于redis生成token的方式


- 可见:extractKey方法中使用values去生成token,多端登录参数进入values都一样
- 所以我们只需要重写token生成规则即可。
解决方式:重写token生成规则
- 加入登录端标识,每个端登录都需要传不一样的标识,比如:app:1,pc:2
- 这样不同端生成token不一样不会相互影响
/**
* @ClassName: CustomAuthenticationKeyGenerator
* @Description: 自定义token生成规则
* @author: ruyi
* @date: 2022/2/28 19:25
*/
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 (CharSequenceUtil.isNotBlank(deviceType)) {
values.put(DEVICE_TYPE, deviceType);
}
// 如果是多租户系统,这里要区分租户ID 条件
return generateKey(values);
}
}
将自定义token生成规则装配进来
/**
* @ClassName: CustomTokenStoreAutoConfiguration
* @Description: redis token store 自动配置
* @author: ruyi
* @date: 2022/2/28 19:25
*/
@RequiredArgsConstructor
@Configuration(proxyBeanMethods = false)
public class CustomTokenStoreAutoConfiguration {
private final KeyStrResolver resolver;
private final RedisConnectionFactory connectionFactory;
@Bean
public TokenStore tokenStore() {
ThgplatformRedisTokenStore tokenStore = new ThgplatformRedisTokenStore(connectionFactory, resolver);
tokenStore.setPrefix(SecurityConstants.PIGX_PREFIX + SecurityConstants.OAUTH_PREFIX);
tokenStore.setAuthenticationKeyGenerator(new CustomAuthenticationKeyGenerator () {
@Override
public String extractKey(OAuth2Authentication authentication) {
// 增加租户隔离部分 租户ID:原生计算值
return resolver.extract(super.extractKey(authentication), StrUtil.COLON);
}
});
return tokenStore;
}
}
/**
* 字符串处理,方便其他模块解耦处理
*/
public interface KeyStrResolver {
/**
* 字符串加工
* @param in 输入字符串
* @param split 分割符
* @return 输出字符串
*/
String extract(String in, String split);
/**
* 字符串获取
* @return 模块返回字符串
*/
String key();
}
- SecurityConstants.PIGX_PREFIX 与SecurityConstants.OAUTH_PREFIX是两个项目常量,可以自定义或者不加,不会影响生成。
测试一下
- device_type =1

- device_type =2

两次不同的device_type 返回的access_token都不一样- pc端也是在线的,不受影响
