基于 SprigBoot + JWT + Redis 实现单点登录思路 实现. 代码如下
返回Token: userid + md5盐 + 当前日期
调用token: JWT_TOKEN
1. 如果token部分 携带日期 大于 当前日期, 此时为被挤下线;
2. 如果token部分 Redis 没有查找到,
拦截器部分:
public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) {
if (handler instanceof HandlerMethod) {
HandlerMethod handlerMethod = (HandlerMethod) handler;
Method method = handlerMethod.getMethod();
NoAuth noAuth = AnnotationUtils.findAnnotation(method, NoAuth.class);
String authorization = request.getHeader("Authorization");
// 需要登录
if (noAuth == null) {
if (null == authorization) {
throw new ServiceException(Result.NOT_LOGIN, "请登录后再操作");
}
//2. 查看token是否被踢下线
String loginTimer = authorization.substring(39);
log.info("token是否过期:{}" , (System.currentTimeMillis() - Long.valueOf(loginTimer)) < JwtConstant.REDIS_TIME_S);
if((System.currentTimeMillis() - Long.valueOf(loginTimer)) < JwtConstant.REDIS_TIME_S){
String userToken = authorization.substring(7);
//3. 如果token不存在就是被挤下线了
if(redisUtils.hasKey(RedisConstant.redisNamePre + userToken)){
long time = redisUtils.getExpire(RedisConstant.redisNamePre+userToken);
//如果 token 小于 10分钟就续费 30 分钟
if(time < 300){
redisUtils.expire(RedisConstant.redisNamePre+userToken , time + JwtConstant.REDIS_TIME);
}
}else{
throw new ServiceException(10004 , "被踢下线喽.......");
}
}
throw new ServiceException(10003 , "TOKEN过期喽.......");
}
return true;
}
return false;
}
登录部分:
@ApiOperation("用户登录")
@NoAuth
@PostMapping("/auth/login")
public Result<String> userLogin(HttpServletRequest request, UserLoginDTO user) throws Exception {
TUtil.checkObj(new String[]{"用户名不能为空", "密码不能为空"}, user.getPhone(), user.getPassword());
String passwd = DigestUtil.md5Hex(user.getPassword() + JwtConstant.MD5_KEY);
user.setPassword(passwd);
TUser tUser = userService.userToken(user);
if(tUser != null){
//获取用户设备
String uaStr = request.getHeader("User-Agent");
UserAgent ua = UserAgentUtil.parse(uaStr);
//1. 创建token数据
JwtToken token = new JwtToken();
token.setUserId(tUser.getId());
token.setCellPhone(tUser.getPhone());
token.setDevice(ua.getOs().toString());
String ip = StringUtils.getIp(request);
String ipInfo = StringUtils.getCityInfo(ip);
token.setIp(ip);
token.setIpInfo(ipInfo);
//2. 生成JWT TOKEN
String tokenStr = JwtUtils.createToken(token);
//创建TokenName: userid + md5盐 + 当前日期
String tokenName = DigestUtil.md5Hex(tUser.getId()+JwtConstant.MD5_KEY+DateUtil.yyyyMMdd.format(new Date())).toUpperCase();
//3.删除redis数据
redisUtils.delKeys(RedisConstant.redisNamePre + tokenName);
//4. 写入缓存
Map<String, Object> map = new HashMap<String, Object>(2);
map.put("loginTimer" , System.currentTimeMillis());
map.put("token" , tokenStr);
String authToken = tokenName + System.currentTimeMillis();
redisUtils.hmset(RedisConstant.redisNamePre + authToken, map, JwtConstant.REDIS_TIME);
log.info("用户: {} 登录成功,设备: {}" , user.getPhone(), token.getDevice());
return Result.initSuccessResult(authToken);
}
return Result.initFailureResult(10001, "用户名或密码错误");
}
以上为实现的主要功能部分
来源:oschina
链接:https://my.oschina.net/watler/blog/3208472
