• SpringBoot整合JWT框架及JWT介绍


    一、传统Session认证

    1、认证过程:

    1、用户向服务器发送用户名和密码。
    2、服务器验证后在当前对话(session)保存相关数据。
    3、服务器向返回sessionId,写入客户端 Cookie。
    4、客户端每次请求,需要通过 Cookie,将 sessionId 回传服务器。
    5、服务器收到 sessionId,验证客户端。

    2、问题缺陷

    1、session保存在服务端,客户端访问高并发时,服务端压力大。
    2、扩展性差,服务器集群,就需要 session 数据共享。

    二、JWT简介

      JWT(全称:JSON Web Token),在基于HTTP通信过程中,进行身份认证,JWT它是目前最流行的跨域身份验证解决方案。

    1、认证流程

      JWT的工作原理:是在服务器身份验证之后,将生成一个JSON对象,这个 JSON 对象里存了一些用户的信息,比如id、role、name等(如:{"name": "**","role": "Admin","id":"**","Expire": "***"}),但是这个JSON对象肯定不能直接返回,所以需要加密一下,生成一个 token,就是一个加密字符串,然后将这个 token 发送回用户之后,当用户与服务器通信时,客户端在请求中需要将这个 token 一起发送回服务器,服务器再解析这个 token 生成之前的JSON对象,然后去认证了这个用户。

      当然为了防止用户篡改数据,服务器将在生成对象时添加签名,并对发回的数据进行验证。

      具体流程如下:

    1、客户端通过用户名和密码登录服务器;
    2、服务端对客户端身份进行验证;
    3、服务器认证以后,生成一个 JSON 对象生成的 token,发回客户端;
    4、客户端与服务端通信的时候,都要发回这个 token;
    5、服务端解析该token,然后得到这个JSON对象,获取用户身份;
    6、服务端可以不必存储该Token对象,身份信息都可以解析出来。

    2、为什么要使用 JWT

    (1)JWT基于json,非常方便解析。

    (2)可以在令牌中自定义丰富的内容,易扩展。

    (3)通过非对称加密算法及数字签名技术,JWT防止篡改,安全性高。

    (4)资源服务使用JWT可不依赖认证服务即可完成授权。

    3、JWT结构

      token长这样

    "token": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.
                  eyJzdWIiOiJhZG1pbiIsImlhdCI6iZEIj3fQ.
                  uEJSJagJf1j7A55Wwr1bGsB5YQoAyz5rbFtF"

      上面的Token被手动格式化了,实际上是用"."分隔的一个完整的长字符串,其结构如下:

    1、头部(header) 声明类型以及加密算法;
    2、负载(payload) 携带一些用户身份信息;
    3、签名(signature) 签名信息。

    (1)Header:

      这个json中的typ属性,用来标识整个token字符串是一个JWT字符串;它的alg属性,用来说明这个JWT签发的时候所使用的签名和摘要算法。typ跟alg属性的全称其实是type跟algorithm,分别是类型跟算法的意思。

      之所以都用三个字母来表示,也是基于JWT最终字串大小的考虑,同时也是跟JWT这个名称保持一致,这样就都是三个字符了。

      typ跟alg是JWT中标准中规定的属性名称。

    (2)Payload:

      payload用来承载要传递的数据,它的json结构实际上是对JWT要传递的数据的一组声明,这些声明被JWT标准称为claims,它的一个“属性值对”其实就是一个claim(要求),每一个claim的都代表特定的含义和作用。

    (3)signature

      签名是把header和payload对应的json结构进行base64url编码之后得到的两个串用英文句点号拼接起来,然后根据header里面alg指定的签名算法生成出来的。算法不同,签名结果不同。以alg: HS256为例来说明前面的签名是以HS256算法得到。

    4、JWT使用方式

      通常推荐的做法是客户端在 HTTP 请求的头信息Authorization字段里面:

    Authorization: Bearer <token>

      服务端获取JWT方式

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

    三、与SpringBoot整合

    1、核心依赖文件

    <!-- jjwt -->
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.1</version>
    </dependency>

    2、配置文件

    // 跟spring同级
    config:
      jwt:
        # 加密密钥
        secret: TestTokenSecret  // 这个自己定义
        # token有效时长
        expire: 3600
        # header 名称
        header: token

    3、JWT配置代码块

    @ConfigurationProperties(prefix = "config.jwt")
    @Component
    public class JwtConfig {
        /*
         * 根据身份ID标识,生成Token
         */
        public String getToken (String identityId){
            Date nowDate = new Date();
            //过期时间
            Date expireDate = new Date(nowDate.getTime() + expire * 1000);
            return Jwts.builder()
                    .setHeaderParam("typ", "JWT")
                    .setSubject(identityId)
                    .setIssuedAt(nowDate)
                    .setExpiration(expireDate)
                    .signWith(SignatureAlgorithm.HS512, secret)
                    .compact();
        }
        /*
         * 获取 Token 中注册信息
         */
        public Claims getTokenClaim (String token) {
            try {
                return Jwts.parser().setSigningKey(secret).parseClaimsJws(token).getBody();
            }catch (Exception e){
                e.printStackTrace();
                return null;
            }
        }
        /*
         * Token 是否过期验证
         */
        public boolean isTokenExpired (Date expirationTime) {
            return expirationTime.before(new Date());
        }
        private String secret;
        private long expire;
        private String header;
        // 省略 GET 和 SET
    }

      主要是看上面加粗的一个生成token,一个解析token的方法咯。

      网上其实也有蛮多 JwtUtil 工具类,可以自己搜的参考。

    四、拦截示例

      其实一般都会搭配SpringSecurity使用,这里自定义一个拦截器示例看下

    1、配置Token拦截器

    @Component
    public class TokenInterceptor extends HandlerInterceptorAdapter {
        @Resource
        private JwtConfig jwtConfig ;
        @Override
        public boolean preHandle(HttpServletRequest request,
                                 HttpServletResponse response,
                                 Object handler) throws Exception {
            // 地址过滤
            String uri = request.getRequestURI() ;
            if (uri.contains("/login")){
                return true ;
            }
            // Token 验证
            String token = request.getHeader(jwtConfig.getHeader());
            if(StringUtils.isEmpty(token)){
                token = request.getParameter(jwtConfig.getHeader());
            }
            if(StringUtils.isEmpty(token)){
                throw new Exception(jwtConfig.getHeader()+ "不能为空");
            }
            Claims claims = jwtConfig.getTokenClaim(token);
            if(claims == null || jwtConfig.isTokenExpired(claims.getExpiration())){
                throw new Exception(jwtConfig.getHeader() + "失效,请重新登录");
            }
            //设置 identityId 用户身份ID
            request.setAttribute("identityId", claims.getSubject());
            return true;
        }
    }

    2、拦截器注册

    @Configuration
    public class WebConfig implements WebMvcConfigurer {
        @Resource
        private TokenInterceptor tokenInterceptor ;
        public void addInterceptors(InterceptorRegistry registry) {
            registry.addInterceptor(tokenInterceptor).addPathPatterns("/**");
        }
    }

      然后就可以写接口测试了。

  • 相关阅读:
    Python合集之面向对象(六)
    Python合集之面向对象(五)
    Python合集之面向对象(四)
    Python合集之面向对象(三)
    Python合集之面向对象(二)
    Python合集之面向对象(一)
    Windows中杀死占用某个端口的进程
    docker mysql 中文乱码问题
    springboot 整合 mybatis
    elasticsearch 学习
  • 原文地址:https://www.cnblogs.com/goloving/p/14923580.html
Copyright © 2020-2023  润新知