JWT令牌在登录系统中的工作原理及相关技术疑问
JWT常见疑问解答
嘿,我来帮你逐个拆解这些JWT的疑问,都是实际开发里常碰到的点:
1. 是否需要在JWT令牌中存储用户名和密码?
绝对不要存密码!JWT的payload是明文可解码的(虽然签名能防止篡改,但任何人拿到令牌都能轻松解析出payload内容),把密码放进去等于把敏感信息裸奔给所有人。
用户名可以存,但不是必须——其实更推荐存用户的唯一不可变标识(比如数据库里的user_id),因为用户名可能会被用户修改,而ID是固定的,后续验证身份更可靠。
2. 若需要存储用户信息,应如何存放?比如是否放在payload的sub字段中?
如果要存用户的主体标识,sub字段是JWT标准里推荐的(sub是subject的缩写,专门用来表示令牌的主体,也就是用户),比如:
{ "sub": "123456", "exp": 1735689600, "iat": 1694150400 }
如果需要额外存用户名,可以加一个自定义字段,比如"username": "johndoe",但还是那句话,优先用不可变的用户ID。再次强调:密码绝对不能出现在JWT的任何部分,哪怕你觉得加密了也不行,因为payload本身不加密,只是签名验证完整性。
3. 注册时是否需要将令牌存储到数据库?
不需要。JWT的核心优势就是无状态,服务器不需要存储令牌——后续验证的时候,只需要用服务器持有的密钥去验证令牌的签名和过期时间即可。
不过如果需要实现主动失效令牌(比如用户改密码、主动登出),那可能需要维护一个令牌黑名单(比如把失效的令牌ID或者用户ID+过期时间存到Redis这类缓存里),但注册环节完全没必要存储令牌,注册成功后直接生成令牌返回给客户端就行。
4. 相同用户数据生成的JWT令牌是否唯一?
你说得完全对!哪怕用户信息一模一样,生成的JWT也几乎不可能重复。原因有两个:
- 标准JWT里通常会包含
iat(签发时间戳)和exp(过期时间戳)字段,这两个值每次生成令牌都会变化,导致payload内容不同,签名后的结果自然也不同。 - 很多JWT库还会自动添加
jti(JWT唯一标识符)字段,这是一个随机生成的字符串,进一步保证每个令牌的唯一性。
5. 如何用JWT验证用户身份?完整流程是怎样的?
完整的身份验证流程应该是这样的:
- 登录阶段:
- 用户在客户端输入用户名/邮箱和密码,客户端把这些数据发给服务器。
- 服务器拿收到的密码,和数据库中存储的用户哈希密码进行比对(注意:数据库里绝对不能存明文密码,必须存哈希后的结果)。
- 密码验证通过后,服务器生成JWT:把用户唯一ID(比如
user_id)放到payload中,加上过期时间、签发时间等标准字段,然后用服务器的密钥对整个令牌进行签名,生成最终的JWT。 - 服务器把JWT返回给客户端,客户端把令牌存在本地(推荐用
HttpOnly、Secure的Cookie存储,比localStorage更安全)。
- 后续请求阶段:
- 客户端每次请求需要授权的接口时,把JWT放到请求头的
Authorization字段里,格式是Bearer <你的JWT令牌>。 - 服务器收到请求后,先提取出令牌,用自己的密钥验证签名是否有效,同时检查令牌是否过期、payload里的用户ID是否在数据库中存在。
- 所有验证通过后,服务器就确认请求来自合法用户,然后处理请求并返回结果。
- 客户端每次请求需要授权的接口时,把JWT放到请求头的
内容的提问来源于stack exchange,提问作者Aniketh Saha
相关产品推荐
相关产品推荐

