认证与授权常见面试题总结:Session、JWT、OAuth 2.0 与权限模型

这部分内容摘自 JavaGuide 下面几篇文章的重点:
认证与会话
⭐️认证和授权有什么区别?
- 认证(Authentication):确认访问者是谁,例如使用密码、短信验证码、Passkey 或客户端证书验证身份。
- 授权(Authorization):确认当前身份可以访问哪些资源、执行哪些操作。
认证通常发生在授权之前,但“已经登录”不代表“拥有所有权限”。服务端收到请求后,既要确认身份,还要结合操作、资源归属、租户和数据范围做授权判断。
常见的认证因素有哪些?什么是 MFA?
认证因素通常分为三类:
- 你知道的信息:密码、PIN。
- 你拥有的东西:手机、硬件安全密钥、一次性验证码设备。
- 你的生物特征:指纹、人脸等。
MFA(Multi-Factor Authentication,多因素认证)要求使用至少两种不同类型的因素。密码加安全问题仍然属于同一类“知道的信息”,不能算真正的双因素认证。
短信验证码使用方便,但会受到 SIM 卡换卡、短信劫持和钓鱼影响。对管理员、支付、改密等高风险操作,更适合使用 TOTP、Passkey 或硬件安全密钥,并结合风险识别和重新认证。
Cookie 和 Session 有什么区别?
Cookie 是浏览器保存并按规则自动随请求发送的数据;Session 是服务端维护的一段会话状态。两者经常组合使用:服务端创建 Session,把没有业务含义的随机 SessionId 放进 Cookie,后续再通过它查找会话。
| 对比项 | Cookie | Session |
|---|---|---|
| 保存位置 | 客户端 | 服务端或共享会话存储 |
| 常见内容 | SessionId、偏好设置 | 用户 ID、登录状态、会话属性 |
| 主要风险 | 窃取、篡改、作用域配置不当 | 会话固定、劫持、过期和存储压力 |
“Session 保存在服务端”不等于绝对安全。攻击者拿到有效 SessionId 后,仍可能直接冒充用户。
⭐️Session-Cookie 认证流程是什么?
- 用户提交登录凭据,服务端完成身份验证。
- 服务端创建 Session,并生成随机、不可预测的
SessionId。 - 服务端通过
Set-Cookie把SessionId交给浏览器。 - 浏览器在符合 Cookie 作用域的请求中自动携带它。
- 服务端查找 Session,恢复用户身份,再执行权限校验。

会话 Cookie 一般要配置 HttpOnly、Secure、合适的 SameSite、Path 和过期时间。登录成功、权限提升或敏感操作重新认证后应更换 Session ID,避免会话固定攻击;退出登录时要让服务端会话失效。
分布式环境下如何管理 Session?
常见方案有三种:
- 会话粘滞:同一用户尽量路由到固定实例。实现简单,但实例故障会丢失本地会话,扩缩容也更麻烦。
- 节点间复制:实例相互同步 Session。节点越多,同步和一致性成本越高。
- 集中存储:把 Session 放入 Redis 等共享存储,应用实例保持无状态。这是常见做法,但需要处理共享存储的高可用、过期和容量。
Spring 项目可以使用 Spring Session 接入 Redis 等外部存储。无论采用哪种方案,Session 的有效期、主动注销、踢下线和权限变更都要有统一管理机制。
Session 和 Token 认证如何选择?
Session 方案由服务端保存会话状态,撤销、踢下线和权限即时变更更直接;代价是服务端需要存储和查询会话。
Token 是客户端携带的访问凭据。Token 可以是随机字符串,也可以是 JWT。随机 Token 通常仍要查询服务端状态;自包含 JWT 可以减少会话查询,但会增加撤销、权限变更和密钥管理难度。
选择时应看应用形态和安全要求:传统 Web 应用常用 Cookie + Session 或 BFF;开放 API、移动端和跨服务调用常用 Bearer Token。两种方案都必须使用 HTTPS,并处理凭据泄露、过期和撤销。
浏览器中应该把 Token 存在哪里?
不要把 localStorage 或 sessionStorage 当成认证凭据的默认存储位置。同源页面中的 JavaScript 可以读取 Web Storage,一处 XSS 漏洞就可能泄露 Access Token 和 Refresh Token。
浏览器应用常见选择是:
- 使用 BFF,由后端保存 OAuth Token,浏览器只持有设置了
HttpOnly、Secure和合适SameSite的会话 Cookie。 - 直接使用 Cookie 保存短期凭据,同时做好 CSRF Token、
Origin/Referer校验等 CSRF 防护。 - 必须由前端持有 Token 时,尽量只放在内存,缩短有效期,并把 Refresh Token 保护放在更高优先级。
凭据放在 Cookie 中要重点防 CSRF;交给 JavaScript 管理则要重点防 XSS。存储方式改变的是主要攻击面,不会让其他风险自动消失。
JWT
⭐️什么是 JWT?它由哪些部分组成?
JWT(JSON Web Token)是一种紧凑的令牌格式,常见的 JWS 形式由三部分组成:
Header.Payload.Signature- Header:令牌类型和签名算法等元数据。
- Payload:Claims,例如
iss、sub、aud、exp、nbf和jti。 - Signature:对 Header 和 Payload 做完整性保护,服务端据此判断内容是否被修改。

Header 和 Payload 通常只是 Base64Url 编码,任何拿到令牌的人都能解码查看。因此,Payload 不应存密码、银行卡号等秘密信息。
JWT 有签名,为什么还需要 HTTPS?
签名主要防止内容被未授权修改,不提供传输保密性,也不能阻止攻击者重放一个被盗但仍然有效的 JWT。
HTTPS 可以保护令牌在传输过程中不被窃听和篡改。服务端还要固定允许的算法集合,校验签名以及 iss、aud、exp、nbf 等声明,并区分 ID Token、Access Token 等不同用途,不能只做一次“能解码”检查。
⭐️JWT 被盗后如何降低风险?
- Access Token 设置较短有效期和尽量小的权限范围。
- Refresh Token 单独保护,绑定客户端、授权范围和资源服务器。
- 使用 Refresh Token 轮换,发现旧令牌重放时撤销整条授权链。
- 改密、退出和账号风险事件发生时,撤销 Refresh Token 或登录会话。
- 对高风险接口增加重新认证、MFA、设备约束或发送者约束令牌。
仅缩短 JWT 有效期会缩小风险窗口,但不会让已经泄露的 Token 立即失效。
使用 JWT 后如何实现退出登录和强制下线?
常见做法有:
- 客户端删除本地 Token,只能处理当前客户端主动退出。
- Access Token 短期有效,服务端撤销 Refresh Token,让旧 Access Token 在较短时间后自然失效。
- 维护 Token 黑名单、用户会话版本号或“最早有效时间”,请求时增加一次状态检查。
- 使用网关或认证中心统一维护会话,向各服务传播撤销事件。
如果系统要求改密后立即让所有设备下线,就不能只依赖完全无状态、有效期很长的 JWT。撤销能力意味着服务端通常仍要保存一部分状态。
Access Token 和 Refresh Token 有什么区别?
| 对比项 | Access Token | Refresh Token |
|---|---|---|
| 用途 | 访问资源服务器 | 向授权服务器换取新 Access Token |
| 有效期 | 通常较短 | 通常较长 |
| 暴露范围 | 会发送给资源服务器 | 只发送给授权服务器 |
| 泄露后果 | 在有效期和权限范围内调用 API | 可以持续换取新 Access Token,风险更高 |
Refresh Token 不一定是 JWT。公共客户端使用 Refresh Token 时,应采用轮换或发送者约束方案检测重放,并设置闲置过期和安全事件撤销。
OAuth 2.0、OIDC 与 SSO
⭐️OAuth 2.0 是什么?有哪些角色?
OAuth 2.0 用于让客户端在资源所有者同意后,获得对受保护资源的有限访问权限。它解决的是委托授权问题。
协议中常见的四个角色是:
- Resource Owner:资源所有者,通常是用户。
- Client:希望访问资源的应用。
- Authorization Server:完成授权并签发 Token。
- Resource Server:保存受保护资源并验证 Access Token。

“使用某平台账号登录”如果只拿 OAuth Access Token 调用用户信息接口,容易把授权和身份认证混在一起。标准的身份层应使用 OIDC,并正确校验 ID Token。
⭐️授权码模式加 PKCE 的流程是什么?
- 客户端生成随机
code_verifier,再计算code_challenge。 - 浏览器跳转到授权服务器,请求中带上
state、code_challenge和回调地址。 - 用户完成认证和授权后,授权服务器把一次性授权码返回客户端。
- 客户端后端或本地应用携带授权码和
code_verifier请求 Token Endpoint。 - 授权服务器校验 PKCE,签发 Access Token,按策略决定是否签发 Refresh Token。
PKCE 让截获授权码的攻击者因为缺少 code_verifier 而无法兑换 Token。state 用于绑定授权请求与回调并防范 CSRF;回调地址必须精确匹配预先登记的地址。当前 OAuth 2.0 安全最佳实践建议授权码模式使用 PKCE,不再把它只看作移动端补丁。
OAuth 2.0 和 OIDC 有什么区别?
- OAuth 2.0:解决“客户端能访问哪些资源”的授权问题,核心凭据是 Access Token。
- OIDC(OpenID Connect):在 OAuth 2.0 之上增加身份层,让客户端验证最终用户身份,核心新增凭据是 ID Token。
Access Token 的受众是资源服务器,不应被客户端当作用户身份证明。客户端使用 OIDC 时,需要校验 ID Token 的签名、签发方、受众、过期时间和 nonce 等字段。
什么是 SSO?如何实现跨系统单点登录?
SSO(Single Sign-On,单点登录)让用户在统一身份提供方完成一次登录后,可以访问多个相互信任的业务系统。
常见实现是让各业务系统分别维护自己的 host-only 会话:未登录时跳转到统一认证中心,认证中心利用自身 Cookie 判断登录状态,再通过一次性、短期授权码把认证结果返回业务系统,业务系统后端换取身份信息并建立本地会话。

不要为了跨子域登录而直接把高权限认证 Cookie 的 Domain 扩大到整个父域。任一薄弱或被接管的子域都可能扩大凭据泄露风险。SSO 还要处理统一退出、子系统会话清理、授权撤销和认证中心高可用。
权限控制
⭐️RBAC、ABAC 和 ACL 有什么区别?
| 模型 | 授权依据 | 适合场景 | 主要问题 |
|---|---|---|---|
| RBAC | 用户所属角色 | 企业后台、功能权限 | 角色可能越建越多 |
| ABAC | 用户、资源、环境等属性 | 多租户、动态策略、细粒度权限 | 规则理解和调试更复杂 |
| ACL | 资源对应的主体权限列表 | 文档分享、文件权限 | 大量资源下维护成本高 |

实际系统经常组合使用:RBAC 判断用户能否使用某项功能,ABAC 或数据范围规则继续判断他能操作哪个部门、租户或具体对象。
为什么前端隐藏按钮不能代替后端授权?
前端代码和请求参数都由客户端控制。攻击者可以手动请求接口、修改资源 ID,或者绕过页面直接调用后端。
前端隐藏菜单和按钮只用于改善交互;后端必须默认拒绝未明确授权的请求,并在每次访问时校验当前主体对目标操作和目标资源的权限。客户端传入的用户 ID、角色或租户 ID 不能直接作为可信授权依据。
⭐️只校验角色为什么还会出现越权?
角色校验通常只能回答“能否使用这个接口”,不能回答“能否操作这条数据”。例如,普通用户都能调用订单详情接口,但用户 A 不能通过修改 orderId 查看用户 B 的订单。
防止对象级越权需要把主体和资源一起放进授权条件:
SELECT id, status, amount
FROM orders
WHERE id = ?
AND owner_id = ?;后台管理场景还可能需要校验组织、区域和数据范围。对不存在和无权访问的资源,应避免返回能帮助攻击者枚举资源的差异化细节。
多租户系统如何避免跨租户访问?
- 租户身份应来自服务端验证过的会话、Token 或可信网关上下文,不能直接相信请求体里的
tenantId。 - 查询、更新和删除都带上租户条件,唯一约束和缓存 Key 也包含租户维度。
- 数据访问层统一注入租户条件,降低业务代码漏写的概率,但仍要测试批量接口、导出任务和后台任务。
- 管理员跨租户操作使用独立权限和审计流程,避免用普通用户链路“临时放开”。
- 高隔离要求可以采用独立 Schema、数据库或实例,并配套迁移和运维方案。
仅在网关校验一次租户还不够。异步消息、定时任务、缓存和搜索索引同样需要携带并校验租户上下文。
权限变更后,如何让缓存中的旧权限及时失效?
常见方案是给用户或租户维护权限版本号:登录态记录版本,请求时与当前版本比较;角色或权限变化后递增版本,使旧登录态失效。也可以删除权限缓存并通过消息通知各节点刷新。
权限缓存应设置过期时间,并保证撤权失败可重试。涉及资金、审批和管理员操作时,可以在执行前查询权威权限服务,不依赖长时间缓存。还要记录谁在什么时间给谁授予或撤销了什么权限,便于审计和追踪。
参考资料
- OWASP Authentication Cheat Sheet
- OWASP Authorization Cheat Sheet
- OWASP Session Management Cheat Sheet
- RFC 9700:Best Current Practice for OAuth 2.0 Security
- OpenID Connect Core 1.0
写在最后
感谢你能看到这里,也希望这篇文章对你有点用。
JavaGuide 坚持更新 6 年多,近 6000 次提交、600+ 位贡献者一起打磨。如果这些内容对你有帮助,非常欢迎点个免费的 Star 支持下(完全自愿,觉得有收获再点就好):GitHub | Gitee。
如果你想要付费支持/面试辅导(比如简历优化、一对一提问、高频考点突击资料等)的话,欢迎了解我的知识星球。已经坚持维护六年,内容持续更新,虽白菜价(0.4元/天)但质量很高,主打一个良心!

