身份验证:登录之后,服务器怎么一直认得你?
2026/7/31 1:35:21 网站建设 项目流程

登录成功后,问题才刚刚开始

认证通过之后,真正的问题才出现:

下一次 HTTP 请求到来的时候,服务器怎么知道它仍然来自刚才已经认证的hzh

为什么 HTTP 会有这个问题?

场景是这样的:hzh输入账号密码登录商城,服务器核验成功后返回“登录成功”。五分钟后,hzh请求/orders

问题在于:第二次请求在应用层面是一次独立请求。即使底层连接可能被复用,服务器也不会自动知道这个请求还属于刚才登录的用户。

除非请求带上某种可验证的信息,证明它和第一次登录建立的身份有关。

所以,一个完整的机制通常是:

  1. 客户端提交认证材料,例如密码。
  2. 服务端验证认证材料。
  3. 服务端签发后续请求要用的凭据。
  4. 客户端在每个需要身份的请求中携带该凭据。
  5. 服务端验证凭据,并恢复或确认用户身份。
  6. 服务端再根据身份、资源和操作判断权限。

登录时完成的是“你是谁”的认证;后续请求一般不需要重新输密码,而是通过验证凭据来确认:这个请求是否仍然代表刚才认证过的用户。

换句话说,认证建立了身份,后续凭据维持了请求 -> 身份之间可信的关联。

一个可验证的凭据,至少要具备三种能力:

  1. 身份关联:能关联到hzh
  2. 可验证性:攻击者不能随便编造一个值就冒充hzh
  3. 时效控制:过期或退出登录后,应该能够失效。

Cookie + Session:最经典的方案

那我们用什么来维持这个身份?一个经典方案是Cookie + Session

这里先记住一句话:

Cookie 负责携带,Session 负责记录。

Cookie 是浏览器携带数据的一种机制;Session 则是服务端保存的会话状态。它们配合起来,才能完成登录态的维持。

一个完整的请求流程

1. 登录

用户提交账号密码,服务端验证通过后:

  1. 创建一条 Session,例如session_7f3...
  2. 把它和用户身份、过期时间等信息存到服务端。
  3. 把 Session ID 通过Set-Cookie发给浏览器。
2. 之后查看订单

浏览器之后访问/orders时,会自动带上 Cookie 中的sid。服务端用这个sid查找 Session,找到对应用户后,才知道请求来自谁。

需要注意:

  1. Cookie 本身不是认证机制。它只是浏览器自动携带数据的方式。
  2. Session 也不必放在单台应用内存中。有多台后端服务器时,可以把 Session 放到 Redis 等共享存储;否则第一次请求落到服务器 A,第二次落到服务器 B,B 就查不到登录状态。
  3. 认证成功后应该重新生成 Session ID。否则攻击者如果提前让用户带上一个已知 Session ID,就可能在用户登录后利用它冒充用户,这叫会话固定攻击

Session ID 必须具有足够高的随机度。服务器不相信 Cookie 里自称的用户,而是用这个随机 ID 查找自己保存的记录。

所以可以做到:

删除服务端的 session_7f3... -> 浏览器发送旧 Cookie -> 服务端查不到有效会话 -> 登录失效

退出登录时发生什么?

如果用户退出登录后,浏览器意外又发送了旧的sid,服务端该怎么处理?

  1. 用户请求POST /logout,携带sid=session_7f3...
  2. 服务端删除或标记session_7f3...失效。
  3. 服务端通过Set-Cookie指示浏览器删除 Cookie,这是辅助动作。
  4. sid再出现时,服务端查不到有效 Session,返回401 Unauthorized

真正让旧凭据失效的关键是第 2 步:服务端不再认可这条 Session。浏览器是否成功删掉 Cookie,不能作为唯一依赖。

Token、Session 和 JWT 到底是什么关系?

说到“后续请求带的凭据”,经常会遇到TokenJWT

Token是“后续请求可出示的凭据”这一类东西;JWT是 Token 可能采用的一种具体数据格式。

Session ID 本身也可以看成一种 Token。它只是一串随机值,具体身份信息在服务端保存。

所以,Token 和 JWT 不是两个平级的认证方案,而是“类别”和“一种具体实现”的关系。

先别急着把 Token 和 JWT 当成两个对立选项。它们更像是“凭据”与“凭据格式”的关系。

接下来可以从两个角度看:凭据由谁保存身份信息,以及服务端收到凭据后如何验证它

两种常见的 Token 设计

1. 不透明 Token(Opaque Token)

客户端: "r4nd0m-long-secret" 服务端: token -> { userId: alice, expiresAt, scopes }

不透明 Token 的结构本身没有业务意义。它和 Session ID 很像:服务端需要通过 Token 查询状态,才能知道它代表谁、有没有过期、能做什么。

优点是服务端可以随时吊销它;代价是每次验证通常都需要查状态。

2. JWT

客户端: header.payload.signature 服务端: 验签并校验声明 -> 读取受信任的声明

JWT 的 Payload 可以包含例如:

{ "sub": "hzh", "exp": 12345678910, "scope": "orders:read" }

服务端验证 JWT 时,除了验签,还需要检查允许的签名算法,以及expissaud等声明是否符合预期。全部通过后,服务端才能信任其中的身份和权限信息。

签名能证明:这些声明是持有对应密钥的一方签发的,且传输途中没有被篡改。

但必须注意:

JWT 的Base64URL 编码不是加密

普通签名 JWT 的内容,拿到它的人通常都能解码查看。签名提供的是完整性来源验证,不是保密性。所以不要把密码、银行卡号等特别敏感的信息放进 JWT Payload。

JWT 也不是天然“无状态”或更安全:如果要立刻吊销某个 JWT、强制用户下线,服务端通常仍需要维护黑名单、版本号或其他状态。它一旦被窃取,也可能在过期前被冒用。

Cookie 和 Token 并不冲突

Cookie 和 Token 并非互斥关系,它们解决的问题不同:

  • Cookie / Authorization Header:凭据怎样从客户端到服务端。
  • Session ID / Opaque Token / JWT:凭据具体是什么,以及服务端怎样验证它。

例如,JWT 可以放在AuthorizationHeader 中,也可以放在 Cookie 中;Session ID 通常放在 Cookie 中。选择哪种方式时,还要结合浏览器自动携带 Cookie、CSRF 风险、XSS 风险和具体业务场景来判断。

总结

可以把整件事记成一句话:

认证解决“你是谁”;授权解决“你能做什么”;Session 或 Token 解决“后续请求如何证明它还是你”。

无论选择 Cookie + Session、不透明 Token 还是 JWT,核心都一样:让服务器能够安全地验证请求携带的凭据,并据此恢复用户身份,再决定是否允许这次操作。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询