什么是Json Web Token

前言

Jwt全称Json Web Token, 是一种防篡改的数据格式, 可以明文, 可以加密. 我们可以用来存储简单的鉴权信息在Jwt之中.
现在主流的应用场景有单点登录, 替代Session, 一次性鉴权.

但是我发现了这篇文章Stop using JWT for sessions, 作者说不要用Jwt来进行身份认证.
建议看完本文后, 再深入阅读这篇文章.

Jwt只是一种数据格式, 就像JSON一样!
Jwt只是一种数据格式, 就像JSON一样!
Jwt只是一种数据格式, 就像JSON一样!
重要的话说3遍, 好了往下看.

结构组成

1
eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJKb2UifQ.gG3FV1r3HgYYUd04sTUh2asQbk68SjmkivuaBHCRhLo

上面是一个JWT, 分为3个部分, headerclaims都是用base64编码, 3个部分用.连接起来.

  1. header: 头部, 最少包含了签名算法.
  2. claims: 内容, 包含了你想要放进去的数据.
  3. signature: 签名

base64解码headerclaims可得

1
2
eyJhbGciOiJIUzI1NiJ9 ----> {"alg":"HS256"}
eyJzdWIiOiJKb2UifQ ----> {"sub":"Joe"}

后面的gG3FV1r3HgYYUd04sTUh2asQbk68SjmkivuaBHCRhLo是签名, 是不可读的, 签名算法就是headeralg字段的值HS256.
可以在Debugger工具测试.

Q1: 为什么说Jwt是防篡改的?
A1: 我们不知道签名的私钥, 不信你在Debugger工具试试, 用上面的headerclaims, 在不知道私钥的情况下, 你能得到gG3FV1r3HgYYUd04sTUh2asQbk68SjmkivuaBHCRhLo吗? 我就告诉你私钥是123456了, 你猜的到吗?

Q2: Jwt能用来替换Session吗?
A2: 它们应该是组合使用, 而不是对立的. Stop using JWT for sessions

Q3: 那我到底要在什么地方用Jwt?
A3: 一般移动端用的比较多, 移动端不像浏览器有一套透明的Cookie方案.

JJWT 应用

我们先来看一个例子

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
public class JwtTest {
@Test
void verify() {
long now = System.currentTimeMillis();

// 1. 生成 jwt
String key = Base64.getEncoder().encodeToString("signKey".getBytes(StandardCharsets.UTF_8));
JwtBuilder builder = Jwts.builder()
.setId("id") // JWT_ID
.setAudience("audience") // 接受者
.setSubject("subject") // 主题
.setIssuer("issuer") // 签发者
.addClaims(null) // 自定义属性
.setIssuedAt(new Date(now)) // 签发时间
.setNotBefore(new Date(now - 1)) // 生效时间
.setExpiration(new Date(now + 1000 * 60 * 60)) // 过期时间
.signWith(SignatureAlgorithm.HS256, key); // 签名算法以及密匙
String token = builder.compact();
System.out.println(token);

// 2. 解析 jwt
try {
Jws<Claims> jws = Jwts.parser()
.setSigningKey(key)
.parseClaimsJws(token);
JwsHeader header = jws.getHeader();
Claims claims = jws.getBody();

Assertions.assertEquals(SignatureAlgorithm.HS256.getValue(), header.getAlgorithm());
Assertions.assertEquals("id", claims.getId());
Assertions.assertEquals("audience", claims.getAudience());
Assertions.assertEquals("subject", claims.getSubject());
Assertions.assertEquals("issuer", claims.getIssuer());
} catch (ExpiredJwtException e) {
e.printStackTrace();
}
}
}

JwtBuilder使用Builder模式, 构建headerclaims, 最后再调用signWith方法添加signature签名.
之后我们使用Jwts.parser()来解析token, 在parseClaimsJws(token)会抛出一堆RuntimeException, 用来校验token是否有效.
得到的Claims其实就是一个Map, 我们从中获取需要的数据即可.

整合 Spring Boot

查看我在Github上的一个示例工程.
https://github.com/Ahaochan/project/tree/master/ahao-spring-boot-jwt

参考资料

点击进入云乞讨模式!
  • 本文作者: Ahaochan
  • 本文链接: What_is_Json_Web_Token?
  • 版权声明: 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
0%