1.实现思路 

1).全局统一拦截,除带访问带有登录的请求路径以为所有请求全部拦截进行Token检验

2).在用户登录之后生成Token并将token返回给前台

3).实现细节如下

2.版本依赖SpringBoot+jwt

        <dependency>
                <groupId>org.mybatis.spring.boot</groupId>
                <artifactId>mybatis-spring-boot-starter</artifactId>
                <version>1.1.1</version>
        </dependency> 
            <!--jwt token验权-->
        <dependency>
            <groupId>com.auth0</groupId>
            <artifactId>java-jwt</artifactId>
        </dependency>

 3.全局统一拦截的实现

WebMvcConfigurer 接口详解https://www.cnblogs.com/pjjlt/p/11005811.html

/**
 * 功能描述:设置拦截器.
 * 打上configuration 注解,标注为配置项
 *
 * @author:hdh
 * @date: \ 11:01
 */
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {

    // 注入 token 拦截器
    @Autowired
    private TokenInterceptor interceptor;

    /**
     * 重写添加拦截器
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        // 添加自定义拦截器,并拦截对应 url
        registry.addInterceptor(interceptor).excludePathPatterns("/login/**");
    }
}

 4.拦截器实现

HandlerInterceptorAdapter 接口:重写拦截器  return true;放行
/**
 * 功能描述:创建一个 token 拦截器.
 * 需要继承 HandlerInterceptorAdapter,并且声明为spring的组件
 *
 * @author:hdh
 * @date: 2020/12/14 11:03
 */
@Component
public class TokenInterceptor extends HandlerInterceptorAdapter {

    // 注入jwt工具类
    @Autowired
    private JwtUtils jwtUtils;

    @Autowired
    private SessionUtils sessionUtils;

    // 重写 前置拦截方法
    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler)
            throws Exception {
        // 1、从请求头中获取token
        String token = request.getHeader("token");

        // 2、判断 token 是否存在
        if (token == null || "".equals(token)) {
            throw new TokenRuntimeException("token 获取失败");
        }

        //3、token是否过期
        boolean tokenExpired = jwtUtils.isTokenExpired(token);
        if (tokenExpired) {
            throw new TokenRuntimeException("token 过期");
        }

        // 4、解析token
        Map<String, Claim> checkMap = jwtUtils.checkToken(token);

        if (checkMap.size() == 0) {
            throw new TokenRuntimeException("token 解析错误");
        }

        //5、将userId存入session有效期2小时
        sessionUtils.setUserId(request, jwtUtils.getUserId(token));
        String userId = sessionUtils.getUserId();

        return true;
    }
}

 5.全局异常处理和全局返回结果处理

/**
*功能描述:自定义 token 异常

*@author:hdh
*@date: 2020/12/14 11:06
*/
@Data
public class TokenRuntimeException extends RuntimeException{
 
  private Integer code = 401;
  private String msg;
 
  public TokenRuntimeException(String msg) {
    this.msg = msg;
  }
 
}
/**
*功能描述:全局异常处理

*@author:hdh
*@date: 2020/12/14 11:05
*/
@RestControllerAdvice
public class SysRuntimeExceptionHandler {

    @ExceptionHandler(TokenRuntimeException.class)
    public ResponseEntity<String> tokenRuntimeException(TokenRuntimeException e) {
        e.printStackTrace();
        return ResultVo.createResponseEntity(ResultVo.CODE_UNAUTHORIZED, e.getMsg());
    }

    @ExceptionHandler(Exception.class)
    public ResponseEntity<String> handlerException(Exception e) {
        e.printStackTrace();
        return ResultVo.createResponseEntity(ResultVo.SYSTEM_ERROR, e.getMessage());
    }
}
package com.java110.vo;

import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;

import java.io.Serializable;

/**
*功能描述:ResultVo

*@author:hdh
*@date: 2020/12/14 11:07
*/
public class ResultVo implements Serializable {

    public static final int CODE_ERROR = 404;// 未知异常

    public static final int CODE_OK = 0; // 成功

    public static final int SUCCESS = 0; // 成功

    public static final int CODE_MACHINE_OK = 0; // 成功

    public static final int CODE_MACHINE_ERROR = -1; // 未知异常

    public static final int CODE_UNAUTHORIZED = 401; //认证失败
    public static final int CODE_WECHAT_UNAUTHORIZED = 1401; //认证失败
    public static final int SYSTEM_ERROR = 500; //系统错误

    public static final int ORDER_ERROR = 500; //订单调度异常


    public static final String MSG_ERROR = "未知异常";// 未知异常

    public static final String MSG_OK = "成功"; // 成功

    public static final String MSG_UNAUTHORIZED = "认证失败"; //认证失败

    public static final int DEFAULT_RECORD = 1;
    public static final int DEFAULT_TOTAL = 1;

    // 分页页数
    private int page;
    // 行数
    private int rows;

    //页数
    private int records;

    // 总记录数
    private int total;

    //状态嘛
    private int code;

    //错误提示
    private String msg;

    //数据对象
    private Object data;

    public ResultVo() {
    }

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

    public ResultVo(Object data) {
        this.code = CODE_OK;
        this.msg = MSG_OK;
        this.data = data;
    }

    public ResultVo(int records, int total, Object data) {
        this.code = CODE_OK;
        this.msg = MSG_OK;
        this.records = records;
        this.total = total;
        this.data = data;
    }

    public ResultVo(int code, String msg, Object data) {
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public ResultVo(int records, int total, int code, String msg, Object data) {
        this.records = records;
        this.total = total;
        this.code = code;
        this.msg = msg;
        this.data = data;
    }

    public int getPage() {
        return page;
    }

    public void setPage(int page) {
        this.page = page;
    }

    public int getRows() {
        return rows;
    }

    public void setRows(int rows) {
        this.rows = rows;
    }

    public int getRecords() {
        return records;
    }

    public void setRecords(int records) {
        this.records = records;
    }

    public int getTotal() {
        return total;
    }

    public void setTotal(int total) {
        this.total = total;
    }

    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 Object getData() {
        return data;
    }

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

    @Override
    public String toString() {
        return JSONObject.toJSONString(this, SerializerFeature.DisableCircularReferenceDetect, SerializerFeature.WriteDateUseDateFormat);
    }


    /**
     * 创建ResponseEntity对象
     *
     * @param data 数据对象
     * @return
     */
    public static ResponseEntity<String> createResponseEntity(Object data) {
        ResultVo resultVo = new ResultVo(DEFAULT_RECORD, DEFAULT_TOTAL, data);
        ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
        return responseEntity;
    }

    /**
     * 成功通用回复
     *
     * @return
     */
    public static ResponseEntity<String> success() {
        ResultVo resultVo = new ResultVo(CODE_OK, MSG_OK);
        ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
        return responseEntity;
    }

    /**
     * 创建ResponseEntity对象
     *
     * @param records 页数
     * @param total   总记录数
     * @param data    数据对象
     * @return
     */
    public static ResponseEntity<String> createResponseEntity(int records, int total, Object data) {
        ResultVo resultVo = new ResultVo(records, total, data);
        ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
        return responseEntity;
    }

    /**
     * 页面跳转
     *
     * @param url
     * @return
     */
    public static ResponseEntity<String> redirectPage(String url) {
        HttpHeaders headers = new HttpHeaders();
        headers.add(HttpHeaders.LOCATION, url);
        ResponseEntity<String> responseEntity = new ResponseEntity<String>("", headers, HttpStatus.FOUND);
        return responseEntity;
    }

    /**
     * 创建ResponseEntity对象
     *
     * @param code 状态嘛
     * @param msg  返回信息
     * @param data 数据对象
     * @return
     */
    public static ResponseEntity<String> createResponseEntity(int code, String msg, Object data) {
        ResultVo resultVo = new ResultVo(code, msg, data);
        ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
        return responseEntity;
    }

    /**
     * 创建ResponseEntity对象
     *
     * @param code 状态嘛
     * @param msg  返回信息
     * @return
     */
    public static ResponseEntity<String> createResponseEntity(int code, String msg) {
        ResultVo resultVo = new ResultVo(code, msg);
        ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
        return responseEntity;
    }

    /**
     * 创建ResponseEntity对象
     *
     * @param records 页数
     * @param total   总记录数
     * @param code    状态嘛
     * @param msg     返回信息
     * @param data    数据对象
     * @return
     */
    public static ResponseEntity<String> createResponseEntity(int records, int total, int code, String msg, Object data) {
        ResultVo resultVo = new ResultVo(records, total, code, msg, data);
        ResponseEntity<String> responseEntity = new ResponseEntity<String>(resultVo.toString(), HttpStatus.OK);
        return responseEntity;
    }
}
View Code

 

6.Jwt工具类

import com.auth0.jwt.JWT;
import com.auth0.jwt.JWTVerifier;
import com.auth0.jwt.algorithms.Algorithm;
import com.auth0.jwt.interfaces.Claim;
import com.auth0.jwt.interfaces.DecodedJWT;
import com.car.oa.exception.TokenRuntimeException;
import org.apache.commons.lang3.StringUtils;
import org.springframework.stereotype.Component;

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


@Component
public class JwtUtils {

    //设置过期时间
    private static final long EXPIRE_DATE = 60*1000*120;
    //token秘钥
    private static final String TOKEN_SECRET = "密钥";

    /**
     * 功能描述:生成token
     *
     * @author:hdh
     * @date: 2020/12/11 13:51
     */
    public String setToken(String userId) {

        String token = "";
        try {
            //过期时间
            Date date = new Date(System.currentTimeMillis() + EXPIRE_DATE);
            //秘钥及加密算法
            Algorithm algorithm = Algorithm.HMAC256(TOKEN_SECRET);
            //设置头部信息
            Map<String, Object> header = new HashMap<>();
            header.put("typ", "JWT");
            header.put("alg", "HS256");

            //携带username,password信息,生成签名
            token = JWT.create()
                    .withHeader(header)
                    .withClaim("userId", userId)
                    .withExpiresAt(new Date(System.currentTimeMillis() + EXPIRE_DATE))
                    .sign(algorithm);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
        return token;
    }

    /**
     * 解密Token
     *
     * @param token
     * @return
     * @throws Exception
     */
    public Map<String, Claim> checkToken(String token) {
        DecodedJWT jwt = null;

        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).build();
            jwt = verifier.verify(token);

        } catch (Exception e) {
            throw new TokenRuntimeException("token 解析异常");
            // token 校验失败, 抛出Token验证非法异常
        }
        return jwt.getClaims();
    }


    /**
     * 根据Token获取user_id
     *
     * @param token
     * @return user_id
     */
    public String getUserId(String token) {
        Map<String, Claim> claims = checkToken(token);
        Claim user_id_claim = claims.get("userId");
        if (null == user_id_claim || StringUtils.isEmpty(user_id_claim.asString())) {
            // token 校验失败, 抛出Token验证非法异常
        }
        return user_id_claim.asString().substring(0, 11);
    }

    /**
     * 判断 token 是否过期
     */
    public boolean isTokenExpired(String token) {
        DecodedJWT jwt = null;
        try {
            JWTVerifier verifier = JWT.require(Algorithm.HMAC256(TOKEN_SECRET)).build();
            jwt = verifier.verify(token);

        } catch (Exception e) {
            throw new TokenRuntimeException("token 过期");
            // token 校验失败, 抛出Token验证非法异常
        }
        Date expiresAt = jwt.getExpiresAt();

        //判断当前时间是否在过期时间之前  token时间小于当前时间返回true token时间大于当前时间返回false
        return expiresAt.before(new Date());
    }
}

7.sessionUtils

如何获取到token中的userId

@Component
/**
 *功能描述:session工具类
 *@author:hdh
 *@date: 2020/12/14 10:10
 */
public class SessionUtils {

    @Autowired
    HttpServletRequest request;

    //从session中获取userId
    public String getUserId() {
        HttpSession session = request.getSession();
        String userId = String.valueOf(session.getAttribute("userId")).substring(0, 11);
        return userId;
    }

    public void setUserId(HttpServletRequest request, String userId) {
        HttpSession session = request.getSession();
        session.setMaxInactiveInterval(60 * 120);
        session.setAttribute("userId", userId);
    }
}

 

posted on 2020-12-14 11:11  忆夏KhaZix  阅读(245)  评论(0编辑  收藏  举报