VIP免费

springboot集成JWT

jwt 原创
36
DEMO程序园
程序猿 2021-01-04
积分:0

简介:

一springboot集成JWT引入JWT相关依赖 <!--引入jwt依赖--> <dependency>     <groupId>com.auth0</groupId>     <artifactId>java-jwt</artifa

一 springboot集成JWT

引入JWT相关依赖

 <!--引入jwt依赖-->
<dependency>
    <groupId>com.auth0</groupId>
    <artifactId>java-jwt</artifactId>
    <version>3.5.0</version>
</dependency>
<dependency>
    <groupId>io.jsonwebtoken</groupId>
    <artifactId>jjwt</artifactId>
    <version>0.7.0</version>
</dependency>

编写JWT工具类

package com.democxy.common.utils;

import io.jsonwebtoken.*;
import java.util.Date;

/**
 * @author SHILING_DENG
 * @version 2020-05-05
 *
 */

public class JwtUtil {


    //设置过期时间为15分钟
    public static final long EXPIRE_TIME = 15*60*1000;

    /**
     * token私钥
     */

    private static final String TOKEN_SECRET = "6CvvNscuUDAq*JxE";

    /**
     * 签发JWT
     * @param id 可以设置为登录账户的ID
     * @param subject 可以是JSON数据,如登录用户的JSON字符串 尽可能少
     * @param ttlMillis token有效时间
     * @return
     */

    public static String signToken(String id, String subject, long ttlMillis) {
        long nowMillis = System.currentTimeMillis();
        Date now = new Date(nowMillis);
        JwtBuilder builder = Jwts.builder()
                .setId(id)
                .setSubject(subject)   // 主题
                .setIssuer("admin")     // 签发者
                .setIssuedAt(now)      // 签发时间
                .signWith(SignatureAlgorithm.HS256, TOKEN_SECRET); // 签名算法以及密匙
        if (ttlMillis >= 0) {
            long expMillis = nowMillis + ttlMillis;
            Date expDate = new Date(expMillis);
            builder.setExpiration(expDate); // 过期时间
        }
        return builder.compact();
    }

    /**
     * 验证JWT
     * @param token
     * @return
     */

    public static boolean validateToken(String token) {
        try {
            Claims claims = parseToken(token);
            if (claims!=null){
                return true;
            }else{
                return false;
            }

        } catch (ExpiredJwtException e) {
           return false;
        } catch (SignatureException e) {
            return false;
        } catch (Exception e) {
            return false;
        }
    }



    /**
     * 解析JWT字符串
     * @param token
     * @return
     * @throws Exception
     */

    public static Claims parseToken(String token){
        Claims body = null;
        try {
            body = Jwts.parser()
                    .setSigningKey(TOKEN_SECRET)
                    .parseClaimsJws(token)
                    .getBody();
        } catch (ExpiredJwtException e) {
            e.printStackTrace();
        } catch (UnsupportedJwtException e) {
            e.printStackTrace();
        } catch (MalformedJwtException e) {
            e.printStackTrace();
        } catch (SignatureException e) {
            e.printStackTrace();
        } catch (IllegalArgumentException e) {
            e.printStackTrace();
        }
        return body;
    }

    public static void main(String[] args){
//        String token = signToken("1", "admin", EXPIRE_TIME);
//        System.out.println(token);
//        System.out.println(validateToken(token));
    }
}

编写全局异常处理相关类

package com.democxy.common.exception;

/**
 * 自定义异常类
 * @author shiling
 * @version 2020-04-28
 */

public class CustomException extends RuntimeException {

    private int code;
    private String msg;

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    public CustomException() {
        this(1001"接口错误");
    }

    public CustomException(String msg) {
        this(1001, msg);
    }

    public CustomException(int code, String msg) {
        super(msg);
        this.code = code;
        this.msg = msg;
    }

}

package com.democxy.common.global;

/**
 * 响应数据
 */

public class ResponeData<T{

    private int code;

    private String msg;

    private T data;

    public int getCode() {
        return code;
    }

    public void setCode(int code) {
        this.code = code;
    }

    public String getMsg() {
        return msg;
    }

    public void setMsg(String msg) {
        this.msg = msg;
    }

    public T getData() {
        return data;
    }

    public void setData(T data) {
        this.data = data;
    }

    public ResponeData(T data) {
        this(ResultCode.SUCCESS,data);
    }

    public ResponeData(ResultCode resultCode, T data) {
        this.code = resultCode.getCode();
        this.msg = resultCode.getMsg();
        this.data = data;
    }
}
package com.democxy.common.global;

/**
 * 响应枚举类
 * @author shiling
 * @version 2020-04-28
 */

public enum ResultCode {

    VALIDATE_FAILED(1002"参数校验失败"),

    SUCCESS(200"操作成功"),

    FAILED(500"响应失败"),

    NOT_FOUND(404"未知请求"),

    LOGIN_FAILED(4040"登录失败!");

    private int code;
    private String msg;

    public int getCode() {
        return code;
    }

    public String getMsg() {
        return msg;
    }

    ResultCode(int code, String msg) {
        this.code = code;
        this.msg = msg;
    }


}
package com.democxy.common.exception;

import com.democxy.common.global.ResponeData;
import com.democxy.common.global.ResultCode;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.validation.BindException;
import org.springframework.validation.ObjectError;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;

/**
 * 全局异常处理类 加上@ControllerAdvice注解或者@RestControllerAdvice,
 * 加@RestControllerAdvice只能全局处理RestFul接口异常
 * @author shiling
 * @version 2020-04-28
 */

@RestControllerAdvice
public class ExceptionControllerAdvice {

    Logger logger = LoggerFactory.getLogger(ExceptionControllerAdvice.class);

    /**
     * 表单验证异常处理
     * @param e
     * @return
     */

    @ExceptionHandler(BindException.class)
    public ResponeData<StringBindExceptionHandler(BindException e
{
        ObjectError objectError = e.getAllErrors().get(0);
        // 注意哦,这里传递的响应码枚举
        logger.error("表单数据校验异常",e);
        return new ResponeData<>(ResultCode.VALIDATE_FAILED, objectError.getDefaultMessage());
    }

    /**
     * 自定义异常处理
     * @param e
     * @return
     */

    @ExceptionHandler(CustomException.class)
    public ResponeData<StringCustomExceptionHandler(CustomException e
{
        logger.error("自定义异常",e);
        // 注意哦,这里传递的响应码枚举
        if (4040 == e.getCode()){
            return new ResponeData<>(ResultCode.LOGIN_FAILED, e.getMsg());
        }else {
            return new ResponeData<>(ResultCode.FAILED, e.getMsg());
        }
    }

    /**
     * Exception异常处理
     * @param e
     * @return
     */

    @ExceptionHandler(Exception.class)
    public ResponeData<StringExceptionHandler(Exception e
{
        //记录日志信息
        logger.error("服务异常",e);
        // 注意哦,这里传递的响应码枚举
        return new ResponeData<>(ResultCode.FAILED, "服务异常!");
    }


}

编写登录拦截器

package com.democxy.common.interceptor;

import com.democxy.common.exception.CustomException;
import com.democxy.common.utils.JwtUtil;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

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

/**
 * 授权验证拦截器
 */

public class AuthenticationInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从 http 请求头中取出 token
        String token = request.getHeader("token");
        System.out.println(token);
        boolean verity = JwtUtil.validateToken(token);
        if (!verity){
            throw new CustomException(4040,"token过期,请重新登录");
        }
        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 {
    }
}

注册拦截器

package com.democxy.common.config;

import com.democxy.common.interceptor.AuthenticationInterceptor;
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 WebConfig implements WebMvcConfigurer {

    // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(new AuthenticationInterceptor())
                .addPathPatterns("/","/admin/**")
                .excludePathPatterns("/admin/account/login","/admin/account/logout");
    }

}

二 springboot基于注解和拦截器实现登录拦截

新建注解

package com.democxy.common.annotation;

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

/**
 * 在需要登录验证的Controller的方法上使用此注解
 * @Target 注解的作用范围 方法之上
 * @Retention 注解的生存周期  运行级别,注解存在于源码、字节码、java虚拟机中,主要用于运行时,可以使用反射获取相关的信息
 */


@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface LoginRequired {
}

新建拦截器

package com.democxy.common.interceptor;

import com.democxy.common.annotation.LoginRequired;
import com.democxy.common.exception.CustomException;
import com.democxy.common.utils.JwtUtil;
import org.springframework.web.method.HandlerMethod;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.lang.reflect.Method;

/**
 * 授权验证拦截器
 */

public class AuthenticationInterceptor implements HandlerInterceptor {

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        // 从 http 请求头中取出 token
//        String token = request.getHeader("token");
//        boolean verity = JwtUtil.validateToken(token);
//        if (!verity){
//            throw new CustomException(4040,"token过期,请重新登录");
//        }

        //基于注解配置登录拦截
        HandlerMethod handlerMethod = (HandlerMethod) handler;
        Method method = handlerMethod.getMethod();
        // 接口是否有@LoginRequired注解, 有则需要判断是否登录
        boolean annotationPresent = method.isAnnotationPresent(LoginRequired.class);
        if (annotationPresent) {
            // 验证token
            String token = request.getHeader("token");
            boolean verity = JwtUtil.validateToken(token);
            if (!verity) {
                throw new CustomException(4040"token过期,请重新登录");
            }
            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 {
    }
}

注册拦截器

package com.democxy.common.config;

import com.democxy.common.interceptor.AuthenticationInterceptor;
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 WebConfig implements WebMvcConfigurer {

    // 这个方法用来注册拦截器,我们自己写好的拦截器需要通过这里添加注册才能生效
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
//        registry.addInterceptor(new AuthenticationInterceptor())
//                .addPathPatterns("/","/admin/**")
//                .excludePathPatterns("/admin/account/login","/admin/account/logout");

        //基于注解配置拦截,只需要注册拦截器,不在需要指定拦截方法
        registry.addInterceptor(new AuthenticationInterceptor());
    }

}

使用注解

@ResponseBody
@RequestMapping(value = "getAccount",method = RequestMethod.POST)
@LoginRequired
public ResponeData<String> getAccountByToken(HttpServletRequest request) {
    Claims claims = JwtUtil.parseToken(request.getHeader("token"));
    String subject = claims.getSubject();
    return new ResponeData<>(ResultEnum.SUCCESS,subject);
}


评论
最新发布
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-19
2024-05-18
layui

微信扫码关注DEMO程序园公众号

本周热门
1989
1630
1387
1337
1279
1060
1041
995
868
516
热门下载
27
20
19
14
14
12
12
12
12
11