jwt是无状态的,不需要服务端存储登录用户信息,一次性生成token后,除非过期,不然是都可以用的。但是这样就产生了token续期、用户注销等问题。
token续期怎么解决呢?
1、使用redis,用户登录成功后,我们生成一个ID,用这个ID标识登录用户信息以及登录时间,存储在redis里,并放在jwt的claim里。之后的用户请求,都从jwt 里面取出claim的ID,在从redis里面取出用户信息及过期时间,判断过期时间将近,就续期。
这种方式吧,我觉着根本不需要用jwt。
2、第二种方式是使用两个token,一个用户正常使用,一个refreshToken。refreshToken的要比正常使用token晚一些时间过期。每次请求都带上两个token,这样如果token过期,就使用refreshToken拿到用户信息,重新生成token。并然会前端,让前端替换。
我这使用第一种方式:
controller的登录方法
@IgnoreLoginValid @PostMapping("login") public AjaxResult<Map<String,String>> login(@Validated @RequestBody LoginRequest request){ String token = loginService.login(request); Map<String,String> result = new HashMap<>(1); result.put("token", token); return AjaxResult.success(result); }
LoginService
@Component public class LoginService { @Resource private IUserService userService; @Resource private TokenService tokenService; public String login(LoginRequest request){ User user = userService.findByUsername(request.getUsername()); if(Objects.isNull(user)){ throw Exceptions.exception("没有该用户,请联系管理员"); } String pwd = Md5Utils.MD5(request.getPassword() + user.getSalt()); if(!StringUtils.equals(pwd, user.getPassword())){ throw Exceptions.exception("密码错误"); } // 验证通过,生成token LoginUser loginUser = new LoginUser(); loginUser.setId(user.getId()); loginUser.setUsername(user.getUsername()); return tokenService.createToken(loginUser); } }
TokenService
@Slf4j @Component public class TokenService { @Value("${token.expireMinute}") private Integer tokenExpireMinute; @Value("${token.secret}") private String secret; @Resource private RedisTemplate<String,Object> redisTemplate; public String createToken(LoginUser loginUser) { String cacheToken = UUID.randomUUID().toString().replace("-", ""); loginUser.setToken(cacheToken); refreshToken(loginUser); String jwtToken = createJwtToken(cacheToken); return jwtToken; } private String createJwtToken(String cacheToken) { Map<String,Object> claims = new HashMap<>(1); claims.put("cacheToken", cacheToken); String jwtToken = Jwts.builder() .setClaims(claims) .signWith(SignatureAlgorithm.HS512, secret).compact(); return jwtToken; } public String parseJwtToken(String jwtToken){ Claims claims = Jwts.parser() .setSigningKey(secret) .parseClaimsJws(jwtToken) .getBody(); return claims.get("cacheToken").toString(); } public LoginUser getLoginUser(HttpServletRequest request) { String token = request.getParameter("token"); if(StringUtils.isEmpty(token)){ token = request.getHeader("token"); } if(StringUtils.isEmpty(token)){ return null; } String cacheToken = parseJwtToken(token); LoginUser loginUser = (LoginUser) redisTemplate.opsForValue().get(UserConstants.LOGIN_USER_TOKEN + cacheToken); long remaining= loginUser.getExpiredTime() - System.currentTimeMillis(); // 过期时间还剩5分钟,进行续期 if(remaining < 5 * 60 * 1000){ refreshToken(loginUser); } return loginUser; } private void refreshToken(LoginUser loginUser){ loginUser.setLoginTime(System.currentTimeMillis()); Long expireTime = System.currentTimeMillis() + tokenExpireMinute * 60 * 1000; loginUser.setExpiredTime(expireTime); redisTemplate.opsForValue().set(UserConstants.LOGIN_USER_TOKEN + loginUser.getToken(), loginUser, tokenExpireMinute, TimeUnit.MINUTES); } }
登录拦截器:
@Slf4j @Component public class LoginInterceptor implements HandlerInterceptor { @Resource private TokenService tokenService; @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { if(handler instanceof HandlerMethod){ IgnoreLoginValid ignoreLoginValid = ((HandlerMethod) handler).getMethodAnnotation(IgnoreLoginValid.class); if(Objects.nonNull(ignoreLoginValid)){ return true; } LoginUser loginUser = tokenService.getLoginUser(request); if(Objects.isNull(loginUser)){ throw Exceptions.exception("请登录"); } WebThreadLocals.setThreadLocalLoginUser(loginUser); } return true; } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { WebThreadLocals.remove(); } }
标签:return,String,登录,redis,jwt,request,token,loginUser,public From: https://www.cnblogs.com/junnnnnnnn/p/16862286.html