(8)还没有用上JWT吗?10分钟掌握JWT

169 阅读3分钟

5 分钟认识JWT

JWT,全称为 JSON Web Token,是一种用于身份验证的标准。它使用 JSON 格式将信息进行编码,可以被签名和加密。JWT 通常用于 Web 应用程序中,用于验证用户身份。

JWT 由三部分组成:头部(header)、载荷(payload)和签名(signature)。

头部包含了使用的算法和令牌类型等信息,例如:

{
"alg":"HS256",
"type":"JWT"
}

载荷包含了需要传递的信息,例如:

{
  "sub": "1653945284140511233",
  "iat": 1683016853
}

签名用于验证消息的完整性,防止消息被篡改。

将Header和Payload用Base64URL编码后,再用点(.)连接起来。然后使用签名算法和密钥对这个字符串进行签名列如:

//伪代码
signature = HMACSHA256(header + "." + payload, secret);

生成签名的时候需要指定一个密码(secret)。该密码保存在服务器中,并且不能向用户公开。然后,使用标头中指定的签名算法根据以下公式生成签名。signature = HMACSHA256(header + "." + payload, secret); 在计算出签名哈希后,JWT头,有效载荷和签名哈希的三个部分组合成一个字符串,每个部分用"."分隔,就构成整个JWT对象。 以上三部分都是在服务器定义,当用户登陆成功后,根据用户信息,按照jwt规则生成token返回给客户端。

JWT 的工作流程如下:

  1. 用户提供用户名和密码进行登录。
  2. 服务器验证用户名和密码的正确性,并生成一个 JWT。
  3. 服务器将 JWT 发送给客户端。
  4. 客户端将 JWT 存储在本地。
  5. 客户端在后续的请求中将 JWT 添加到请求头中。
  6. 服务器验证 JWT 的有效性,并根据其中的信息进行相应的操作。

JWT 的优点是可以在跨域和分布式系统中进行身份验证,不需要使用 Session 或 Cookie,可以减少服务器端的存储和网络传输压力。但是需要注意的是,由于 JWT 是基于文本的标准,因此在网络传输中存在被篡改的风险。因此,在使用 JWT 进行身份验证时需要注意安全性。

JwtUtil 工具类封装

pom.xml 文件中引入 jjwt 依赖

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

配置文件设置密钥和过期时间

jwt.secret-key=xiaohuo@163.com!!
jwt.exp-time=PT1H

定义 JwtUtil

@Component
@Slf4j
public class JwtUtil {
    @Value("${jwt.secret-key}")
    private String secretKey;
    @Value("${jwt.exp-time}")
    private Duration expTime;
​
    /**
     * 签发token
     * @param subject:我一般用来存用户id
     * @param claims:存储在jwt的内容,一般不能放置敏感信息
     * @return
     */
    public String createToken(String subject, Map<String,Object> claims){
        JwtBuilder builder= Jwts.builder();
        /**
         * 负载主要存一些放置在jwt的信息
         * 不建议存敏感信息
         */
        if(claims!=null){
            builder.setClaims(claims);
        }
        /**
         * 主题 一般存用户id
         */
        if(StringUtils.hasLength(subject)){
            builder.setSubject(subject);
        }
        long currentMillis=System.currentTimeMillis();
        /**
         * 签发时间
         */
        builder.setIssuedAt(new Date(currentMillis));
       long millis= expTime.toMillis();
        /**
         * 过期时间
         */
       if(millis>0){
           long expMillis=currentMillis+millis;
           builder.setExpiration(new Date(expMillis));
       }
        /**
         * 签名密钥 不要对外公布
         */
       if(StringUtils.hasLength(secretKey)){
           SignatureAlgorithm signatureAlgorithm=SignatureAlgorithm.HS256;
           builder.signWith(signatureAlgorithm, DatatypeConverter.parseBase64Binary(secretKey));
       }
       return builder.compact();
    }
    /**
     * 解析token
     */
    public Claims pareToken(String token){
        try {
            Claims claims=Jwts.parser()
                    .setSigningKey(DatatypeConverter.parseBase64Binary(secretKey))
                    .parseClaimsJws(token).getBody();
            return claims;
        } catch (ExpiredJwtException e) {
            log.error("ExpiredJwtException:{}",e);
        } catch (UnsupportedJwtException e) {
            log.error("UnsupportedJwtException:{}",e);
        } catch (MalformedJwtException e) {
            log.error("MalformedJwtException:{}",e);
        } catch (SignatureException e) {
            log.error("SignatureException:{}",e);
        } catch (IllegalArgumentException e) {
            log.error("IllegalArgumentException:{}",e);
        }
        return null;
    }
​
    /**
     * 获取用户id方法
     * @param token
     * @return
     */
    public String getUserId(String token){
        Claims claims = pareToken(token);
        if(claims!=null){
            return claims.getSubject();
        }
        return null;
    }
    /**
     * 校验token是否符合要求
     * tue:校验通过
     * false:校验失败
     */
    public boolean validateToken(String token){
        try {
            Claims claims = pareToken(token);
            Date exp= claims.getExpiration();
            return exp.after(new Date());
        } catch (Exception e) {
            log.error("validateToken:{}",e);
            return false;
        }
​
    }
}