通常系统都会限制同一个账号的登录人数,多人登录要么限制后者登录,要么踢出前者,今天讲的是踢出前者。
JWT(token)存储在Redis中,类似 JSessionId-Session的关系,用户登录后每次请求在Header中携带jwt
比较时间戳
维护一个 username: jwtToken 这样的一个 key-value 在Reids中
拦截器逻辑
package com.gitee.taven.filter;
import com.gitee.taven.utils.JWTUtil;
import org.apache.commons.lang3.StringUtils;
import org.redisson.api.RBucket;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
/**
* 比较时间戳
*/
public class CompareKickOutFilter extends KickOutFilter {
@Override
public boolean isAccessAllowed(HttpServletRequest request, HttpServletResponse response) {
String token = request.getHeader("Authorization");
String username = JWTUtil.getUsername(token);
String userKey = PREFIX + username;
RBucket<String> bucket = redissonClient.getBucket(userKey);
String redisToken = bucket.get();
if (token.equals(redisToken)) {
return true;
} else if (StringUtils.isBlank(redisToken)) {
bucket.set(token);
} else {
Long redisTokenUnixTime = JWTUtil.getClaim(redisToken, "createTime").asLong();
Long tokenUnixTime = JWTUtil.getClaim(token, "createTime").asLong();
// token > redisToken 则覆盖
if (tokenUnixTime.compareTo(redisTokenUnixTime) > 0) {
bucket.set(token);
} else {
// 注销当前token
userService.logout(token);
sendJsonResponse(response, 4001, "您的账号已在其他设备登录");
return false;
}
}
return true;
}
}
用户登录成功 生成token给到用户 同时存储到redis中(key值为用户名(标识))
用户再次访问系统请求参数中带有token信息 后台拦截进行比对
如果token匹配成功 就放行 匹配不成功 说明两个token不一致 开始比对对应的时间戳 后者时间戳 大于前者 就把当前token覆盖(如果旧的token请求再次进来 期时间戳就晚于当前redis中的token时间(token已经更新)判断其为被踢出的用户提示重新登录)