SpringBoot 全局拦截请求(jwt token登录校验,全局拦截请求jwt)

https://www.jianshu.com/p/e369bf77bacb
springboot2.x jwt token登录校验,全局拦截请求jwt

springboot2.x jwt token登录校验,全局拦截请求jwt

pom.xml添加jwt依赖

 <!--jwt (json web token) token 生成 校验-->
    <dependency>
        <groupId>io.jsonwebtoken</groupId>
        <artifactId>jjwt</artifactId>
        <version>0.9.1</version>
    </dependency>

生成和解析token的工具类
1.对称加密算法

/**
 *  json web token
 * 生成和解析token的工具类
 * 对称加密算法
 *
 */
public class JwtTokenUtils {
    SecretKeySpec key;
    /**
     *
     * @param key
     * 密钥
     */
    public JwtTokenProvider(String key){
        SecretKeySpec secretKeySpec = new SecretKeySpec(key.getBytes(),
                SignatureAlgorithm.HS512.getJcaName());
        this.key=secretKeySpec;
    }
    /**
     * 生成token
     * @return
     */
    public String createToken(Claims claims){
        return Jwts.builder()
                .setHeaderParam("type","jwt")
//                .compressWith(CompressionCodecs.DEFLATE) //内容压缩
                .setClaims(claims) //jwt 主体内容
                .signWith(SignatureAlgorithm.HS512,key) //签名方式
                .compact(); //生成
    }
    /**
     *校验token
     * @param token
     * @return
     */
    public Claims parseToken(String token){
        try {
            return Jwts.parser()
                  .setSigningKey(key)
                  .parseClaimsJws(token)
                  .getBody();
        }catch (Exception e){
             return null;
        }
    }
    /**
     * Claims 初始化token有效时间 秒
     *  7天 单位秒  604800
     * @param expire 初始化token有效时间 秒
     * @return
     */
    public DefaultClaims getDefaultClaims(long expire) {
        Claims claims = initClaims(new DefaultClaims(), expire);
        return (DefaultClaims) claims;
    }
    /**
     * 设置token有效期
     * @param claims
     * @param expire
     * @return
     */
    public Claims setClaimsExpire(Claims claims,long expire) {
        return initClaims(claims, expire);
    }
    public Claims initClaims(Claims claims, long expire) {
        if (claims!=null && expire>0) {
            Date nowDate = new Date();
            Date expireDate = new Date(nowDate.getTime()+expire*1000);
            claims.setIssuedAt(nowDate);
            claims.setExpiration(expireDate);
        }
        return claims;
    }
  
}

2.非对称加密算法
采用RSA算法

/**
 * RSA 算法 
 */
public class RSAUtils {

    /**
     * 获取公钥
     * @param publicKey
     * @return
     * JDK
     * java.security.spec.X509EncodedKeySpec
     * java.security.KeyFactory
     */
    public static PublicKey getPublicKey(byte[] publicKey) {
        X509EncodedKeySpec spec = new X509EncodedKeySpec(publicKey);
        KeyFactory kf = null;
        try {
            kf = KeyFactory.getInstance("RSA");
            return kf.generatePublic(spec);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 获取私钥
     * @param privateKey
     * @return
     * JDK
     * java.security.spec.PKCS8EncodedKeySpec
     * java.security.KeyFactory
     */
    public static PrivateKey getPrivateKey(byte[] privateKey){
        PKCS8EncodedKeySpec spec = new PKCS8EncodedKeySpec(privateKey);
        try {
            KeyFactory kf = KeyFactory.getInstance("RSA");
            return kf.generatePrivate(spec);
        }catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 生成公私钥
     *  byte[] publicKeyBytes = keyPair.getPublic().getEncoded();
     *  byte[] privateKeyBytes = keyPair.getPrivate().getEncoded();
     * String publicKey = Base64.getEncoder().encodeToString(publicKeyBytes)
     */
    public static KeyPair generateKey(){
        try {
            KeyPairGenerator keyPairGenerator= KeyPairGenerator.getInstance("RSA");
            SecureRandom secureRandom = new SecureRandom();
            keyPairGenerator.initialize(1024,secureRandom);
            KeyPair keyPair = keyPairGenerator.generateKeyPair();
            return keyPair;
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
    }
}

RSAUtils 工具生成公私钥对

/**
 * 生成和解析token的工具类【非对称加密算法版】
 *
 *
 */
public class JwtToken2Utils {

    PublicKey publicKey;
    PrivateKey privateKey;

    public JwtToken2Utils (String publicKey,String privateKey){
        byte[] publicKeyBytes = Base64.getDecoder().decode(publicKey);
        byte[] privateKeyBytes = Base64.getDecoder().decode(privateKey);

        try {
            X509EncodedKeySpec publicKeySpec = new X509EncodedKeySpec(publicKeyBytes);
            KeyFactory publicKeyFactory = KeyFactory.getInstance("RSA");
            this.publicKey = publicKeyFactory.generatePublic(publicKeySpec);

            PKCS8EncodedKeySpec privateKeySpec = new PKCS8EncodedKeySpec(privateKeyBytes);
            KeyFactory privateKeyFactory = KeyFactory.getInstance("RSA");
            this.privateKey = privateKeyFactory.generatePrivate(privateKeySpec);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeySpecException e) {
            e.printStackTrace();
        }
    }
    public JwtToken2Utils (KeyPair  keyPair){
         this.publicKey = keyPair.getPublic();      
         this.privateKey =keyPair.getPrivate();        
    }

    /**
     * 生成token
     * @param claims
     * @return
     */
    public String createToken(Claims claims){
        return Jwts.builder()
                .setHeaderParam("type","jwt")
                .setClaims(claims) //claims,就是自定义的playload部分
//                .compressWith(CompressionCodecs.DEFLATE) //内容压缩
                .signWith(SignatureAlgorithm.RS512,privateKey) //签名用私钥
                .compact();
    }

    /**
     *
     * @param token
     * @return
     */
    public Claims parseToken(String token){
        Claims claims = Jwts.parser()
                .setSigningKey(publicKey)
                .parseClaimsJws(token)
                .getBody();
        return claims;
    }

    /**
     * Claims 初始化token有效时间 秒
     *  7天 单位秒  604800
     * @param expire
     * @return
     */
    public DefaultClaims getDefaultClaims(long expire) {
        Claims claims = initClaims(new DefaultClaims(), expire);
        return (DefaultClaims) claims;
    }

    /**
     * 设置token有效期
     * @param claims
     * @param expire
     * @return
     */
    public Claims setClaimsExpire(Claims claims,long expire) {
        return initClaims(claims, expire);
    }

    public Claims initClaims(Claims claims, long expire) {
        if (claims!=null && expire>0) {
            Date nowDate = new Date();
            Date expireDate = new Date(nowDate.getTime()+expire*1000);
            claims.setIssuedAt(nowDate);
            claims.setExpiration(expireDate);
        }
        return claims;
    }

}

拦截器Interceptor 拦截请求,校验jwt

/**
 * 自定义 注解
 * 是否需要校验jwt
 *
 * @Target:注解的作用目标
 * @Target(ElementType.TYPE)——接口、类、枚举、注解
 * @Target(ElementType.FIELD)——字段、枚举的常量
 * @Target(ElementType.METHOD)——方法
 * @Target(ElementType.PARAMETER)——方法参数
 * @Target(ElementType.CONSTRUCTOR) ——构造函数
 * @Target(ElementType.LOCAL_VARIABLE)——局部变量
 * @Target(ElementType.ANNOTATION_TYPE)——注解
 * @Target(ElementType.PACKAGE)——包
 *
 *@Retention:注解的保留位置
 *RetentionPolicy.SOURCE:这种类型的Annotations只在源代码级别保留,编译时就会被忽略,在class字节码文件中不包含。
 * RetentionPolicy.CLASS:这种类型的Annotations编译时被保留,默认的保留策略,在class文件中存在,但JVM将会忽略,运行时无法获得。
 * RetentionPolicy.RUNTIME:这种类型的Annotations将被JVM保留,所以他们能在运行时被JVM或其他使用反射机制的代码所读取和使用。
 * @Document:说明该注解将被包含在javadoc中
 * @Inherited:说明子类可以继承父类中的该注解
 *
 *
 *
 */
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginJWT {

    boolean required() default true;

}

自定义拦截Interceptor

/**
 * 自定义拦截器后,需要配置进Spring
 *
 * 拦截器Interceptor可以拿到原始的HTTP请求和响应的信息,
 *    也可以拿到你真正处理请求方法的信息,但是拿不到传进参数的那个值。
 *
 *拦截顺序:filter—>Interceptor-->ControllerAdvice-->@Aspect -->Controller
 *
 */
@Slf4j
@Component
public class JwtInterceptor implements HandlerInterceptor {

    @Value("${learn.jwt.secret}")
    private String secretKey;

    JwtTokenProvider jwtTokenProvider;

    /**
     * 在访问Controller某个方法之前这个方法会被调用。
     * @param request
     * @param response
     * @param handler
     * @return false则表示不执行postHandle方法,true 表示执行postHandle方法
     * @throws Exception
     */
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        log.info("Token Interceptor preHandle ");

        if ( !(handler instanceof HandlerMethod)){
            return true;//如果不是映射到方法直接通过
        }

        String token = request.getHeader("token");

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        //检查有没有需要用户权限的注解
        if (method.isAnnotationPresent(LoginJWT.class)){
            LoginJWT loginJWT = method.getAnnotation(LoginJWT.class);
            if (loginJWT.required()){
                // 执行认证
                if (token == null) {
                    throw new RuntimeException("无token,请重新登录");
                }
                //校验token是否有效
                jwtTokenProvider = new JwtTokenProvider(secretKey);
                Claims claims = jwtTokenProvider.parseToken(token);
                log.info("Token Interceptor preHandle claims :{}",claims);
                if (claims!=null){
                    log.info("Token Interceptor preHandle claims 有效" );
                }else {//过期了
                    //抛出异常
                    log.info("Token Interceptor preHandle claims 过期");
                    returnJson(response);//返回前端异常
                    return false;//不执行下一步chain链,直接repose返回
                }
                return true;
            }
        }

        return true;//false则表示不执行postHandle方法
    }

    /**
     * 请求处理之后进行调用,但是在视图被渲染之前(Controller方法调用之后)
     * preHandle方法处理之后这个方法会被调用,如果控制器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 {
        log.info("Token Interceptor postHandle");
    }

    /**
     * 不管有没有异常,这个afterCompletion都会被调用
     * @param request
     * @param response
     * @param handler
     * @param ex
     * @throws Exception
     */
    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        log.info("Token Interceptor afterCompletion");
    }
}
/**
     * 返回异常结果
     * @param response
     */
    private void returnJson(HttpServletResponse response){
        response.setCharacterEncoding("UTF-8");
        response.setContentType("application/json; charset=utf-8");
        try {
            Map<String, Object> result = new HashMap<>();
            result.put("code",400);
            result.put("message","用户令牌token无效");
            result.put("data", null);
            response.getWriter().print(result);
        } catch (IOException e){

        } finally {

        }
    }

在需要jwt验证的controller的方法上加上注解LoginJWT

   @GetMapping("/test")
    @LoginJWT
    public String test(){
        return "test";
    }
  • 1
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值