暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

SpringBoot 集成 JWT

全栈精英 2023-03-08
1405

本文讲解SpringBoot项目集成JWT的基础用法

1.新建SpringBoot项目(本案例使用 2.7.X 版)

2.依赖(pom.xml)

除基本的 spring-boot-starter-web 包之外,需要导入的 JWT 相关的包有:

 <!--JWT 包-->
 <dependency>
     <groupId>com.auth0</groupId>
     <artifactId>java-jwt</artifactId>
     <version>3.19.2</version>
 </dependency>
 <!--JWT 工具包-->
 <dependency>
     <groupId>io.jsonwebtoken</groupId>
     <artifactId>jjwt</artifactId>
     <version>0.9.1</version>
 </dependency>

2.配置文件(application.properties)

自定义的配置信息:密钥和token的过期时间

 # 密钥
 jwt.secret=123456
 # tocken 过期时间,单位毫秒
 jwt.expire=60000

如果使用的yaml配置文件,写法是

 jwt: 
  secret: 123456
  expire: 60000

3.定义JWT工具类

包名:utils

类名:JWTUtil

 package com.hu.springbootjwt.utils;
 
 import com.auth0.jwt.JWT;
 import com.auth0.jwt.algorithms.Algorithm;
 import com.auth0.jwt.exceptions.JWTCreationException;
 import com.auth0.jwt.exceptions.JWTVerificationException;
 import com.auth0.jwt.interfaces.Claim;
 import com.auth0.jwt.interfaces.DecodedJWT;
 import com.auth0.jwt.interfaces.JWTVerifier;
 import io.jsonwebtoken.*;
 import org.springframework.beans.factory.annotation.Value;
 import org.springframework.stereotype.Component;
 
 import java.util.*;
 
 /**
   JWT的工具类
 */
 @Component
 public class JWTUtil {
 
     // 生成签名的秘钥(来自配置文件项的jwt.secret)
     private static String key;
 
     // jwt过期时间
     private static long ttlMillis;
 
     // 静态属性的注入必须显示set方法
     // import org.springframework.beans.factory.annotation.Value;
     // (来自配置文件项的jwt.secret)
     @Value("${jwt.secret}")
     public void setKey(String secret){
         key=secret;
    }
     // (来自配置文件项的jwt.expire)
     @Value("${jwt.expire}")
     public void setTtlMillis(Long expire){
         ttlMillis=expire;
    }
 
     /**
      * 用户登录成功后生成Jwt
      * 使用Hs256算法
      *
      * @param username 用户名
      * @param password 用户密码
      * @return token串
      */
     public static String createJWT(String username,String password) {
         // 使用的签名算法(header部分,jjwt包已封装,此处直接调用)
         SignatureAlgorithm signatureAlgorithm = SignatureAlgorithm.HS256;
 
         // 计算时间 (在后续使用)
         long nowMillis = System.currentTimeMillis();
         Date now = new Date(nowMillis);
 
         // 创建payload的私有声明(在后续使用)
         //(此处是存放的用户名和密码)
         Map<String, Object> claims = new HashMap<String, Object>();
         claims.put("username", username);
         claims.put("password",password);
 
         // 通过JwtBuilder,设置jwt的body部分
         JwtBuilder builder = Jwts.builder()
                 // 给builder的claim赋值(放入 payload 的私有声明,必须先写)
                .setClaims(claims)
                 // 设置JWT ID(JWT的唯一标识)
                 // 根据业务需要设置为一个不重复的值,用来作为一次性token, 从而回避重放攻击。
                .setId(UUID.randomUUID().toString())
                 // 设置jwt的签发时间
                .setIssuedAt(now)
                 // 所有人,作为用户的唯一标志
                .setSubject(username)
                 // 设置秘钥
                .signWith(signatureAlgorithm, key);
         
         //设置过期时间
         if (ttlMillis >= 0) {
             // 相对于当前时刻,在 ttlMillis 属性设置的时间后过期
             long expMillis = nowMillis + ttlMillis;
             Date exp = new Date(expMillis);
             builder.setExpiration(exp);
        }
         
         return builder.compact();
    }
 
 
     /**
      * Token的解密
      * @param token 加密后的token
      * @return 解密后的token
      */
     public static Claims parseJWT(String token) {
         // 使默认的JWT解析器
         Claims claims = Jwts.parser()
                 // 秘钥
                .setSigningKey(key)
                 // 获取 token 的内容
                .parseClaimsJws(token).getBody();
         return claims;
    }
 
 
     /**
      * 校验token
      * (校验逻辑是:token 携带的password 是否与传入的密码一致
      * @param token     原始token(加密的)
      * @param password 传入的密码
      * @return 是否校验成功
      */
     public static Boolean isVerify(String token, String password) {
         try {
             // 调用上面写的parseJWT方法
             Claims claims = parseJWT(token);
             // 校验
             if (claims.get("password").equals(password)) {
                 return true;
            }
        }
         catch (ExpiredJwtException e){
             e.printStackTrace();
        }
         return false;
    }
 }

4.控制器

在页面调用过程中测试 JWT 工具类的使用

 @RestController
 public class TestController {
     // 创建token
     @PostMapping("/get")
     public String creatToken2(){
          return JWTUtil.createJWT("zhangsan","123");
    }
 
     // 解析和校验token
     @PostMapping("/test")
     public String testToken2(HttpServletRequest request, HttpServletResponse response){
         String token= request.getHeader("Authorization");
         if (JWTUtil.isVerify(token,"123")){
             return "通过";
        }
         return "失败";
    }
 }

5.测试:

第一次请求http://localhost:8080/get

第一次结果:得到下面的token串 (每次请求会有变化)

eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ6aGFuZ3NhbiIsInBhc3N3b3JkIjoiMTIzIiwiZXhwIjoxNjU0ODMwOTgzLCJpYXQiOjE2NTQ4MzA5ODMsImp0aSI6ImY5MTMwMjBlLThhOWItNDg3Ni1iOTM1LTRiNjA3Mjk1MzE0MiIsInVzZXJuYW1lIjoiemhhbmdzYW4ifQ.mGZfLOQJJxBkJGsf9Li7doaHhoGGv0Kz84V1at0Q4OI

第二次请求http://localhost:8080/test

Authorization:  放入第一次请求拿到的token串(不要有换行)

第二次结果:通过

如果没有token串或token串错误(含过期)都会显示 “失败” 的结果

关于测试工具:使用postman或swagger,下面是使用的swagger+knife4j ,在全局参数设置页面,添加 Authorization 参数,其参数的值为 token 串


文章转载自全栈精英,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

评论