mirror of https://gitee.com/stylefeng/roses
【auth】重构sessionManager
parent
c6bd3aebdf
commit
2a4f76ce32
|
@ -59,12 +59,24 @@
|
|||
<artifactId>spring-web</artifactId>
|
||||
</dependency>
|
||||
|
||||
<!--redis的依赖-->
|
||||
<!--缓存的依赖-->
|
||||
<!--session manager可以用redis,可以用内存的-->
|
||||
<dependency>
|
||||
<groupId>org.springframework.boot</groupId>
|
||||
<artifactId>spring-boot-starter-data-redis</artifactId>
|
||||
<optional>true</optional>
|
||||
<groupId>com.sedinbj.kernel</groupId>
|
||||
<artifactId>cache-api</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sedinbj.kernel</groupId>
|
||||
<artifactId>cache-sdk-memory</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
<dependency>
|
||||
<groupId>com.sedinbj.kernel</groupId>
|
||||
<artifactId>cache-sdk-redis</artifactId>
|
||||
<version>1.0.0</version>
|
||||
<scope>provided</scope>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
|
|
@ -1,32 +1,26 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session;
|
||||
|
||||
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
|
||||
import com.sedinbj.kernel.cache.api.CacheOperatorApi;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_TOKEN_PREFIX;
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_USERID_PREFIX;
|
||||
|
||||
/**
|
||||
* 基于内存的会话管理
|
||||
* 基于redis的会话管理
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2019-09-28-14:43
|
||||
*/
|
||||
public class MemoryCacheSessionManager implements SessionManagerApi {
|
||||
public class DefaultSessionManager implements SessionManagerApi {
|
||||
|
||||
/**
|
||||
* 登录用户缓存
|
||||
* <p>
|
||||
* key是 LOGGED_TOKEN_PREFIX + 用户的token
|
||||
*/
|
||||
private final TimedCache<String, LoginUser> loginUserCache;
|
||||
private final CacheOperatorApi<LoginUser> loginUserCache;
|
||||
|
||||
/**
|
||||
* 用户token的缓存,这个缓存用来存储一个用户的所有token
|
||||
|
@ -37,57 +31,60 @@ public class MemoryCacheSessionManager implements SessionManagerApi {
|
|||
* <p>
|
||||
* 这个缓存应该定时刷新下,因为有过期token的用户,所以这个里边的值set得清理
|
||||
*/
|
||||
private final Map<String, Set<String>> loginTokenCache = new HashMap<>();
|
||||
private final CacheOperatorApi<Set<String>> allPlaceLoginTokenCache;
|
||||
|
||||
public MemoryCacheSessionManager(TimedCache<String, LoginUser> loginUserCache) {
|
||||
/**
|
||||
* session的超时时间
|
||||
*/
|
||||
private final Long sessionExpiredSeconds;
|
||||
|
||||
public DefaultSessionManager(CacheOperatorApi<LoginUser> loginUserCache, CacheOperatorApi<Set<String>> allPlaceLoginTokenCache, Long sessionExpiredSeconds) {
|
||||
this.loginUserCache = loginUserCache;
|
||||
this.allPlaceLoginTokenCache = allPlaceLoginTokenCache;
|
||||
this.sessionExpiredSeconds = sessionExpiredSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSession(String token, LoginUser loginUser) {
|
||||
|
||||
// 装配用户信息的缓存
|
||||
loginUserCache.put(getTokenKey(token), loginUser);
|
||||
loginUserCache.put(token, loginUser, sessionExpiredSeconds);
|
||||
|
||||
// 装配用户token的缓存
|
||||
String userIdKey = getUserIdKey(loginUser.getUserId());
|
||||
Set<String> theUserTokens = loginTokenCache.get(userIdKey);
|
||||
Set<String> theUserTokens = allPlaceLoginTokenCache.get(loginUser.getUserId().toString());
|
||||
if (theUserTokens == null) {
|
||||
HashSet<String> tempUserTokens = new HashSet<>();
|
||||
tempUserTokens.add(token);
|
||||
loginTokenCache.put(userIdKey, tempUserTokens);
|
||||
} else {
|
||||
theUserTokens.add(token);
|
||||
theUserTokens = new HashSet<>();
|
||||
}
|
||||
theUserTokens.add(token);
|
||||
allPlaceLoginTokenCache.put(loginUser.getUserId().toString(), theUserTokens);
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginUser getSession(String token) {
|
||||
return loginUserCache.get(getTokenKey(token));
|
||||
return loginUserCache.get(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSession(String token) {
|
||||
|
||||
String tokenKey = getTokenKey(token);
|
||||
LoginUser loginUser = loginUserCache.get(tokenKey);
|
||||
LoginUser loginUser = loginUserCache.get(token);
|
||||
|
||||
// 删除用户id对应token的缓存
|
||||
// 删除本token用户信息的缓存
|
||||
loginUserCache.remove(token);
|
||||
|
||||
// 删除多端登录信息
|
||||
if (loginUser != null) {
|
||||
Long userId = loginUser.getUserId();
|
||||
Set<String> userTokens = loginTokenCache.get(getUserIdKey(userId));
|
||||
Set<String> userTokens = allPlaceLoginTokenCache.get(userId.toString());
|
||||
if (userTokens != null) {
|
||||
userTokens.remove(token);
|
||||
|
||||
// 如果删除后size为0,则把整个key删掉
|
||||
if (userTokens.size() == 0) {
|
||||
loginTokenCache.remove(getUserIdKey(userId));
|
||||
allPlaceLoginTokenCache.remove(userId.toString());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除用户信息的缓存
|
||||
loginUserCache.remove(getTokenKey(token));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
@ -107,40 +104,20 @@ public class MemoryCacheSessionManager implements SessionManagerApi {
|
|||
// 设置用户id对应的token列表为参数token
|
||||
HashSet<String> tokenSet = new HashSet<>();
|
||||
tokenSet.add(token);
|
||||
loginTokenCache.put(getUserIdKey(userId), tokenSet);
|
||||
allPlaceLoginTokenCache.put(userId.toString(), tokenSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean haveSession(String token) {
|
||||
return loginUserCache.containsKey(getTokenKey(token));
|
||||
return loginUserCache.contains(token);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshSession(String token) {
|
||||
LoginUser loginUser = loginUserCache.get(getTokenKey(token));
|
||||
LoginUser loginUser = loginUserCache.get(token);
|
||||
if (loginUser != null) {
|
||||
loginUserCache.put(LOGGED_TOKEN_PREFIX + token, loginUser, loginUserCache.timeout());
|
||||
loginUserCache.expire(token, sessionExpiredSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token的缓存key
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/10/21 15:09
|
||||
*/
|
||||
private String getTokenKey(String token) {
|
||||
return LOGGED_TOKEN_PREFIX + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户id的缓存key
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/10/21 15:10
|
||||
*/
|
||||
private String getUserIdKey(Long userId) {
|
||||
return LOGGED_USERID_PREFIX + userId;
|
||||
}
|
||||
|
||||
}
|
|
@ -1,159 +0,0 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session;
|
||||
|
||||
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
|
||||
import com.alibaba.fastjson.parser.ParserConfig;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_TOKEN_PREFIX;
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_USERID_PREFIX;
|
||||
|
||||
/**
|
||||
* 基于redis的会话管理
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2019-09-28-14:43
|
||||
*/
|
||||
public class RedisSessionManager implements SessionManagerApi {
|
||||
|
||||
/**
|
||||
* 登录用户缓存
|
||||
* <p>
|
||||
* key是 LOGGED_TOKEN_PREFIX + 用户的token
|
||||
*/
|
||||
private final RedisTemplate<String, LoginUser> loginUserRedisTemplate;
|
||||
|
||||
/**
|
||||
* 用户token的缓存,这个缓存用来存储一个用户的所有token
|
||||
* <p>
|
||||
* 没开启单端限制的话,一个用户可能有多个token,因为一个用户可能在多个地点或打开多个浏览器访问系统
|
||||
* <p>
|
||||
* key是 LOGGED_USERID_PREFIX + 用户id
|
||||
* <p>
|
||||
* 这个缓存应该定时刷新下,因为有过期token的用户,所以这个里边的值set得清理
|
||||
*/
|
||||
private final RedisTemplate<String, Set<String>> loginTokenRedisTemplate;
|
||||
|
||||
/**
|
||||
* session的超时时间
|
||||
*/
|
||||
private final Long sessionExpiredSeconds;
|
||||
|
||||
public RedisSessionManager(RedisTemplate<String, LoginUser> loginUserRedisTemplate, RedisTemplate<String, Set<String>> loginTokenRedisTemplate, Long sessionExpiredSeconds) {
|
||||
this.loginUserRedisTemplate = loginUserRedisTemplate;
|
||||
this.loginTokenRedisTemplate = loginTokenRedisTemplate;
|
||||
this.sessionExpiredSeconds = sessionExpiredSeconds;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void createSession(String token, LoginUser loginUser) {
|
||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
||||
|
||||
// 装配用户信息的缓存
|
||||
loginUserRedisTemplate.opsForValue().set(getTokenKey(token), loginUser, sessionExpiredSeconds, TimeUnit.SECONDS);
|
||||
|
||||
// 装配用户token的缓存
|
||||
String userIdKey = getUserIdKey(loginUser.getUserId());
|
||||
Set<String> theUserTokens = loginTokenRedisTemplate.opsForValue().get(userIdKey);
|
||||
if (theUserTokens == null) {
|
||||
HashSet<String> tempUserTokens = new HashSet<>();
|
||||
tempUserTokens.add(token);
|
||||
loginTokenRedisTemplate.opsForValue().set(userIdKey, tempUserTokens);
|
||||
} else {
|
||||
theUserTokens.add(token);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public LoginUser getSession(String token) {
|
||||
ParserConfig.getGlobalInstance().setAutoTypeSupport(true);
|
||||
return loginUserRedisTemplate.opsForValue().get(getTokenKey(token));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSession(String token) {
|
||||
|
||||
String tokenKey = getTokenKey(token);
|
||||
LoginUser loginUser = loginUserRedisTemplate.opsForValue().get(tokenKey);
|
||||
|
||||
// 删除用户id对应token的缓存
|
||||
if (loginUser != null) {
|
||||
Long userId = loginUser.getUserId();
|
||||
Set<String> userTokens = loginTokenRedisTemplate.opsForValue().get(getUserIdKey(userId));
|
||||
if (userTokens != null) {
|
||||
userTokens.remove(token);
|
||||
|
||||
// 如果删除后size为0,则把整个key删掉
|
||||
if (userTokens.size() == 0) {
|
||||
loginUserRedisTemplate.delete(getUserIdKey(userId));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 删除用户信息的缓存
|
||||
loginUserRedisTemplate.delete(getTokenKey(token));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeSessionExcludeToken(String token) {
|
||||
|
||||
// 获取token对应的会话
|
||||
LoginUser session = this.getSession(token);
|
||||
|
||||
// 如果会话为空,直接返回
|
||||
if (session == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
// 获取用户id
|
||||
Long userId = session.getUserId();
|
||||
|
||||
// 设置用户id对应的token列表为参数token
|
||||
HashSet<String> tokenSet = new HashSet<>();
|
||||
tokenSet.add(token);
|
||||
loginTokenRedisTemplate.opsForValue().set(getUserIdKey(userId), tokenSet);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean haveSession(String token) {
|
||||
Boolean flag = loginUserRedisTemplate.hasKey(getTokenKey(token));
|
||||
if (flag == null) {
|
||||
return false;
|
||||
} else {
|
||||
return flag;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void refreshSession(String token) {
|
||||
LoginUser loginUser = loginUserRedisTemplate.boundValueOps(getTokenKey(token)).get();
|
||||
if (loginUser != null) {
|
||||
loginUserRedisTemplate.boundValueOps(getTokenKey(token)).expire(sessionExpiredSeconds, TimeUnit.SECONDS);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取token的缓存key
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/10/21 15:09
|
||||
*/
|
||||
private String getTokenKey(String token) {
|
||||
return LOGGED_TOKEN_PREFIX + token;
|
||||
}
|
||||
|
||||
/**
|
||||
* 获取用户id的缓存key
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/10/21 15:10
|
||||
*/
|
||||
private String getUserIdKey(Long userId) {
|
||||
return LOGGED_USERID_PREFIX + userId;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session.cache.logintoken;
|
||||
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import com.sedinbj.kernel.cache.AbstractMemoryCacheOperator;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_USERID_PREFIX;
|
||||
|
||||
|
||||
/**
|
||||
* 基于内存的token缓存
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/24 19:16
|
||||
*/
|
||||
public class MemoryLoginTokenCache extends AbstractMemoryCacheOperator<Set<String>> {
|
||||
|
||||
public MemoryLoginTokenCache(TimedCache<String, Set<String>> timedCache) {
|
||||
super(timedCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonKeyPrefix() {
|
||||
return LOGGED_USERID_PREFIX;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session.cache.logintoken;
|
||||
|
||||
import com.sedinbj.kernel.cache.AbstractRedisCacheOperator;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_USERID_PREFIX;
|
||||
|
||||
|
||||
/**
|
||||
* 基于redis的token的缓存
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/24 19:16
|
||||
*/
|
||||
public class RedisLoginTokenCache extends AbstractRedisCacheOperator<Set<String>> {
|
||||
|
||||
public RedisLoginTokenCache(RedisTemplate<String, Set<String>> redisTemplate) {
|
||||
super(redisTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonKeyPrefix() {
|
||||
return LOGGED_USERID_PREFIX;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session.cache.loginuser;
|
||||
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
|
||||
import com.sedinbj.kernel.cache.AbstractMemoryCacheOperator;
|
||||
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_TOKEN_PREFIX;
|
||||
|
||||
/**
|
||||
* 基于内存的登录用户缓存
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/24 19:16
|
||||
*/
|
||||
public class MemoryLoginUserCache extends AbstractMemoryCacheOperator<LoginUser> {
|
||||
|
||||
public MemoryLoginUserCache(TimedCache<String, LoginUser> timedCache) {
|
||||
super(timedCache);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonKeyPrefix() {
|
||||
return LOGGED_TOKEN_PREFIX;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,27 @@
|
|||
package cn.stylefeng.roses.kernel.auth.session.cache.loginuser;
|
||||
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
|
||||
import com.sedinbj.kernel.cache.AbstractRedisCacheOperator;
|
||||
import org.springframework.data.redis.core.RedisTemplate;
|
||||
|
||||
import static cn.stylefeng.roses.kernel.auth.api.constants.AuthConstants.LOGGED_TOKEN_PREFIX;
|
||||
|
||||
|
||||
/**
|
||||
* 基于redis的登录用户缓存
|
||||
*
|
||||
* @author fengshuonan
|
||||
* @date 2020/12/24 19:16
|
||||
*/
|
||||
public class RedisLoginUserCache extends AbstractRedisCacheOperator<LoginUser> {
|
||||
|
||||
public RedisLoginUserCache(RedisTemplate<String, LoginUser> redisTemplate) {
|
||||
super(redisTemplate);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getCommonKeyPrefix() {
|
||||
return LOGGED_TOKEN_PREFIX;
|
||||
}
|
||||
|
||||
}
|
|
@ -24,6 +24,13 @@
|
|||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
<!--默认使用内存-->
|
||||
<dependency>
|
||||
<groupId>com.sedinbj.kernel</groupId>
|
||||
<artifactId>cache-sdk-memory</artifactId>
|
||||
<version>1.0.0</version>
|
||||
</dependency>
|
||||
|
||||
</dependencies>
|
||||
|
||||
<build>
|
||||
|
|
|
@ -1,17 +1,25 @@
|
|||
package cn.stylefeng.roses.kernel.auth.starter;
|
||||
|
||||
import cn.hutool.cache.CacheUtil;
|
||||
import cn.hutool.cache.impl.TimedCache;
|
||||
import cn.stylefeng.roses.kernel.auth.api.SessionManagerApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.expander.AuthConfigExpander;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordStoredEncryptApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.password.PasswordTransferEncryptApi;
|
||||
import cn.stylefeng.roses.kernel.auth.api.pojo.login.LoginUser;
|
||||
import cn.stylefeng.roses.kernel.auth.password.BcryptPasswordStoredEncrypt;
|
||||
import cn.stylefeng.roses.kernel.auth.password.RsaPasswordTransferEncrypt;
|
||||
import cn.stylefeng.roses.kernel.auth.session.MemoryCacheSessionManager;
|
||||
import cn.stylefeng.roses.kernel.auth.session.DefaultSessionManager;
|
||||
import cn.stylefeng.roses.kernel.auth.session.cache.logintoken.MemoryLoginTokenCache;
|
||||
import cn.stylefeng.roses.kernel.auth.session.cache.loginuser.MemoryLoginUserCache;
|
||||
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
|
||||
import org.springframework.context.annotation.Bean;
|
||||
import org.springframework.context.annotation.Configuration;
|
||||
|
||||
import java.util.Set;
|
||||
|
||||
import static com.sedinbj.kernel.cache.api.constants.CacheConstants.NONE_EXPIRED_TIME;
|
||||
|
||||
/**
|
||||
* 认证和鉴权模块的自动配置
|
||||
*
|
||||
|
@ -57,7 +65,14 @@ public class GunsAuthAutoConfiguration {
|
|||
@ConditionalOnMissingBean(SessionManagerApi.class)
|
||||
public SessionManagerApi sessionManagerApi() {
|
||||
Long sessionExpiredSeconds = AuthConfigExpander.getSessionExpiredSeconds();
|
||||
return new MemoryCacheSessionManager(CacheUtil.newTimedCache(sessionExpiredSeconds * 1000));
|
||||
|
||||
TimedCache<String, LoginUser> loginUsers = CacheUtil.newTimedCache(1000L * sessionExpiredSeconds);
|
||||
TimedCache<String, Set<String>> loginTokens = CacheUtil.newTimedCache(NONE_EXPIRED_TIME);
|
||||
|
||||
MemoryLoginUserCache memoryLoginUserCache = new MemoryLoginUserCache(loginUsers);
|
||||
MemoryLoginTokenCache memoryLoginTokenCache = new MemoryLoginTokenCache(loginTokens);
|
||||
|
||||
return new DefaultSessionManager(memoryLoginUserCache, memoryLoginTokenCache, sessionExpiredSeconds);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue