• work_37_SpringBoot如何结合jwt写一个优美的小程序登录


    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);
        }
    }
  • 相关阅读:
    win10 升级导致找不到SQL Server配置管理器
    【原创】Talend ETL Job日志框架——基于P&G项目的一些思考和优化
    【转】Talend作业设计模式和最佳实践-Part II
    【转】Talend作业设计模式和最佳实践-Part I
    【原创】Talend ETL开发——基于joblet的统一的email发送
    【原创】BI解决方案选型之ETL数据整合工具对比
    【原创】SQL Server Job邮件详细配置
    【原创】Oracle 11g R2 Client安装配置说明(多图详解)
    【原创】SQL SERVER 2012安装配置说明(多图详解)
    【原创】Win Server 2012R2 IIS 详细配置(多图详解)
  • 原文地址:https://www.cnblogs.com/asndxj/p/14132167.html
Copyright © 2020-2023  润新知