springboot(六)token验证

34 阅读2分钟

pom.xml中引入依赖

pom.xml

        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
            <version>3.8.1</version>
        </dependency>

配置文件中增加全局变量

application.yml

jwt:  
    header: "Authorization" #token返回头部  
    tokenPrefix: "Bearer " #token前缀  
    secret: "peng123456" #密钥  
    expireTime: 30 #token有效时间 (分钟) 建议一小时以上

增加jwt工具类

util/JWTUtil

package com.example.springboot2.util;

import com.auth0.jwt.JWT;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.exceptions.TokenExpiredException;
import com.example.springboot2.exception.JwtException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.stereotype.Component;

import java.util.Date;

@Component
@ConfigurationProperties(prefix = "jwt")
@Slf4j
public class JWTUtils {

    //定义token返回头部
    public static String header;

    //token前缀
    public static String tokenPrefix;

    //签名密钥
    public static String secret;

    //有效期
    public static long expireTime;

    //存进客户端的token的key名
    public static final String USER_LOGIN_TOKEN = "USER_LOGIN_TOKEN";

    public void setHeader(String header) {
        JWTUtils.header = header;
    }

    public void setTokenPrefix(String tokenPrefix) {
        JWTUtils.tokenPrefix = tokenPrefix;
    }

    public void setSecret(String secret) {
        JWTUtils.secret = secret;
    }

    public void setExpireTime(int expireTimeInt) {
        JWTUtils.expireTime = expireTimeInt*1000L*60;
    }

    /**
     * 创建TOKEN
     * @param sub
     * @return
     */
    public static String createToken(String sub){
        return tokenPrefix + JWT.create()
                .withSubject(sub)
                .withExpiresAt(new Date(System.currentTimeMillis() + expireTime))
                .sign(Algorithm.HMAC512(secret));
    }

    /**
     * 验证token
     * @param token
     */
    public static String validateToken(String token){
        try {
            return JWT.require(Algorithm.HMAC512(secret))
                    .build()
                    .verify(token.replace(tokenPrefix, ""))
                    .getSubject();
        } catch (TokenExpiredException e){
            throw new JwtException("token不能为空");
        } catch (Exception e){
            throw new JwtException("token验证失败");
        }
    }

    /**
     * 检查token是否需要更新
     * @param token
     * @return
     */
    public static boolean isNeedUpdate(String token){
        //获取token过期时间
        Date expiresAt = null;
        try {
            expiresAt = JWT.require(Algorithm.HMAC512(secret))
                    .build()
                    .verify(token.replace(tokenPrefix, ""))
                    .getExpiresAt();
        } catch (TokenExpiredException e){
            return true;
        } catch (Exception e){
            throw new JwtException("token已过期,请重新登录");
        }
        //如果剩余过期时间少于过期时常的一般时 需要更新
        return (expiresAt.getTime()-System.currentTimeMillis()) < (expireTime>>1);
    }
}

增加自定义jwt异常处理类

exception/JwtException

package com.example.springboot2.exception;

public class JwtException extends RuntimeException {
    public  JwtException(String errorMsg){
        super(errorMsg);
    }
}

把自定义jwt异常,增加到全局异常类中

exception/GraceExceptionHandler

package com.example.springboot2.exception;

import com.example.springboot2.util.JSONResult;
import org.apache.tomcat.util.http.fileupload.impl.FileSizeLimitExceededException;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;

@ControllerAdvice
public class GraceExceptionHandler {

    @ExceptionHandler(JwtException.class)
    @ResponseBody
    @ResponseStatus(value = HttpStatus.UNAUTHORIZED)
    public JSONResult returnJwtException(JwtException e){
        return JSONResult.errorMsg(e.getMessage());
    }
}

增加对token的拦截

interceptor/LoginInterceptor

package com.example.springboot2.interceptor;

import com.example.springboot2.util.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

@Slf4j
public class LoginInterceptor implements HandlerInterceptor {

    /**
     * 拦截请求,访问controller之前
     * @param request
     * @param response
     * @param handler
     * @return
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request,
                             HttpServletResponse response,
                             Object handler) {
        String token = request.getHeader("Authorization");
        JWTUtils.validateToken(token);
        return true;
    }

    /**
     * 请求访问到controller之后,渲染视图之前
     * @param request
     * @param response
     * @param handler
     * @param modelAndView
     * @throws Exception
     */
    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {
    }

    /**
     * 请求访问到controller之后,渲染视图之后
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {

    }
}

配置类中增加对jwt拦截的处理

package com.example.springboot2.config;

import com.example.springboot2.interceptor.LoginInterceptor;
import com.example.springboot2.interceptor.UserInfoInterceptor;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;

@Configuration
public class InterceptorConfig implements WebMvcConfigurer {

    @Bean
    public LoginInterceptor loginInterceptor() {
        return new LoginInterceptor();
    }


    public void addInterceptors(InterceptorRegistry registry){
        registry.addInterceptor(loginInterceptor())
                .addPathPatterns("/**")
                .excludePathPatterns("/login");//开放登录路径
    }
}

测试

登录controller

package com.example.springboot2.controller;

import com.example.springboot2.util.JSONResult;
import com.example.springboot2.util.JWTUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.web.bind.annotation.*;

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

@RestController()
@RequestMapping("login")
@Slf4j
public class LoginController {

    @PostMapping("")
    public JSONResult login(@RequestBody Map<String, Object> map){
        String username = (String) map.get("username");
        String password = (String) map.get("password");
        Boolean isAge = map.containsKey("age");
        if(map.containsKey("age")){
            log.info("aaa"+isAge);
        }else{
            log.info("bbb"+isAge);
        }


        if(!(username.equalsIgnoreCase("admin") && password.equalsIgnoreCase("123456"))){
            return JSONResult.errorMsg("账号密码错误");
        }

        String token = JWTUtils.createToken(username.toString());
        Map<String,Object> res = new HashMap<>();
        res.put("token",token);

        return JSONResult.ok(res);
    }
}


测试

无token image.png

登录,拿到token

image.png

有token

image.png