你好!在我们构建的系统中,有些API是公开的(比如登录),但大部分API(如查看订单详情)必须是登录用户才能访问。我们如何识别用户身份并控制权限呢?答案就是 JWT (JSON Web Token)。
在很久以前,Web应用普遍使用Session(会话)机制。
用户登录成功。
服务器创建一个“会话记录”保存在自己这里(比如内存或数据库里),并生成一个Session ID。
服务器把这个Session ID通过Cookie发给浏览器。
浏览器之后的每次请求都会带上这个Cookie。
服务器收到请求后,根据Session ID找到对应的会话记录,从而知道是哪个用户。
缺点: 服务器需要存储所有用户的会话信息,这叫有状态。当用户量巨大,或者系统由多台服务器组成时,管理和同步这些会话信息会成为一个巨大的负担。这违背了我们RESTful API提倡的“无状态”原则。
JWT是一种无状态的认证方案。它就像一张由服务器签发的、防伪的“数字通行证”。
工作流程:
用户使用账号密码登录。
服务器验证通过后,生成一个JWT(通行证)并返回给用户。
用户(浏览器)将这个JWT保存起来(通常在LocalStorage)。
当用户需要访问受保护的资源时,就在请求头里附上这个JWT,就像进门时出示通行证。
服务器收到请求后,检查这个通行证的“防伪标识”。如果有效,就予以放行。
全程服务器不需要存储任何东西。它只需要在需要时验证通行证的真伪即可。
一个JWT看起来是一长串由点(.)分割的字符串,像这样:xxxxx.yyyyy.zzzzz
它由三部分组成:
1. Header (头部)
内容: 描述JWT元数据,比如类型是JWT,以及使用的签名算法(如HMAC SHA256)。
格式: 一个JSON对象,经过Base64Url编码后形成第一段xxxxx。
Generated json
{
"alg": "HS256",
"typ": "JWT"
}
2. Payload (载荷)
内容: 存放实际需要传递的数据,也叫“声明(Claims)”。比如用户ID、用户名、角色、过期时间等。
重要: Payload里的信息是公开的!它只是被编码,没有被加密。绝对不要在Payload里存放敏感信息,如密码!
格式: 也是一个JSON对象,编码后形成第二段yyyyy。
Generated json
{
"sub": "user-123", // Subject, 通常是用户ID
"name": "Li Lei",
"roles": ["USER", "VIP"],
"exp": 1698384000 // Expiration Time, 过期时间戳
}
Use code with caution.Json
3. Signature (签名)
内容: 这是JWT的“防伪标识”,是保证Token不被篡改的关键。
生成方式:
Signature = HMACSHA256(base64UrlEncode(header) + "." + base64UrlEncode(payload), secret)
它由三部分混合计算而成:
编码后的Header
编码后的Payload
一个只有服务器知道的密钥(secret)
作用:
防篡改: 如果有人修改了Payload(比如把自己的角色从"USER"改成"ADMIN"),由于他没有服务器的secret,就无法生成正确的签名。服务器一验证签名,就会发现不匹配,从而拒绝请求。
验证来源: 只有用正确的secret才能签发有效的JWT,确保了通行证是由可信的服务器颁发的。
JWT是一种紧凑且自包含的认证方式,通过无状态的Token在各方之间安全地传递信息。
它的核心在于Signature,它利用服务器私有的secret来保证了信息的完整性和真实性。
在课程中,我们将使用Spring Security框架,轻松实现一整套基于JWT的登录认证和接口保护流程。
Comments (0)