1.什么是 JWT?
JWT(JSON Web Token) 是一种开放标准(RFC 7519),用于在网络应用间安全传输信息,通常用于身份验证和信息交换。其核心特点是通过紧凑且自包含的 JSON 对象传递数据,无需服务端存储会话状态。
2.JWT组成
- Header(头部):通常由以下两部分组成:
- Token 类型:通常是 JWT。
- 加密算法:例如 HS256(HMAC SHA-256)、RS256(RSA SHA-256)等。
- Payload(载荷) :JWT 的主体部分,通常为以下三类:
- 标准声明(Registered Claims):预定义的字段,如 iss(发行者)、exp (过期时间)、sub(主题)等。
- 公共声明(Public Claims):用户自定义的字段,例如用户 ID、用户名、角色等。
- 私有声明(Private Claims):在特定场景下使用的字段,通常用于内部系统。
- Signature(签名):用于验证 Token 的完整性和防止篡改。
它们之间用点“.”分隔,形成一个字符串(Token)。
3.执行流程
JWT 执行流程如下:
在 Spring Boot 项目中,JWT 的执行流程主要分为以下步骤:
3.1 用户登录与令牌生成
- 用户通过用户名和密码发起登录请求。
- 服务端验证用户凭证,若验证成功,则使用 JWT 工具类生成令牌:
- Header:指定算法(如 HS256)和令牌类型(JWT)。
- Payload:包含用户信息(如用户 ID、角色)和声明(如过期时间 exp)。
- Signature:使用密钥对 Header 和 Payload 进行签名,确保令牌不可篡改。
3.2 客户端存储令牌
- 服务端将生成的 JWT 返回给客户端(通常通过响应体或 Header)。
- 客户端(如浏览器或移动端)将令牌存储在本地(如 LocalStorage 或 Cookie)。
3.3 请求携带令牌
- 客户端在后续请求的 Authorization Header 中以 Bearer 格式携带 JWT。
3.4 服务端验证令牌
- 拦截器/过滤器:Spring Boot 通过自定义拦截器或 Spring Security 过滤器链拦截请求,提取并验证 JWT:
- 签名验证:使用密钥校验签名是否有效。
- 过期检查:检查 exp 字段是否过期。
- 用户信息提取:解析 Payload 中的用户信息(如用户 ID),用于后续权限控制。
3.5 授权与响应
- 若验证通过,服务端处理请求并返回数据。
- 若验证失败(如令牌过期或签名错误),返回 401 状态码或自定义错误信息。
4.JWT令牌如何生成?
这段代码是一个简单的 Java 方法,用于生成 JSON Web Token(JWT)字符串。下面是对代码的详细介绍:
Map<String,Object> claims参数
:传递一个 Map 对象,用于存储 JWT 的 payload(载荷)信息,这里包括用户的 id 和 username。- 生成JWT的有效时间:将当前时间+参数传递过来的时间为JWT的有效期限。
.setClaims(claims)
:将参数 claims 作为 JWT 的 payload 部分。.signWith(SignatureAlgorithm.HS256, "itheima")
:指定使用 HS256 签名算法,并提供一个密钥 "itheima" 进行签名。.setExpiration(new Date(System.currentTimeMillis() +ttlMillis
)
:设置 JWT 的过期时间为当前时间往后推迟ttlMillis秒。String jwt = Jwts.builder()... .compact();
:使用 Jwts.builder() 创建一个 JWT 构建器对象,然后设置其参数并最终调用 compact() 方法生成 JWT 字符串。
5.JWT令牌校验
这段代码是对JWT解密的一个Java方法,下面是对这段代码的解读(与上面JWT令牌生成对比着看)。
1.该方法有两个参数,第一个参数是对JWT加密时使用的密钥,第二个参数时加密过后的token(JWT令牌)。
2.Jwts.parser().setSigningKey(secretKey.getBytes(StandardCharsets.UTF_8)):调用该方法设置解密用的密钥;parseClaimsJws(token).getBody()设置解析的token并得到JWT的主体部分,通过使用相同的加密算法和密钥对接收到的 JWT 的头部和载荷进行签名计算,然后将计算得到的签名值与 JWT 中的签名值进行比较,以验证 JWT 的真实性。
3.返回claims集合(包含用户的个人信息像id,username等等)用来用户进行后续操作的验证和使用。
为什么JWT足够可靠?
1.篡改令牌中的任何一个字符,在对令牌解析时都会报错,所以JWT令牌十分的可靠。
2.验证JWT时会用相同的加密算法和密钥进行对JWT头部和载荷重新计算并与签名部分比较,而密钥通常是保留在服务端的,不会暴露出去,因此十分安全。
3.JWT设置了有效期,当JWT有效期结束,JWT将无法通过后续操作的验证,会被解析为非法令牌。
5.1在登录校验中,JWT发挥了什么作用?
- 先检查有无令牌,没有令牌就没登录,去登录。
- 登录后才有令牌,有令牌,再校验,无效了再去登录
注意事项
- 密钥安全:签名密钥需妥善保管,并定期修改,避免泄露。
- 无状态性:JWT 无需服务端存储会话信息,适合分布式系统。
6.JWT签名是如何被计算出来的,总结:
JWT 的签名是通过 HMAC(Hash-based Message Authentication Code)算法进行计算的。在生成 JWT 时,签名的计算过程如下:
- 首先,将 JWT 的头部和载荷以 Base64URL 编码的形式串联起来,中间使用一个点号(".")连接,形成未签名的部分。
- 使用指定的算法(比如在你的代码中使用的是HMAC-SHA256算法)和密钥对上一步得到的未签名部分进行签名计算,得到签名值。
- 将签名值添加到 JWT 中,形成最终的 JWT。
在验证 JWT 时,解析器会重复这个过程,使用相同的算法和密钥对接收到的 JWT 的头部和载荷进行签名计算,然后将计算得到的签名值与 JWT 中的签名值进行比较,以验证 JWT 的真实性。
7.JWT优点分析
JWT 相较于传统的基于会话(Session)的认证机制,具有以下优势:
- 无需服务器存储状态:传统的基于会话的认证机制需要服务器在会话中存储用户的状态信息,包括用户的登录状态、权限等。而使用 JWT,服务器无需存储任何会话状态信息,所有的认证和授权信息都包含在 JWT 中,使得系统可以更容易地进行水平扩展。
- 跨域支持:由于 JWT 包含了完整的认证和授权信息,因此可以轻松地在多个域之间进行传递和使用,实现跨域授权。
- 适应微服务架构:在微服务架构中,很多服务是独立部署并且可以横向扩展的,这就需要保证认证和授权的无状态性。使用 JWT 可以满足这种需求,每次请求携带 JWT 即可实现认证和授权。
- 自包含:JWT 包含了认证和授权信息,以及其他自定义的声明,这些信息都被编码在 JWT 中,在服务端解码后使用。JWT 的自包含性减少了对服务端资源的依赖,并提供了统一的安全机制。
- 扩展性:JWT 可以被扩展和定制,可以按照需求添加自定义的声明和数据,灵活性更高。
8.小结
JWT 是一种用于身份验证的开放标准,由 Header、Payload、Signature 组成。它的执行流程是:用户登录后生成加密令牌、客户端存储并在请求头携带、服务端验证签名和过期时间后授权。它的优点包括无状态、跨域支持、自包含性,适用于分布式系统和微服务架构,通过签名确保数据安全。