一、JWT工具类

  • JwtUtil.java
import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.JWTDecodeException;
import com.auth0.jwt.interfaces.DecodedJWT;

import java.util.Date;
import java.util.HashMap;
import java.util.Map;

public class JwtUtil {
    /**
     * 过期时间一天,
     * TODO 正式运行时修改为15分钟
     */
    private static final long EXPIRE_TIME = 24 * 60 * 60 * 1000;
    /**
     * token私钥
     */
    private static final String TOKEN_SECRET = "f26e587c28064d0e855e72c0a6a0e618";

    /**
     * 校验token是否正确
     *
     * @param token 密钥
     * @return 是否正确
     */
    public static boolean verify(String token) {
        try {
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            JWTVerifier verifier = JWT.require(algorithm)
                    .build();
            DecodedJWT jwt = verifier.verify(token);
            return true;
        } catch (Exception exception) {
            return false;
        }
    }

    /**
     * 获得token中的信息无需secret解密也能获得
     *
     * @return token中包含的用户名
     */
    public static String getUserName(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userName").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 获取登陆用户密码
     *
     * @param token
     * @return
     */
    public static String getUserId(String token) {
        try {
            DecodedJWT jwt = JWT.decode(token);
            return jwt.getClaim("userId").asString();
        } catch (JWTDecodeException e) {
            return null;
        }
    }

    /**
     * 生成签名,15min后过期
     *
     * @param userName 用户名
     * @return 加密的token
     */
    public static String sign(String userName) {
        try {
//            过期时间
            Date date = new Date(System.currentTimeMillis() + EXPIRE_TIME);
//            私钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
//            设置头部信息
            Map<String, Object> header = new HashMap<>(2);
            header.put("typ", "JWT");
            header.put("alg", "HS256");
            // 附带username,userId信息,生成签名
            return JWT.create()
                    .withHeader(header)
                    .withClaim("userName", userName)
                    .withExpiresAt(date)
                    .sign(algorithm);
        } catch (Exception e) {
            return null;
        }
    }
}

二、 @TokenRequire注解

@Target({ElementType.METHOD, ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface TokenRequired {
    boolean required() default true;
}

三、 Token拦截器

  • TokenInterceptor.java
public class TokenInterceptor implements HandlerInterceptor {
    @Autowired
    RedisUtil redisUtil;
    
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从 http 请求头中取出 token
        String token = request.getHeader("Token");
        // 如果不是映射到方法直接通过
        if (!(handler instanceof HandlerMethod)) {
            return true;
        }
        Method method = ((HandlerMethod) handler).getMethod();

        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(TokenRequired.class)) {
            TokenRequired userLoginToken = method.getAnnotation(TokenRequired.class);
            if (userLoginToken.required()) {
                // 执行认证
                if (token == null) {
                    ResponseUtil.responseMessage(response, InfoUtil.getInfo(UserError.TOKEN_IS_NOT_EXIT));
                    return false;
                }
                //获取token中的userId
                String userId = JwtUtil.getUserId(token);
                if (userId == null) {
                    ResponseUtil.responseMessage(response, InfoUtil.getInfo(UserError.TOKEN_IS_INVALID));
                    return false;
                }

                //验证token是否过期
                if (!JwtUtil.verify(token)) {
                    //如果token检验失败,查询redis中是否存在,redis为空,用户重新登录
                    if (redisUtil.get("userToken_" + userId) == null) {
                        ResponseUtil.responseMessage(response, InfoUtil.getInfo(UserError.NONE_TOKEN));
                        return false;
                    }
                    //redis中存在token,刷新token
                    String refreshToken = JwtUtil.sign(userId);
                    redisUtil.set("userToken_" + userId, refreshToken, 20, TimeUnit.DAYS);
                    JSONObject jsonObject = new JSONObject();
                    jsonObject.put("newToken", refreshToken);
                    ResponseUtil.responseMessage(response, InfoUtil.getInfo(UserError.TOKEN_IS_EXPIRED, jsonObject));
                    return false;
                }
                //将userId存到session
                HttpSession session = request.getSession();
                session.setAttribute("userId", userId);
                return true;
            }
        }
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

三、 WebConfig配置

  • WebConfig.java
@Configuration
public class WebConfig implements WebMvcConfigurer {

    @Bean
    TokenInterceptor getTokenInterceptor() {
        return new TokenInterceptor();
    }


    //注册拦截器
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //注册token设置
        registry.addInterceptor(getTokenInterceptor())
                .addPathPatterns("/**");
    }
}

四、 使用方法

  • @TokenRequire使用
    @TokenRequired   //使用该注解表示该方法需要token
    @PostMapping("/getUserInfo")
    public Info getUserInfo() {
        return userService.getUserInfo();
    }
  • 登录方法
    @Override
    //登录
    public Info login(Code code) {
        Integer userId = userMapper.login(code);
        //userId为null,说明用户名或密码错误
        if (userId == null) {
            return InfoUtil.getInfo(UserError.PASSWORD_OR_NAME_IS_ERROR);
        }

        //登录成功,返回token
        JSONObject jsonObject = new JSONObject();
        //根据userId生成token
        String token = JwtUtil.sign(userId.toString());
        //将token存于Redis
        redisUtil.set("userToken_" + userId, token, 20, TimeUnit.DAYS);
        jsonObject.put("token", token);
        //返回token
        return InfoUtil.getInfo(jsonObject);
    }

hhhhh