JWT:

JWT简介:

  • JWT是json web token的缩写,它将用户信息加密到token里,服务器不保存任何用户信息,服务器通过使用保存的密钥验证token的正确性,只要正确即通过验证
  • 优点是在分布式系统中,很好地解决了单点登录问题以及session共享的问题
  • 缺点是无法作废已颁布的令牌/不易应对数据过期

JWT的结构:

1、JWT长什么样

JWT是由三段信息构成的,将这三段信息文本用 . 链接一起就构成了JWT字符串

2、JWT的构成

第一部分我们称它为头部(header),第二部分我们称其为载荷(payload,类似于飞机上承载的物品),第三部分是签证(signature)

header:

jwt的头部承载两部分信息:

声明类型,这里是jwt

声明加密的算法,通常直接使用 HMAC SHA256

完整的头部就像下面这样的JSON:

{
    'typ':'JWT',
    'alg':'HS256'
}

然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分

payload:

载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分

  1. 标准中注册的声明
  2. 公共的声明
  3. 私有的声明

标准中注册的声明(建议但不强制使用):

  • iss:jwt签发者
  • sub:jwt所面向的用户
  • aud:接收jwt的一方
  • exp:jwt的过期时间,这个过期时间必须要大于签发时间
  • nbf:定义在什么时间之前,该jwt都是不可用的
  • iat:jwt的签发时间
  • jti:jwt的唯一身份标识,主要用来作一次性token,从而回避重放攻击

公共的声明:

公共的声明可以添加任何的信息,一般添加用户相关信息或其他业务需要的必要信息,但不建议添加敏感信息,应为该部分在客户端可解密

私有的声明:

私有声明是提供者和消费者所共同定义的声明,一般不建议存放敏感信息,因为base64是对称解密的,意味着该部分信息可以归类为明文信息

定义一个payload:

{
    "sub":"1234567890",
    "name":"John Doe",
    "admin":true
}

然后将其进行base64加密,得到JWT的第二部分

signature:

jwt的第三部分是一个签证信息,这个签证信息由三部分组成

  • header(base64后的)
  • payload(base64后的)
  • secret

这个部分需要base64加密后的header和base64加密后的payload使用,连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分

//javascriptvar encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload);
var signature = HMACSHA256(encodedString,'secret');

将这三部分用 . 连接成一个完整的字符串,构成了最终的jwt

JWT的应用:

一般是在请求头里加入Authorization或(xx_token),并加上xx标注:

$.ajax({
  type:'post',
    url:"http://localhost:8080/info",
    headers:{
        token:localStorage.getItem("Authorization")//获取token
    }
})

服务端会验证token,如果验证通过就会返回相应的资源。整个流程就是这样的:

image-20221022134638832.png

开发依赖包:

<dependency>
      <groupId>com.auth0</groupId>
      <artifactId>java-jwt</artifactId>
      <version>3.10.0</version>
    </dependency>
    <dependency>
      <groupId>io.jsonwebtoken</groupId>
      <artifactId>jjwt</artifactId>
      <version>0.9.1</version>
    </dependency>
    <dependency>
      <groupId>javax.xml.bind</groupId>
      <artifactId>jaxb-api</artifactId>
      <version>2.3.0</version>
    </dependency>
  • JWTUtils.java:
package com.ahnu.utils;
​
import io.jsonwebtoken.JwtBuilder;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
​
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
​
public class JWTUtils {
    private static final String SECRET = "#^%*hello";
​
    //生成token
    public static String generateToken(String acct) {
        Map<String,Object> claims = new HashMap<String,Object>();
        claims.put("acct",acct);
        JwtBuilder jwtBuilder = Jwts.builder();
//        签发算法,设置密钥
        jwtBuilder.signWith(SignatureAlgorithm.HS256,SECRET);
//        body数据,要唯一,自行设置
        jwtBuilder.addClaims(claims);
//        设置签发时间
        jwtBuilder.setIssuedAt(new Date());
//        设置过期时间 一天
        jwtBuilder.setExpiration(new Date(System.currentTimeMillis()+1000*60*60*24));
        String token = jwtBuilder.compact();
        return token;
    }
    
    //解密token
    public static Map<String,Object> parseToken(String token) {
        Jwt jwt = Jwts.parser().setSigningKey(SECRET).parse(token);
        Map<String,Object> claims = (Map<String, Object>) jwt.getBody();
        return claims;
    }
​
    public static void main(String[] args) {
        String token = JWTUtils.generateToken("admin");
        System.out.println(token);
        Map<String, Object> map = JWTUtils.parseToken(token);
        String acct = (String)map.get("acct");
        System.out.println(acct);
    }
}
​

总结:

  • 因为json的通用性,所以JWT是可以进行跨语言支持的,像Java,JavaScript,Node JS,PHP等很多语言都可以使用
  • 因为有了payload部分,所以JWT可以在自身存储一些其他业务逻辑所必要的非敏感信息
  • 便于传输,jwt的构成非常简单,字节占用很小,所以它是非常便于传输的
  • 它不需要在服务端保存会话信息,所以它易于应用的扩展
最后修改:2024 年 07 月 26 日
如果觉得我的文章对你有用,请随意赞赏