首页 > 数据库 >使用jwt,redis,实现登录

使用jwt,redis,实现登录

时间:2022-11-06 11:58:39浏览次数:33  
标签:return String 登录 redis jwt request token loginUser public

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

相关文章