JWT 作者:马育民 • 2021-06-30 10:03 • 阅读:10076 # JWT JWT,全拼 JSON Web Token ,是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。 该信息可以被 **验证** 和 **信任**,因为它是数字签名的。 官网:https://jwt.io/ # 应用场景 - **Authorization (授权)**: 最常见。一旦用户登录,后续每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。 - **Information Exchange (信息交换)**: 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWTs可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改。 # 传统session的缺点 - 传统的 session都是保存在内存中,而随着用户的增多,服务端的开销会明显增大。 - 跨域传递 cookie 限制 # JWT 好处 - 可将用户信息放入到 JWT 中,session不放数据,可接收服务器内存 - 跨域不能传递 cookie,但是能发送 JWT # 基于token的鉴权机制 基于token的鉴权机制类似于http协议也是无状态的,它不需要在服务端去保留用户的认证信息或者会话信息。这就意味着基于token认证机制的应用不需要去考虑用户在哪一台服务器登录了,这就为应用的扩展提供了便利。 流程上是这样的: 1. 用户 输入 用户名、密码,发送 **登录** 请求 2. 服务器进行验证用户的信息 3. 服务器通过验证,将用户信息放到 JWT,发送给 浏览器 4. 浏览器 存储 JWT,并在每次请求时附送上这个 JWT 5. 服务端验证 JWT,获取用户信息 6. 服务端向客户端发送响应 [](https://www.malaoshi.top/upload/pic/springcloud/20170505094543469.png) # JWT 结构 第一部分我们称它为头部(header),第二部分我们称其为载荷(payload, 类似于飞机上承载的物品),第三部分是签证(signature). 如下: [](https://www.malaoshi.top/upload/pic/springcloud/1497192-20190614135643073-1269712693.png) ### header jwt的头部承载两部分信息: - 声明类型,这里是jwt - 声明加密的算法 通常直接使用 HMAC SHA256 完整的头部就像下面这样的JSON: ``` { 'typ': 'JWT', 'alg': 'HS256' } ``` 然后将头部进行base64加密(该加密是可以对称解密的),构成了第一部分. ``` eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9 ``` ### playload 载荷就是存放有效信息的地方。这个名字像是特指飞机上承载的货品,这些有效信息包含三个部分 - 标准中注册的声明 - 公共的声明 - 私有的声明 标准中注册的声明 (建议但不强制使用) : - 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的第二部分。 ``` eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9 ``` ### signature jwt的第三部分是一个签证信息,这个签证信息由三部分组成: - header (base64后的) - payload (base64后的) - secret 这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。 ``` // javascript var encodedString = base64UrlEncode(header) + '.' + base64UrlEncode(payload); var signature = HMACSHA256(encodedString, 'secret'); // TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ ``` # JWT库 在 https://jwt.io/ 网站中收录有各类语言的JWT库实现(有关JWT详细介绍请访问 https://jwt.io/introduction/ ),其中JAVA语言到目前(2020-09)有6个实现库 - Auth0实现 的 java-jwt -- maven: com.auth0 / java-jwt / 3.3.0 - Brian Campbell实现的 jose4j -- maven: org.bitbucket.b_c / jose4j / 0.6.3 - connect2id实现的 nimbus-jose-jwt -- maven: com.nimbusds / nimbus-jose-jwt / 5.7 - Les Haziewood实现的 jjwt -- maven: io.jsonwebtoken / jjwt-root / 0.11.1 - Inversoft实现的prime-jwt -- maven: io.fusionauth / fusionauth-jwt / 3.5.0 - Vertx实现的vertx-auth-jwt. -- maven: io.vertx / vertx-auth-jwt / 3.5.1 原文出处:http://malaoshi.top/show_1IX1PA78nPBO.html