一、什么JWT
JWT(JSON Web Token)是一种用于在网络应用中传递信息的开放标准(RFC 7519)。它是一种紧凑且自包含的方式,用于表示要在两个实体之间安全地传输的信息。JWT 通常用于身份验证和授权,以及在跨域和跨语言的应用程序之间传递声明(claims)。
二、JWT 的基础概念
-
令牌(Token): JWT 是一种令牌,它是一个字符串,通常很短,可以轻松地在网络上传递。令牌包含了一些声明(claims)以及签名,用于验证令牌的完整性和真实性。
-
三部分组成: JWT 由三部分组成,它们用
.
分隔开来:-
Header(头部): 头部通常包含了两部分信息,令牌的类型(JWT)和所使用的签名算法,例如 HMAC SHA256 或 RSA。
-
Payload(负载): 负载包含声明(claims),声明是关于实体(通常是用户)和其他数据的声明。有三种类型的声明:
- 注册声明(Registered claims):这些声明是 JWT 规范中定义的标准声明,包括
iss
(签发者)、sub
(主题)、aud
(受众)、exp
(过期时间)、nbf
(生效时间)和iat
(签发时间)等。 - 私有声明(Private claims):这些声明是应用程序特定的自定义声明,用于在双方之间共享信息。
- 公共声明(Public claims):这些声明是标准化的声明,但不是强制性的。
- 注册声明(Registered claims):这些声明是 JWT 规范中定义的标准声明,包括
-
Signature(签名): 签名用于验证令牌的完整性和真实性。它由头部、负载和一个秘密密钥(或公钥,如果使用 RSA)进行签名。签名确保令牌在传输过程中没有被篡改。
-
-
安全性: JWT 是一种安全的令牌,因为它的内容是经过签名的,只有知道密钥的一方才能验证令牌的真实性。这确保了令牌在传输过程中不会被篡改。
-
无状态性: JWT 是无状态的,即它包含了所有必要的信息,无需在服务器端存储会话信息。这使得 JWT 适用于分布式和可伸缩的应用程序。
-
用途: JWT 主要用于身份验证和授权,以及在不同的应用程序之间传递声明信息。它可以用于单点登录(Single Sign-On,SSO)系统、跨域通信、API 访问控制等场景。
-
生命周期: JWT 可以设置过期时间(
exp
声明),以确保令牌不会无限期有效。一旦令牌过期,就需要重新生成一个令牌。
算出签名以后,把 Header、Payload、Signature 三个部分拼成一个字符串,每个部分之间用"点"(.
)分隔,这个字符串就是 JWT 。
三、如何基于 JWT 进行身份验证
-
用户登录: 用户提供用户名和密码进行登录。服务器验证用户名和密码的有效性。
-
生成 JWT: 如果用户名和密码有效,服务器生成一个 JWT(JSON Web Token)。这个令牌包含了用户的身份信息和其他声明(claims),并用服务器端的私钥进行签名以确保令牌的完整性和真实性。
-
将 JWT 发送给客户端: 服务器将生成的 JWT 发送给客户端。通常,JWT 放在 HTTP 响应的头部中,例如
Authorization
头部中,或者放在响应的 JSON 数据中。 -
客户端存储 JWT: 客户端接收到 JWT 后,通常会将其存储在本地,例如在浏览器的
localStorage
或sessionStorage
中,或者在移动应用程序的本地存储中。 -
在后续请求中发送 JWT: 客户端在后续的请求中,例如访问受保护的资源或进行其他操作时,将 JWT 放在请求的头部中,例如
Authorization
头部中的 Bearer 令牌。 -
服务器验证 JWT: 服务器在接收到请求时,会从请求头部中提取 JWT,并使用服务器端的公钥来验证 JWT 的签名。如果签名有效且令牌没有过期,服务器会信任令牌,并根据令牌中的声明来验证用户的身份和权限。
-
响应请求或拒绝访问: 根据 JWT 中的声明和验证结果,服务器可以决定响应请求,提供资源或执行操作,或者拒绝访问,并返回适当的错误消息。
四、使用java 验证jwt举例
-
引入依赖: 首先,确保您的项目中已经添加了"jjwt"库的依赖
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-api</artifactId>
<version>0.11.2</version>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-impl</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>io.jsonwebtoken</groupId>
<artifactId>jjwt-jackson</artifactId>
<version>0.11.2</version>
<scope>runtime</scope>
</dependency>
- 编写验证代码: 编写Java代码来验证JWT。下面是一个示例:
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;
import io.jsonwebtoken.Jwts;
import io.jsonwebtoken.SignatureAlgorithm;
import io.jsonwebtoken.security.Keys;
// 密钥(用于验证JWT的签名)
String secretKey = "zhaosan";
// 要验证的JWT
String jwtToValidate = "your-generated-jwt";
try {
// 使用密钥验证JWT的签名
Jws<Claims> jws = Jwts.parserBuilder()
.setSigningKey(secretKey.getBytes()) // 使用字节数组密钥验证JWT
.build()
.parseClaimsJws(jwtToValidate);
// 如果签名验证成功,您可以从JWT中提取声明
Claims claims = jws.getBody();
// 获取JWT中的声明
String username = claims.getSubject();
System.out.println("Username: " + username);
// 还可以验证其他声明,如过期时间(exp)等
// Date expirationDate = claims.getExpiration();
} catch (Exception e) {
// 验证失败
e.printStackTrace();
}
- 在上述示例中,我们使用
Jwts.parserBuilder()
创建JWT解析器,并使用密钥来验证JWT的签名。如果验证成功,我们可以从JWT中提取声明(例如用户名)。 - 处理异常: 请注意,在验证JWT时可能会出现异常,例如签名无效、过期时间已过等。因此,在实际应用中,请确保适当地处理这些异常,以便能够根据需要采取适当的操作。
- 安全性注意事项: 确保密钥(用于签名和验证JWT)的安全存储和管理非常重要。密钥泄露可能导致JWT被滥用,因此请采取适当的安全措施来保护密钥。