7.6 KiB
7.6 KiB
Token滑动机制技术文档
一、概述
本系统采用基于Redis的Token滑动窗口机制,实现用户会话的自动续期功能。当用户在系统中持续活动时,Token会自动刷新,避免频繁登录,提升用户体验。
二、核心配置
2.1 配置文件(application.yml)
# token配置
token:
# 令牌自定义标识
header: Authorization
# 令牌密钥
secret: abcdefghijklmnopqrstuvwxyz
# 令牌有效期(默认30分钟,单位:分钟)
expireTime: 10080
配置说明:
header: HTTP请求头中Token的字段名secret: JWT签名密钥expireTime: Token有效期,当前配置为10080分钟(7天)
三、核心实现
3.1 数据模型(LoginUser)
public class LoginUser implements UserDetails {
/**
* 用户唯一标识
*/
private String token;
/**
* 登录时间
*/
private Long loginTime;
/**
* 过期时间
*/
private Long expireTime;
// ... 其他字段
}
3.2 Token服务(TokenService)
3.2.1 关键常量
// 令牌有效期(从配置文件读取)
@Value("${token.expireTime}")
private int expireTime;
// 毫秒常量
protected static final long MILLIS_SECOND = 1000;
protected static final long MILLIS_MINUTE = 60 * MILLIS_SECOND;
// 滑动窗口触发阈值:20分钟
private static final Long MILLIS_MINUTE_TEN = 20 * 60 * 1000L;
3.2.2 创建Token
public String createToken(LoginUser loginUser) {
String token = IdUtils.fastUUID();
loginUser.setToken(token);
setUserAgent(loginUser);
refreshToken(loginUser); // 初始化Token过期时间
Map<String, Object> claims = new HashMap<>();
claims.put(Constants.LOGIN_USER_KEY, token);
return createToken(claims);
}
3.2.3 验证Token(滑动机制核心)
/**
* 验证令牌有效期,相差不足20分钟,自动刷新缓存
*
* @param loginUser
*/
public void verifyToken(LoginUser loginUser) {
long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
// 如果距离过期时间不足20分钟,触发刷新
if (expireTime - currentTime <= MILLIS_MINUTE_TEN) {
refreshToken(loginUser);
}
}
3.2.4 刷新Token
/**
* 刷新令牌有效期
*
* @param loginUser 登录信息
*/
public void refreshToken(LoginUser loginUser) {
// 更新登录时间为当前时间
loginUser.setLoginTime(System.currentTimeMillis());
// 重新计算过期时间 = 当前时间 + 配置的有效期
loginUser.setExpireTime(loginUser.getLoginTime() + expireTime * MILLIS_MINUTE);
// 将更新后的用户信息存入Redis,并设置过期时间
String userKey = getTokenKey(loginUser.getToken());
redisCache.setCacheObject(userKey, loginUser, expireTime, TimeUnit.MINUTES);
}
3.2.5 获取登录用户
public LoginUser getLoginUser(HttpServletRequest request) {
// 获取请求携带的令牌
String token = getToken(request);
if (StringUtils.isNotEmpty(token)) {
try {
Claims claims = parseToken(token);
// 解析对应的权限以及用户信息
String uuid = (String) claims.get(Constants.LOGIN_USER_KEY);
String userKey = getTokenKey(uuid);
LoginUser user = redisCache.getCacheObject(userKey);
return user;
} catch (Exception e) {
// Token解析失败
}
}
return null;
}
四、滑动机制工作流程
4.1 流程图
用户请求 → 获取Token → 从Redis获取LoginUser → 验证Token有效期
↓
距离过期 ≤ 20分钟?
↓ ↓
是 否
↓ ↓
刷新Token 继续使用
↓
更新过期时间
↓
更新Redis缓存
4.2 详细说明
-
用户登录
- 创建Token(UUID)
- 设置初始过期时间 = 当前时间 + expireTime
- 存入Redis,设置过期时间
-
用户请求
- 从请求头获取Token
- 从Redis获取LoginUser对象
- 调用
verifyToken()验证
-
滑动窗口判断
- 计算剩余有效时间 = expireTime - currentTime
- 如果剩余时间 ≤ 20分钟,触发刷新
- 否则,继续使用当前Token
-
Token刷新
- 更新loginTime为当前时间
- 重新计算expireTime
- 更新Redis中的LoginUser对象
五、关键特性
5.1 滑动窗口策略
- 触发条件:距离过期时间不足20分钟
- 刷新动作:重置过期时间为当前时间 + expireTime
- 优势:用户持续活动时,Token自动续期,无需重新登录
5.2 Redis存储
- Key格式:
login_tokens:{uuid} - Value:LoginUser对象(序列化)
- 过期时间:与Token过期时间一致
- 优势:分布式环境下共享会话,自动清理过期数据
5.3 双重过期机制
- LoginUser.expireTime:业务层面的过期时间判断
- Redis TTL:存储层面的自动清理机制
六、配置建议
6.1 生产环境配置
token:
expireTime: 120 # 2小时
说明:
- 滑动窗口触发阈值固定为20分钟
- 如果用户在2小时内有任何操作,且距离过期不足20分钟,会自动续期2小时
- 如果用户超过2小时无操作,Token过期,需要重新登录
6.2 开发环境配置
token:
expireTime: 10080 # 7天
说明:
- 方便开发调试,减少频繁登录
- 生产环境不建议设置过长
七、安全考虑
7.1 Token安全
- 使用JWT签名,防止Token篡改
- Token存储在Redis中,支持主动失效
- 支持单点登录控制
7.2 滑动窗口安全
- 20分钟的滑动窗口阈值,平衡用户体验和安全性
- 即使Token被盗用,最长有效期仍受expireTime限制
- 可通过删除Redis中的Token实现强制下线
八、扩展功能
8.1 积木报表Token验证
// JimuReportTokenService.java
public boolean isTokenValid(String token) {
LoginUser loginUser = tokenService.getLoginUser(request);
if (loginUser != null) {
// 检查token是否过期
long expireTime = loginUser.getExpireTime();
long currentTime = System.currentTimeMillis();
return currentTime < expireTime;
}
return false;
}
8.2 用户代理信息记录
public void setUserAgent(LoginUser loginUser) {
UserAgent userAgent = UserAgent.parseUserAgentString(
ServletUtils.getRequest().getHeader("User-Agent")
);
String ip = IpUtils.getIpAddr();
loginUser.setIpaddr(ip);
loginUser.setLoginLocation(AddressUtils.getRealAddressByIP(ip));
loginUser.setBrowser(userAgent.getBrowser().getName());
loginUser.setOs(userAgent.getOperatingSystem().getName());
}
九、总结
本系统的Token滑动机制通过以下方式实现了高效的会话管理:
- 自动续期:用户活跃时自动延长会话,提升体验
- 灵活配置:通过配置文件调整有效期和滑动窗口
- 分布式支持:基于Redis实现,支持集群部署
- 安全可控:双重过期机制,支持主动失效
核心优势:在保证安全性的前提下,最大化提升用户体验,避免频繁登录带来的困扰。