private static final Logger logger = LoggerFactory.getLogger(LoginTools.class);
/**
* 用户token,eg. token:1245637858
*/
private final static String TOKEN_KEY = "token:%s";
/**
* 在多长时间内用户不用再次登录,比如3月1日登录了,expires为7天,那么用户
* 在3月8日之前都不用重新登录
*/
private final static long TOKEN_REFRESH_EXPIRE_SECONDS = 60*60*24*7;
private static BaseRedisTools redisTools;
@Autowired(required = false)
private BaseRedisTools baseRedisTools;
/**
* 用户登录,生成token,
* token有效期为两个小时,将该token存入redis中,
* key为id,value为token,该key的有效期设置为7天,
* 并将token返回给前端,解决token自动续期问题。
*
* @param userId 登录用户的唯一表示,eg.'token:123456'
* @param token 登录用户的token(不一定是token,但是一定只能代表一个用户的信息,用token可以获取到一些信息)
* @data 2021/4/15 10:48
* @author zhaojin
*/
public static String setTokenToRedis(String userId, String token) {
String key = getRedisKey(userId);
// 如果oldToken存在且没过期就返回oldToken,否则会导致其他端(用的也是这种刷新方式)的token无法刷新
// 原因是刷新oldToken的时候需要判断oldToken和redis里存的oldToken是否相同,
// 相同的话就能刷新,不相同就不能刷新,至于为什么要判断是否相同,请看刷新token逻辑
String oldToken = (String) redisTools.get(key);
if (!StringUtils.isEmpty(oldToken) && !TokenTools.isExpired(oldToken)) {
return oldToken;
}
if (!redisTools.set(key, token, TOKEN_REFRESH_EXPIRE_SECONDS)) {
logger.error("用户登录token存入失败:[userId:{},token:{},expires:{}秒]", userId, token, TOKEN_REFRESH_EXPIRE_SECONDS);
throw new RuntimeException("登录服务出错");
}
return token;
}
private static String getRedisKey(String userId) {
return String.format(TOKEN_KEY, userId);
}
public static String refreshTokenByRedis(String token) {
String userId = TokenTools.getAudience(token);
String key = getRedisKey(userId);
Object oldToken = redisTools.get(key);
// 当前过期token必须和redis里存在的token相同,
// 要不然只要是个过期的token就能被刷新,存在安全问题
if (oldToken != null && Objects.equals(token, oldToken)) {
try {
Assert.isTrue(!StringUtils.isEmpty(userId), "用户id为空");
String newToken = TokenTools.getToken(userId, AppConfiguration.APP_LOGIN_SECRET);
logger.info("用户登录token刷新过期时间,[key:'{}']", key);
setTokenToRedis(userId, newToken);
redisTools.expire(key, TOKEN_REFRESH_EXPIRE_SECONDS);
return newToken;
} catch (Exception e) {
logger.warn("用户登录token已过期,重新生成token错误:[key:{},oldToken:{},expires:{}秒]",
key, oldToken, TOKEN_REFRESH_EXPIRE_SECONDS);
throw new TokenAgainLoginException();
}
} else {
logger.info("用户登录token已过期,并长时间未操作,需要重新登录:[key:'{}',expires:'{}秒']", key, TOKEN_REFRESH_EXPIRE_SECONDS);
throw new TokenAgainLoginException();
}
}
token刷新
最新推荐文章于 2025-03-12 18:53:28 发布