1. 完整回答
Web 认证与会话管理主要解决两个问题:确认用户身份,以及在多次 HTTP 请求之间维持用户的登录状态。
因为 HTTP 本身是无状态协议,服务器默认无法直接判断两次请求是否来自同一个已登录用户,所以需要一套认证和会话管理机制。
整个过程可以分为三个阶段。
首先是身份认证。用户提交账号密码,服务端验证通过后,会建立登录状态,并向客户端发放后续请求使用的凭证。
其次是登录状态维持。这里有两种常见的实现方案。
第一种是服务端 Session 方案。服务端保存用户的会话信息,生成一个随机的 Session ID,通常通过 Cookie 返回给浏览器。后续浏览器自动携带 Session ID,服务端根据它查询会话,就能知道当前用户是谁。
第二种是基于 Token 的方案。Token 本身是一个通用的凭证概念,可以是随机字符串,也可以采用 JWT 格式。如果使用签名 JWT,服务端可以把用户标识、有效期等声明写入令牌,后续通过验证签名和相关声明来确认令牌的有效性,从而减少会话状态查询。
最后是权限校验和会话生命周期管理。服务端确认用户身份后,还要判断用户能否访问对应资源,同时处理登录过期、主动退出、凭证刷新和异常撤销等问题。
安全方面,通常会结合 HTTPS、Cookie 安全属性、CSRF 和 XSS 防护,以及合理的过期策略。
实际项目中,普通 Web 后台可以优先使用服务端 Session;多个服务需要独立验证令牌时可以考虑 JWT;涉及第三方登录时,通常使用 OAuth 2.0 和 OpenID Connect。
2. 核心原理与关键概念
2.1 核心原理
- 身份认证与登录状态建立
用户提交账号密码 → 服务端验证密码 → 确认用户身份 → 建立登录状态 → 向客户端发放凭证。
服务端通常使用 Argon2id、bcrypt 等密码哈希算法验证密码,数据库保存的是密码哈希值,而非明文密码。
登录成功以后,客户端可以通过后续请求携带的凭证维持登录状态,避免每次访问都重新输入密码。
- 服务端 Session 方案
登录成功 → 服务端创建 Session → 生成 Session ID → 将 Session ID 写入 Cookie → 浏览器后续自动携带 Cookie → 服务端查询 Session → 确认用户身份。
例如,用户登录成功后:
-
服务端保存:
Session ID → 用户 ID、登录时间等会话信息 -
浏览器保存:
sessionId=abc123,这里仅用于示意,实际 Session ID 应使用安全随机值。
后续请求携带 sessionId,服务端根据它查询会话记录,判断是否有效。
这种方式的特点是登录状态主要保存在服务端,可以通过删除会话记录主动撤销登录状态。
- 基于签名 JWT 的方案
登录成功 → 服务端签发 JWT → 客户端保存 JWT → 后续请求携带 JWT → 服务端验证签名和有效期等声明 → 确认身份并检查权限。
JWT 可以通过以下请求头传递:
Authorization: Bearer <token>
也可以通过 Cookie 传递。
如果服务端只依靠 JWT 的签名和声明完成验证,就不需要每次查询服务端 Session。但如果业务需要立即撤销登录、检查实时权限,仍然可能需要查询服务端状态。
- 登录状态失效
登录成功 → 正常访问 → 会话续期或令牌刷新 → 退出登录或过期失效。
-
服务端 Session: 可以设置空闲超时和绝对过期时间,退出登录时删除服务端会话。
-
JWT: 可以设置较短的有效期,过期后重新认证或通过刷新令牌获取新的访问令牌。
-
提前撤销 JWT: 可以增加令牌撤销列表、用户会话版本或其他服务端状态校验机制。
2.2 关键概念
| 概念 | 本质 | 核心作用 |
|---|---|---|
| 认证(Authentication) | 身份验证过程 | 确认当前用户是谁 |
| 授权(Authorization) | 权限判断过程 | 判断用户能访问哪些资源 |
| 会话(Session) | 一段持续的用户交互状态 | 维持登录状态 |
| Session ID | 会话标识,也是凭证的一种 | 关联服务端保存的 Session |
| Token | 身份或访问权限凭证的统称 | 让客户端证明其身份或访问权限 |
| JWT | 一种结构化 Token 格式 | 携带可验证的声明 |
| Cookie | 浏览器数据存储与传递机制 | 常用于自动携带 Session ID 或 Token |
| Access Token | 访问令牌 | 访问受保护接口 |
| Refresh Token | 刷新令牌 | 获取新的 Access Token |
这里有一个关键关系:
Session 是会话管理概念,Token 是凭证概念,JWT 是 Token 的一种格式,Cookie 是浏览器传递凭证的一种方式。
它们并非完全互斥的技术方案。
例如:
-
服务端 Session 可以使用 Session ID 作为 Token,通过 Cookie 传递。
-
JWT 可以作为 Access Token,通过请求头或者 Cookie 传递。
-
Token 也可以是随机字符串,由服务端查询数据库或 Redis 验证。
因此,实际比较认证方案时,更准确的划分是服务端保存会话状态的方案,与使用可独立验证的签名 JWT 的方案。
3. 高频面试追问
3.1 Session 和 Token 是两种不同的认证机制吗?
严格来说,Session 是会话管理概念,Token 是凭证概念,两者属于不同层级,可以配合使用。
Session 表示客户端和服务端之间持续的一段会话。在常见的服务端 Session 方案中,服务器保存会话状态,客户端通过 Session ID 找到对应的会话。
Token 是一种通用凭证,代表持有者的身份或访问权限。它可以是随机字符串,也可以采用 JWT 格式。
实际上,Session ID 本身就属于一种 Token,因为它也是客户端用来证明自己拥有某个有效会话的凭证。
所以平时说的 Session 认证和 Token 认证,通常是在比较两类具体实现:
-
服务端 Session 方案: 服务端保存会话状态,通过 Session ID 查询。
-
自包含 JWT 方案: 服务端通过验证 JWT 的签名和声明,完成令牌校验。
两者的核心差异在于状态保存位置和凭证验证方式。
继续追问:使用 JWT,还需要 Session 吗?
如果 JWT 已经包含必要的身份声明,服务端可以直接验签,就不一定需要保存传统的服务端 Session。
但从业务角度看,用户仍然有一段持续的登录会话。如果需要单设备登录、强制下线、实时撤销等功能,可能还要引入服务端会话状态。
3.2 Cookie 和 Session 是什么关系?为什么通常配合使用?
Cookie 负责在浏览器和服务器之间传递数据,服务端 Session 负责保存会话状态。
例如用户登录成功后,服务端创建 Session,生成对应的 Session ID,并通过 Set-Cookie 响应头返回给浏览器。
后续浏览器访问匹配的地址时,会自动携带 Cookie。服务端根据 Session ID 查询会话,确认用户身份。
Cookie 中通常只需要保存 Session ID,用户信息和权限等数据可以留在服务端。
需要注意,Cookie 也可以保存 JWT,而且 Session ID 也可以通过自定义请求头传递。
因此,Cookie 是一种凭证传递方式,Session 是会话管理机制。
继续追问:Session Cookie 和 Session 是一回事吗?
两者含义不同。
Session Cookie 是浏览器中的一种 Cookie,通常没有显式设置 Max-Age 或 Expires,其生命周期由浏览器会话管理规则决定。
服务端 Session 则由服务器管理,可以设置独立的过期时间。即使浏览器仍保留 Cookie,只要服务端 Session 已经失效,用户就需要重新登录。
3.3 JWT 和普通随机 Token 有什么区别?JWT 为什么可以独立验证?
JWT 和随机 Token 的主要区别在于凭证结构及其验证方式。
普通随机 Token 通常是没有业务含义的随机字符串,也称为不透明 Token(Opaque Token)。服务端收到它以后,需要查询数据库、Redis 或调用令牌校验服务,判断它对应哪个用户、是否有效。
JWT 可以把用户标识、签发者、有效期等声明放进令牌,通过数字签名保证内容未被非法修改。
常见的签名 JWT 由三部分组成:
Header.Payload.Signature
-
Header: 描述令牌类型、签名算法等信息。
-
Payload: 保存用户标识、有效期等声明。
-
Signature: 用于验证令牌完整性和签发来源。
服务端验证时,会使用预先配置和允许的算法及密钥检查签名,再检查 exp、iss、aud 等适用的声明,最后执行权限判断。
这样就可以在不查询传统会话记录的情况下完成令牌校验。
继续追问:JWT 的 Payload 可以直接解码吗?
可以。常见签名 JWT 的 Payload 使用 Base64URL 编码,任何拿到令牌的人都可以解码查看内容。
签名可以防止内容被非法篡改,但不会隐藏其中的数据。因此,不应该把密码等敏感信息直接放进 Payload。
3.4 分布式系统中,Session 和 JWT 怎么选择?Session 为什么经常使用 Redis?
服务端 Session 和 JWT 都能用于分布式系统,主要区别在于服务端是否需要共享会话状态。
如果 Session 只保存在某台应用服务器的内存中,当用户下次请求被负载均衡到另一台服务器时,就可能查询不到对应的 Session。
常见解决方案是通过 Redis 集中保存会话状态。
流程是:
用户登录 → 应用服务器创建 Session → 保存到 Redis → 返回 Session ID → 后续任意应用服务器都可以通过 Redis 查询会话。
这样多个应用实例可以共享登录状态,也方便实现统一过期、强制下线等功能。
JWT 则可以由认证服务统一签发,再由多个业务服务使用对应的密钥或公钥独立验证,减少每次请求对集中会话存储的依赖。
但如果系统要求权限变更立即生效,或者令牌能够随时撤销,JWT 也可能需要额外的服务端查询。
实际项目中,普通后台管理系统我会优先考虑服务端 Session;多个独立服务需要验证统一签发的令牌时,可以考虑 JWT。具体还要看撤销需求、权限实时性和系统复杂度。
3.5 用户退出登录后,Session 和 JWT 怎么失效?Token 怎么实现无感刷新?
服务端 Session 可以直接撤销会话;独立验签的 JWT 通常依赖过期时间或额外的撤销机制。
对于服务端 Session,退出登录时删除服务端会话记录,并清理浏览器对应的 Cookie,就可以让该 Session ID 失效。
对于 JWT,如果服务端只验证签名和有效期,那么即使客户端删除了令牌,之前泄露的有效 JWT 仍然可能被使用。
解决方式通常包括:
-
设置较短的 Access Token 有效期。
-
使用服务端撤销列表或会话版本校验。
-
对需要实时失效的高风险操作增加服务端状态检查。
如果还需要长期维持登录,可以使用 Access Token + Refresh Token:
正常访问 → Access Token 过期 → 使用 Refresh Token 请求刷新 → 服务端验证刷新令牌 → 返回新的 Access Token → 客户端继续访问。
Refresh Token 需要受到更严格的保护,通常配合服务端撤销和轮换机制。
继续追问:Refresh Token 轮换机制是什么?
每次使用 Refresh Token 成功刷新后,服务端会签发新的 Refresh Token,并使旧令牌失效。
如果旧令牌再次被使用,服务端就能检测到异常重复使用,并根据策略撤销相关令牌。
这种方式可以降低刷新令牌长期被盗用的风险。
3.6 Token 存储在 Cookie 还是 localStorage?哪个更安全?
对于浏览器中的敏感登录凭证,我通常优先考虑 HttpOnly Cookie,或者使用 BFF 模式让服务端保管访问令牌。
localStorage 的特点是页面刷新后数据仍然存在,前端 JavaScript 可以直接读取,使用起来比较方便。
但如果网站存在 XSS 漏洞,恶意脚本也可能读取其中的 Token,并将其发送给攻击者。
HttpOnly Cookie 可以阻止 JavaScript 直接读取凭证,降低令牌被脚本窃取的风险。
不过,浏览器会按照 Cookie 规则自动发送它,因此还需要处理 CSRF 风险。
对于使用 OAuth 的复杂前后端分离应用,也可以采用 BFF(Backend for Frontend)架构,由后端保存 Access Token,浏览器只持有受保护的会话 Cookie。
继续追问:HttpOnly Cookie 能彻底防止 XSS 吗?
不能。HttpOnly 能防止脚本直接读取 Cookie,但恶意脚本仍可能在当前页面上下文中发送携带 Cookie 的请求。
所以仍然需要做好输出编码、输入处理和内容安全策略等防护。
3.7 CSRF 和 XSS 有什么区别?Cookie 的安全属性有哪些?
CSRF 主要利用浏览器自动携带登录凭证的行为,XSS 主要利用网站执行了攻击者注入的恶意脚本。
例如用户已经登录某个网站,攻击者诱导用户访问恶意页面,触发对原网站的修改操作。如果原网站缺少必要的请求校验,就可能发生 CSRF。
常见的 CSRF 防护措施有:
-
使用 CSRF Token,并由服务端验证。
-
对修改数据的请求检查 Origin 等来源信息。
-
设置合理的 Cookie SameSite 属性。
-
避免使用 GET 请求执行修改数据的操作。
XSS 则通常通过对输出进行上下文相关的编码、避免执行不可信 HTML 或脚本,以及配置 CSP 等方式防护。
对于登录 Cookie,常用的安全属性包括:
| 属性 | 作用 |
|---|---|
| HttpOnly | 阻止 JavaScript 直接读取 Cookie |
| Secure | 限制 Cookie 通过 HTTPS 发送 |
| SameSite=Strict | 限制跨站请求携带 Cookie |
| SameSite=Lax | 允许部分跨站顶层导航携带 Cookie |
| SameSite=None | 允许跨站携带,需要同时设置 Secure |
需要注意,SameSite 只是 CSRF 防护的一部分,不能覆盖所有攻击场景。
继续追问:如果 Token 放在 Authorization 请求头里,还会有 CSRF 吗?
如果凭证只由客户端 JavaScript 主动添加到请求头,攻击者无法让浏览器自动附加该凭证,那么传统依赖自动携带 Cookie 的 CSRF 风险会明显降低。
但系统仍然需要关注 XSS,以及其他可能自动携带的认证凭证。是否存在 CSRF 风险取决于实际的凭证传递和请求处理方式。
3.8 什么是 Session 劫持和 Session 固定攻击?怎么防护?
Session 劫持是攻击者获取有效会话凭证后冒用用户身份;Session 固定攻击是攻击者设法让受害者登录时使用攻击者已知的 Session ID。
Session 劫持可能通过 Cookie 泄露、XSS 或不安全的传输方式发生。
如果攻击者拿到了有效的 Session ID,就可能在会话失效前冒用用户身份。
Session 固定攻击则通常发生在系统登录成功后没有重新生成 Session ID 的情况下。
例如攻击者提前让受害者使用某个已知的 Session ID,受害者登录成功后,如果这个 ID 继续有效并关联到登录身份,攻击者就可能复用它。
防护方面,我会采取以下措施:
-
使用 HTTPS 和安全的 Cookie 属性。
-
使用不可预测的高强度随机 Session ID。
-
登录成功或权限等级变化后重新生成 Session ID。
-
设置空闲超时和绝对过期时间。
-
退出登录时在服务端撤销会话。
-
对修改密码等敏感操作重新验证身份。
继续追问:滑动过期和绝对过期有什么区别?
滑动过期会根据用户活动延长会话的空闲超时时间;绝对过期则限制会话从建立开始的最长存活时间。
实际系统中可以结合使用,既减少频繁登录,也避免会话无限期有效。
3.9 身份认证和权限授权有什么区别?401 和 403 分别代表什么?
身份认证负责确认用户是谁,权限授权负责判断用户能执行什么操作。
例如用户输入账号密码并登录成功,完成了身份认证。
但普通用户访问管理员接口时,仍然需要权限校验。
除了接口权限,还要校验具体的数据访问权限。比如用户访问订单详情时,服务端需要确认该订单是否属于当前用户,防止通过修改订单 ID 访问其他人的数据。
在 HTTP 状态码中:
-
401 Unauthorized: 请求缺少有效认证凭证,例如未登录、Token 过期或无效。
-
403 Forbidden: 服务端拒绝执行请求,典型情况是用户已认证,但没有访问目标资源的权限。
因此,令牌验证通过,只能说明凭证满足相应的验证要求,不能直接代表用户拥有全部业务权限。
3.10 OAuth 2.0、OIDC 和 JWT 有什么关系?第三方登录一般怎么实现?
OAuth 2.0 是委托授权框架,OpenID Connect(OIDC)在它的基础上提供标准化身份认证能力,JWT 则是一种令牌格式。
例如用户允许第三方应用访问自己的云盘文件,属于 OAuth 2.0 的典型授权场景。
如果网站支持使用 Google 等第三方账号登录,通常会采用 OIDC,让第三方身份提供方完成认证,并向业务应用提供可信的用户身份信息。
现代 Web 应用一般采用授权码模式 + PKCE:
用户点击第三方登录 → 跳转身份提供方 → 用户完成认证和必要的授权 → 返回授权码 → 使用授权码和 PKCE 验证参数交换令牌 → 校验身份信息 → 建立业务系统自己的登录状态。
PKCE 可以降低授权码被截获后遭到非法兑换的风险。
OIDC 中的 ID Token 通常采用 JWT 格式,用来向客户端表达身份认证结果;Access Token 则用于访问受保护资源。
继续追问:第三方登录成功后,业务系统还需要自己的 Session 吗?
通常需要维护自己的登录状态。
例如第三方身份认证成功后,业务系统可以找到或创建本地用户,再建立自己的服务端 Session 或签发应用内部使用的凭证。
这样业务系统就可以独立管理本地登录状态、用户角色和业务权限。
4. 易混淆概念对比
4.1 Session、Session ID、Token、JWT、Cookie
| 概念 | 所属层级 | 主要含义 |
|---|---|---|
| Session | 会话管理 | 用户持续交互的会话状态,常见实现由服务端保存 |
| Session ID | 会话凭证 | 用于查找服务端 Session 的标识 |
| Token | 通用凭证 | 用于证明身份、会话持有权或访问权限 |
| JWT | 凭证格式 | 能携带声明并提供签名或加密机制 |
| Cookie | 浏览器机制 | 负责存储数据并按规则在请求中发送 |
这几个概念之间可以组合使用。Session ID 属于 Token 的一种,JWT 也属于 Token 的一种,Cookie 则可以用于传递它们。
4.2 服务端 Session 方案与签名 JWT 方案
| 对比维度 | 服务端 Session 方案 | 自包含签名 JWT 方案 |
|---|---|---|
| 主要状态位置 | 服务端 | JWT 中携带可验证的声明 |
| 客户端凭证 | 通常为 Session ID | JWT |
| 验证方式 | 查询服务端会话状态 | 验证签名和相关声明 |
| 分布式部署 | 通常需要共享会话存储 | 可由多个服务独立验签 |
| 主动撤销 | 删除会话记录即可 | 通常需要额外撤销机制 |
| 典型场景 | Web 后台、需要集中会话管理的系统 | 多服务令牌验证、分布式 API |
这里比较的是两种具体实现方案。使用 Token 并不意味着服务端一定无状态。
4.3 Cookie、localStorage、sessionStorage
| 对比维度 | Cookie | localStorage | sessionStorage |
|---|---|---|---|
| 自动随请求发送 | 满足规则时会 | 不会 | 不会 |
| JavaScript 读取 | 可以通过 HttpOnly 禁止 | 可以 | 可以 |
| 页面刷新后 | 通常保留 | 保留 | 保留 |
| 浏览器关闭后 | 取决于 Cookie 类型和浏览器行为 | 通常保留 | 对应标签页会话结束后清除 |
| 主要用途 | 会话凭证、浏览器状态 | 本地持久化数据 | 标签页级临时数据 |
对于敏感认证凭证,优先考虑受保护的 HttpOnly Cookie 或服务端保存方案。
4.4 Access Token、Refresh Token、ID Token
| 对比维度 | Access Token | Refresh Token | ID Token |
|---|---|---|---|
| 主要用途 | 访问受保护资源 | 获取新的 Access Token | 表达身份认证结果 |
| 接收方 | 资源服务器 | 授权服务器 | OIDC 客户端 |
| 有效期 | 通常较短 | 通常相对较长 | 按身份提供方策略设置 |
| 格式 | 可以是 JWT 或不透明字符串 | 可以是随机字符串等格式 | OIDC 中通常为 JWT |
| 使用场景 | API 访问 | 令牌续期 | 第三方登录、身份认证 |
ID Token 主要面向客户端证明认证结果,不能直接作为通用的 API Access Token 使用。
4.5 身份认证、会话管理、权限授权
| 对比维度 | 身份认证 | 会话管理 | 权限授权 |
|---|---|---|---|
| 核心问题 | 用户是谁 | 如何维持登录状态 | 用户能做什么 |
| 典型机制 | 密码验证、多因素认证、OIDC | Session ID、Cookie、令牌生命周期管理 | RBAC、资源级权限检查 |
| 执行阶段 | 登录或重新认证时 | 登录后持续维护和验证 | 访问受保护资源时 |
| 主要目标 | 建立可信身份 | 安全维持和终止登录状态 | 防止越权访问 |
三者通常共同组成完整的 Web 登录与访问控制体系。
5. 总结
Web 认证与会话管理主要解决用户身份确认,以及 HTTP 多次请求之间的登录状态维持问题。身份认证通过以后,系统会建立登录状态,并通过凭证识别后续请求。常见的服务端 Session 方案会保存会话信息,让客户端携带 Session ID 进行查询;基于签名 JWT 的方案则可以通过验证令牌的签名和声明,减少对集中会话存储的依赖。这里 Session 是会话管理概念,Token 是凭证概念,JWT 是 Token 的一种格式,Cookie 可以负责传递凭证。实际项目中还要做好权限校验、凭证过期与撤销,以及 CSRF、XSS 和会话劫持防护。方案选择主要取决于系统架构、状态共享需求,以及是否需要实时管理和撤销登录状态。