学习参考:BV1gk4y177DS
-------------------------------------------------------------------------------------------------------
- Java Web
- Spring/SpringMVC/SpringBoot
- Spring Security
官网:https://jwt.io/
JSON Web Token,简称 JWT,读音是 [dʒɒt],是一个基于 RFC 7519 的开放数据标准,它定义了一种宽松且紧凑的数据组合方式。其作用是:**JWT是一种加密后数据载体,可在各应用之间进行数据传输**。
JWT中一般涵盖了用户身份信息,每次访问时,server校验信息合法性即可。
一个 JWT 通常由 HEADER (头),PAYLOAD (有效载荷)和 SIGNATURE (签名)三个部分组成,三者之间使用“.”链接,格式如下:
header.payload.signature
**一个简单的JWT案例:**
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9 //header
.eyJ1c2VyX2luZm8iOlt7ImlkIjoiMSJ9LHsibmFtZSI6ImRhZmVpIn0seyJhZ2UiOiIxOCJ9XSwiaWF0IjoxNjgxNTcxMjU3LCJleHAiOjE2ODI3ODM5OTksImF1ZCI6InhpYW9mZWkiLCJpc3MiOiJkYWZlaSIsInN1YiI6ImFsbHVzZXIifQ //payload
.v1TxJ0mngnVx4t9O3uibAHPSLUyMM7sUM06w8ODYjuE //signature
> 注意三者之间有一个点号(“.”)相连
JWT的头部承载两部分信息:
- 声明类型,默认是JWT
- 声明加密的算法 常用的算法:HMAC 、RSA、ECDSA等
{
"alg": "HS256",
"typ": "JWT"
}
**alg**:表示签名的算法,默认是 HMAC SHA256(写成 HS256);
**typ**: 表示令牌(token)的类型,JWT 令牌统一写为 JWT。
使用Base64加密,构成了JWT第一部分-header:
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9
Payload 部分也是一个 JSON 对象,用来存放实际需要传递的有效信息。
标准载荷:有很多,建议使用,但不强制,对JWT信息作补充。
| 标准载荷 | 介绍 |
| --------------------- | -------------------------------------- |
| iss (issuer) | 签发人(谁签发的) |
| exp (expiration time) | 过期时间,必须要大于签发时间 |
| sub (subject) | 主题(用来做什么) |
| aud (audience) | 受众(给谁用的)比如:http://www.xxx.com |
| nbf (Not Before) | 生效时间 |
| iat (Issued At) | 签发时间 |
| jti (JWT ID) | 编号,JWT 的唯一身份标识 |
自定义载荷:可以添加任何的信息,一般添加用户的相关信息或其他业务需要的必要信息。但不建议添加敏感信息,因为该部分在客户端可解密。
{
"user_info": [
{
"id": "1"
},
{
"name": "dafei"
},
{
"age": "18"
}
],
"iat": 1681571257,
"exp": 1682783999,
"aud": "xiaofei",
"iss": "dafei",
"sub": "alluser"
}
使用Base64加密,构成了JWT第二部分-payload:
eyJ1c2VyX2luZm8iOlt7ImlkIjoiMSJ9LHsibmFtZSI6ImRhZmVpIn0seyJhZ2UiOiIxOCJ9XSwiaWF0IjoxNjgxNTcxMjU3LCJleHAiOjE2ODI3ODM5OTksImF1ZCI6InhpYW9mZWkiLCJpc3MiOiJkYWZlaSIsInN1YiI6ImFsbHVzZXIifQ
Signature 部分是对前两部分的签名,防止数据篡改。
首先,需要指定一个密钥(secret)。这个密钥只有服务器才知道,不能泄露给用户。然后,使用 Header 里面指定的签名算法(默认是 HMAC SHA256),按照下面的公式产生签名。
signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.)分隔,就可以返回给用户。
**因为有这个密钥的存在,所以即便调用方偷偷的修改了前两部分的内容,在验证环节就会出现签名不一致的情况,所以保证了安全性。**
使用Base64加密,构成了JWT第三部分-signature:
l6JdYARw4IHmjliSbh9NP6ji1L15qVneWTJU5noQ-k8
地址:https://tooltt.com/jwt-encode/
地址:https://tool.box3.cn/jwt.html
### 3.1 无状态
JWT 不需要在服务端存储任何状态,客户端可以携带 JWT 来访问服务端,在服务端直接进行校验(客户端无需缓存JWT),从而使服务端变得无状态。这样,服务端就可以更轻松地实现扩展和负载均衡。
### 3.2 可自定义
JWT 的载荷部分可以自定义,可以存储任何 JSON 格式的数据。这意味着我们可以使用 JWT 来实现一些自定义的功能,例如存储用户喜好、配置信息等等。
### 3.3 扩展性强
JWT 有一套标准规范,因此很容易在不同平台和语言之间共享和解析。此外,开发人员可以根据需要自定义声明(claims)来实现更加灵活的功能。
### 3.4 调试性好
由于 JWT 的内容是以 Base64 编码后的字符串形式存在的,因此非常容易进行调试和分析。
### 3.5 安全性取决于密钥管理
JWT 的安全性取决于密钥的管理。如果密钥被泄露或者被不当管理,那么 JWT 将会受到攻击。因此,在使用 JWT 时,一定要注意密钥的管理,包括生成、存储、更新、分发等等。
### 3.6 无法撤销
由于 JWT 是无状态的,一旦 JWT 被签发,就无法撤销。如果用户在使用 JWT 认证期间被注销或禁用,那么服务端就无法阻止该用户继续使用之前签发的 JWT。因此,开发人员需要设计额外的机制来撤销 JWT,例如使用黑名单或者设置短期有效期等等。
### 3.7 需要缓存到客户端
由于 JWT 包含了用户信息和授权信息,一般需要客户端缓存,这意味着 JWT 有被窃取的风险。
### 3.8 载荷大小有限制
由于 JWT 需要传输到客户端,因此载荷大小也有限制。一般不建议载荷超过 1KB,会影响性能。
- 无状态:JWT 本身不需要存储在服务器上,因此可以实现无状态的身份验证和授权。
- 可扩展性:JWT 的载荷可以自定义,因此可以根据需求添加任意信息。
- 可靠性:JWT 使用数字签名来保证安全性,因此具有可靠性。
- 跨平台性:JWT 支持多种编程语言和操作系统,因此具有跨平台性。
- 高效性:由于 JWT 不需要查询数据库,因此具有高效性。
- 安全性取决于密钥管理:JWT 的安全性取决于密钥的管理,如果密钥被泄露或者被不当管理,那么 JWT 将会受到攻击。
- 无法撤销令牌:由于 JWT 是无状态的,一旦 JWT 被签发,就无法撤销。
- 需要传输到客户端:由于 JWT 包含了用户信息和授权信息,因此 JWT 需要传输到客户端,这意味着 JWT 有被攻击者窃取的风险。
- 载荷大小有限制:由于 JWT 需要传输到客户端,因此载荷大小也有限制。
用户注册成功后发一份激活邮件或者其他业务需要邮箱激活操作,都是可以使用jwt。
原因:
JWT时效性:让该链接具有时效性(比如约定2小时内激活),
JWT不可篡改性:防止篡改以激活其他账户
使用 JWT 来做 RESTful api 的身份凭证:当用户身份校验成功,客户端每次接口访问都带上JWT,服务端校验JWT合法性(是否篡改/是否过期等)
JWT是在各方(项目间/服务间)之间安全传输信息的好方式。 因为JWT可以签名:例如使用公钥/私钥对,所以可以确定发件人是他们自称的人。 此外,由于使用标头和有效载荷计算签名,因此您还可以验证内容是否未被篡改。
JWT 令牌登录也是一种应用场景,但也是JWT被诟病最多的地方,因为JWT令牌存在各种不安全。
1>JWT令牌存储与客户端,容易泄露并被伪造身份搞破坏。
2>JWT 被签发,就无法撤销,当破坏在进行时,后端无法马上禁止。
上面问题可通过监控异常JWT访问,设置黑名单 + 强制下线等方式尽量避免损失。