zoukankan      html  css  js  c++  java
  • 【Jwt】JSON Web Token

    一.什么是JSON Web Token:

      首先要明确的是JSON Web Token:是一个开放标准,这个标准定义了一种用于简洁,自包含的用于通信双方之间以JSON对象的形式安全传递信息的方法

      而我们在项目中使用的JWT Token就是通过一定规范生成token,常用于单体应用或者微服务应用下的登录校验解决方法

      那么问题来了,现有的登录校验方案,有Cookie和Seesion这些会话技术,那么为什么还需要JSON,Web Token呢,下面就这些问题来说明

    二,JSON Web Token的组成

      JWT由三个部分组成:

        1.JWT头部 header

          -header部分用于描述JWT元数据的JSON对象,主要是用来哦描述签名部分所使用的算法

        2.JWT负载 payload

          -负载部分主要描述了加密对象的信息,如用户的id等等,也可以加写规范里面的东西,例如expire过期时间,iss签发者,sub面羡慕的用户等等

        3.JWT签名 signature

          -签名部分主要是讲前面的header部分和payload部分两部分进行加密,常用的是单向加密(也就是摘要算法,例如MD5,SHA等等,这些加解密算法,请阅读我另一篇博客)

           主要目的是为了防止别人那道token进行base解密后篡改token,用于保护数据的完整性

    三,为什么要使用JWT,而不使用会话技术Cookie或者Seesion,

         

       在前后端分离的项目中,前端部署在Ngnix,后端代码部署在应用服务器Tomcat,Nginx和Tomcat分别部署在不同的服务器,前端浏览器的请求

    通过Nginx代理转发到Tomcat所在的服务器中,并且前后端的交互也主要是通过ajax请求(例如,vue组件axios),在不设置跨域请求的前提下,Tomcat会将每一次的

    ajax请求作为一个新的请求,生成一个新的Session,因此需要设置添加Cookie,

       Cookie是Session的载体,是Http请求头中的属性,Session在服务端生成并保存到服务端,服务端每次响应,会将Session传给浏览器,浏览器在下次请求的时候会以在Cookie中以SessionID:xxxxxx的形式带入到服务端做会话验证;

         这里就有几个缺点:

        1.Session的内存占用问题

          Session在服务端生成,并保存到服务端,以常见得场景注册登录的场景为例,用户登录成功之后,服务端生成Session用来保持会话,

    很重要的一点就是,Session保存到内存中,当大量用户登录时,会造成大量内存被占用,造成服务器的压力;

        对比JWT Token 的认证方式,JWT同样也是在服务端生成响应给客户端,但是并不保存到服务端,减轻了服务器的内存压力,牺牲的仅仅是CPU在加解密时的计算性能,

    相比内存大量被Seesion占用,牺牲CPU的计算能力来的更加划算;

        2.用户信息的问题:

        传统的Seesion和Cookie仅作为会话保持,并没有携带相关的用户信息,相反的JWT的payload负载部分,有携带用户的基本信息,可以做为简单的用户校验等等

    四.JWT相关的代码以及工具类

    工具类

    /**
     * jwt工具类
     */
    public class JwtUtils {
    
    
        public static final String SUBJECT = "coolJWT";
    
        public static final long EXPIRE = 1000*60*60*24*7;  //过期时间,毫秒,一周
    
        //秘钥
        public static final  String APPSECRET = "xd666";
    
        /**
         * 生成jwt
         * @param user
         * @return
         */
        public static String geneJsonWebToken(User user){
    
            if(user == null || user.getId() == null || user.getName() == null
                    || user.getHeadImg()==null){
                return null;
            }
            String token = Jwts.builder().setSubject(SUBJECT)
                    .claim("id",user.getId())
                    .claim("name",user.getName())
                    .claim("img",user.getHeadImg())
                    .setIssuedAt(new Date())
                    .setExpiration(new Date(System.currentTimeMillis()+EXPIRE))
                    .signWith(SignatureAlgorithm.HS256,APPSECRET).compact();
    
            return token;
        }
        /**
         * 校验token
         * @param token
         * @return
         */
        public static Claims checkJWT(String token ){
    
            try{
                final Claims claims =  Jwts.parser().setSigningKey(APPSECRET).
                        parseClaimsJws(token).getBody();
                return  claims;
    
            }catch (Exception e){ }
            return null;
    
        }
    }

    在拦截器中进行JWT的校验(注意:C端不适合做复杂的权限校验)

    public class LoginIntercepter implements HandlerInterceptor {
    
    
        private static final Gson gson = new Gson();
    
        /**
         * 进入controller之前进行拦截
         * @param request
         * @param response
         * @param handler
         * @return
         * @throws Exception
         */
        @Override
        public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
    
            //token放在头Header信息中
            String token = request.getHeader("token");
            if(token == null ){
                token = request.getParameter("token");
            }
            if(token != null ) {
               //jWtUtils验证失败会返回null
               Claims claims =  JwtUtils.checkJWT(token);
                if(claims !=null){
                    Integer userId = (Integer)claims.get("id");
                    String name = (String) claims.get("name");
    
                    request.setAttribute("user_id",userId);
                    request.setAttribute("name",name);
                    //验证成功
                    return true;
                }
            }
            //验证失败
            sendJsonMessage(response,JsonData.buildError("请登录"));
            return false;
        }
        /**
         * 响应数据给前端
         * @param response
         * @param obj
         */
        public static void sendJsonMessage(HttpServletResponse response, Object obj) throws IOException {
            response.setContentType("application/json; charset=utf-8");
            PrintWriter writer = response.getWriter();
            writer.print(gson.toJson(obj));
            writer.close();
            response.flushBuffer();
        }
    }

    注册拦截器

    /**
     * 拦截器配置
     */
    @Configuration
    public class IntercepterConfig implements WebMvcConfigurer {
    
        @Override
        public void addInterceptors(InterceptorRegistry registry) {
    
            registry.addInterceptor(new LoginIntercepter()).addPathPatterns("/user/api/v1/*/**");
    
            WebMvcConfigurer.super.addInterceptors(registry);
        }
    }
  • 相关阅读:
    鼠标拖动DIV移动
    JS中事件&对象
    响应式与弹性布局
    JS中的变量和输入输出
    JS中的运算符&JS中的分支结构
    HTML基本标签
    CSS基础语法
    JS中循环结构&函数
    String 二
    StringBuffer
  • 原文地址:https://www.cnblogs.com/july-sunny/p/11721208.html
Copyright © 2011-2022 走看看