JWT

2022/02/17 系统安全 共 2358 字,约 7 分钟

JWT, 全称 JSON WEB Token,是一种基于JSON的、用于在网络上声明某种主张的令牌(token)。

JWT通常由三部分组成: 头信息(header), 消息体(payload)和签名(signature)。

结构

头信息指定了该JWT使用的签名算法:

header = '{"typ":"JWT","alg":"HS256"}'

HS256 表示使用了 HMAC-SHA256 来生成签名。

消息体包含了JWT的意图,不建议在此存放敏感信息:

payload = '{"loggedInAs":"admin","iat":1422779638}'//iat表示令牌生成的时间

未签名的令牌由base64url编码的头信息和消息体拼接而成(使用”.”分隔),签名则通过私有的key计算而成:

// 秘钥
key = 'secretkey'  
// base64编码
unsignedToken = encodeBase64(header) + '.' + encodeBase64(payload)  

签名是用签名算法对Base64编码后的信息进行加密

// 签名
signature = HMAC-SHA256(key, unsignedToken) 

最终生成的token(使用”.”分隔)如下:

token = encodeBase64(header) + '.' + encodeBase64(payload) + '.' + encodeBase64(signature) 

实际如下:

eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiYWRtaW4iLCLnrqHnkIblkZgiLCLnlLciXSwiZXhwIjoxNjQ1MTQ5MzcyfQ.jaiv9gvlnh7aSvvhWODukZB_tGZ9MtcobV5kDXPLBkI

JWT常常被用作保护服务端的资源(resource),客户端通常将JWT通过HTTP的Authorization header发送给服务端,服务端使用自己保存的key计算、验证签名以判断该JWT是否可信:

Authorization: Bearer eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiYWRtaW4iLCLnrqHnkIblkZgiLCLnlLciXSwiZXhwIjoxNjQ1MTQ5MzcyfQ.jaiv9gvlnh7aSvvhWODukZB_tGZ9MtcobV5kDXPLBkI

token的前面两部分只是经过了base64编码,是可以正常解码看到结果的,所以密码等隐私数据不能放在JWT。

demo

依赖jar

<dependency>
  <groupId>com.auth0</groupId>
  <artifactId>java-jwt</artifactId>
  <version>3.4.0</version>
</dependency>

java代码:

// 秘钥
private static final String SECRET = "this is secret";

public static void test() {
  String token = JWT.create()
    .withAudience("admin", "管理员", "男") //需要加密的数据
    .withExpiresAt(new Date()) //过期时间,用于校验
    .sign(Algorithm.HMAC256(SECRET));
  log.info("token = {}", token);

  // 校验token合法性
  Verification verification = JWT.require(Algorithm.HMAC256(SECRET));
  verification.build().verify(token);

  DecodedJWT decodedJWT = JWT.decode(token);

  List<String> audiences = decodedJWT.getAudience();
  log.info("audiences = {}", audiences.toString());

  Date expiresAt = decodedJWT.getExpiresAt();
  log.info("expiresAt = {}", expiresAt);
}

结果如下:

生成的token = eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhdWQiOlsiYWRtaW4iLCLnrqHnkIblkZgiLCLnlLciXSwiZXhwIjoxNjQ1MTQ5MzcyfQ.jaiv9gvlnh7aSvvhWODukZB_tGZ9MtcobV5kDXPLBkI
解码后audiences = [admin, 管理员, ]
解码后expiresAt = Fri Feb 18 09:56:12 CST 2022

优点

基于JSON,方便解析,可以在令牌中自定义丰富内容

防止篡改、安全性高

JWT无状态(服务端无需存储,不依赖认证服务)、易于水平扩展。

缺点

无法作废已经发放的令牌。所有的认证信息都在JWT中,由于在服务端没有状态,即使你知道了某个JWT被盗取了,你也没有办法将其作废。在JWT过期之前(你绝对应该设置过期时间),你无能为力。

使用场景

JWT最适合的场景是不需要服务端保存用户状态的场景,有效期很短,或者只希望使用一次等场景。

比如,用户注册后发一封邮件让其激活账户,通常邮件中需要有一个链接,这个链接需要具备以下的特性:能够标识用户,该链接具有时效性(通常只允许几小时之内激活),不能被篡改以激活其他可能的账户,一次性的。这种场景就适合使用jwt。

文档信息

搜索

    Table of Contents