认证与授权
了解身份验证(authentication)和授权(authorization)之间的区别,以及它们如何在现代应用程序中保护访问权限。
身份验证与授权
身份验证用于确认身份。授权用于确定权限。它们解决的是不同的问题,并且按顺序发生。
通过凭据验证身份
身份已验证 → 权限已检查
- 身份验证(AuthN)回答:“你是谁?”
- 授权(AuthZ)回答:“你被允许做什么?”
- 你可以通过身份验证,但仍然会被授权机制阻止。
详情
身份验证用于建立身份。系统会验证用户是否就是其声称的那个人——通常通过密码、令牌或外部身份提供方等凭据来完成。
授权发生在身份确认之后。系统会评估该身份是否有权限执行某个特定操作,或访问某个特定资源。
这两个概念必须保持分离。身份验证并不自动意味着拥有访问权限。已登录的用户仍然可能没有权限查看某些数据或执行管理操作。
概念上: 用户 → 登录 → 身份已验证 → 权限检查 → 资源访问。
身份验证先发生。授权随后发生——通常在每个请求中都会进行。
身份验证 — 身份如何被确认
身份验证确认一个被声明的身份是否由有效凭据支持。
密码凭据
哈希密码
服务器验证
- 凭据可以是密码、OAuth 登录、API key,或多因素证明。
- 服务器会将这些凭据与存储的数据或受信任的提供方进行验证。
- 如果验证失败,请求会在访问任何资源之前被拒绝。
详情
当用户或系统声明一个身份并提供凭据作为证明时,身份验证就开始了。
用户名 + 密码 是传统方法。服务器会将提交的凭据与存储的账户数据进行比对。
OAuth 登录 将身份验证委托给受信任的外部提供方(例如 Google 或 GitHub),由其向应用返回已验证的身份。
API Keys 通常用于服务器到服务器的身份验证,用于识别应用程序,而不是人类用户。
多因素身份验证(MFA) 通过要求第二个证明(例如一次性验证码或硬件令牌)来增强身份验证。
概念流程: 登录 → 提交凭据 → 服务器验证 → 身份确认。
没有有效身份时,请求就会在这里停止。
基于会话的身份验证
会话存储
会话创建:登录请求发送到服务器,会话被保存,然后 cookie 发送到浏览器。
- 登录后,服务器会创建一个与已认证用户关联的会话。
- session ID 会存储在客户端的 cookie 中。
- 服务器保存会话状态,并在每次请求时查找它。
详情
在传统的 Web 应用中,身份验证是通过服务器端会话来处理的。
当用户成功登录后,服务器会生成一个包含身份信息的会话对象。这个会话存储在服务器上——通常是在内存、数据库或分布式缓存中。
服务器会将 session ID 返回给客户端,通常存储在 cookie 中。在后续请求中,浏览器会自动携带该 cookie。
服务器读取 session ID,获取对应的会话数据,并确定用户的身份。
核心思想很简单:服务器存储会话状态,客户端只保存对它的引用。
基于令牌的身份验证
| 步骤 | 操作 |
|---|---|
| 1 | 登录 → 服务器签发已签名的 JWT |
| 2 | 客户端随请求发送令牌 |
| 3 | 服务器验证令牌签名 |
| 4 | 请求已处理(无需会话查找) |
- 在验证凭据后,服务器会发放一个令牌(例如 JWT)。
- 客户端会在每个请求中发送该令牌,通常放在 Authorization header 中。
- 服务器在不存储每个用户的会话状态的情况下验证令牌。
详情
在现代 API 和分布式系统中,身份验证通常是无状态的。
登录成功后,服务器会生成一个包含身份信息的签名令牌。该令牌会返回给客户端。
对于之后的每个请求,客户端都会包含该令牌——通常作为 Authorization header 中的 Bearer token。
服务器不会在服务端存储中查找会话数据,而是直接验证令牌的签名,并从中提取用户身份。
与基于会话的身份验证的关键区别在于,服务器不会为每个用户维护会话状态。身份验证是通过验证令牌本身来完成的。
这种模型简化了水平扩展,因为任何服务器实例都可以在不依赖共享会话存储的情况下验证令牌。
什么是 JWT?
- JWT 包含三部分:Header、Payload 和 Signature。
- 签名可确保令牌未被篡改。
- JWT 默认是签名的,不是加密的。
详情
JWT 是一个结构化字符串,由三个用点号分隔的 Base64 编码部分组成:
Header → 关于令牌和签名算法的元数据
Payload → 声明(例如用户 ID 或角色)
Signature → 令牌未被修改的加密证明
当服务器签发 JWT 时,它会使用密钥或私钥对令牌进行签名。之后当令牌被提交时,服务器会验证签名,以确保 payload 没有被修改。
重要说明:JWT 默认不是加密的。任何持有该令牌的人都可以解码 payload。签名只能保证完整性,不能保证机密性。
JWT 很有用,因为它允许身份信息以可验证的方式随请求一起传递,而不需要服务器端会话存储。
授权 — 强制执行权限
- 在身份验证完成后,授权会检查权限。
- RBAC 根据角色分配权限。
- 每次受保护的请求都会评估授权。
详情
一旦用户的身份被确认,系统就必须决定他们被允许执行哪些操作。
授权用于强制执行访问控制规则。即使用户已经通过身份验证,他们也可能没有权限访问某些资源或执行某些操作。
一种常见模型是 Role-Based Access Control (RBAC),其中用户会被分配诸如“admin”、“editor”或“viewer”之类的角色,并且每个角色都有预定义的权限。
另一种模型是 Attribute-Based Access Control (ABAC),其中决策基于用户属性、资源属性或请求上下文等属性。
身份验证通常在每个会话或令牌签发时发生一次。不过,授权会针对每个受保护的请求进行评估,以确保访问规则始终得到一致执行。
请求流程中认证发生的位置
- 请求到达服务器并经过认证中间件。
- 如果凭据无效,服务器返回 401 Unauthorized。
- 如果身份有效但权限不足,服务器返回 403 Forbidden。
详情
当请求到达服务器时,它不会立即执行应用逻辑。它首先会经过一个认证层,通常在 Express、Django 或 FastAPI 等框架中通过中间件实现。
这个中间件会检查诸如会话 cookie 或 authorization token 之类的凭据。如果凭据缺失或无效,服务器会返回 401 Unauthorized 响应并拒绝该请求。
如果身份验证成功,系统随后会评估权限。当用户没有访问所请求资源的权限时,服务器会返回 403 Forbidden。
只有在认证和授权检查都通过之后,请求才会到达处理程序并执行业务逻辑,从而确保敏感操作受到保护,避免未授权访问。
安全注意事项
- 密码在存储之前必须进行哈希处理——绝不能以明文存储。
- 身份验证流量必须使用 HTTPS,以防止被拦截。
- 令牌应设置过期时间,并且可以使用刷新令牌进行续期。
详情
即使身份验证流程实现正确,如果缺少核心保护措施,系统仍然可能不安全。
密码在存入数据库之前必须进行哈希处理。哈希可以确保即使数据库被攻破,原始密码也不会泄露。
所有身份验证流量都必须通过 HTTPS 传输。如果没有传输加密,凭据和令牌可能会被攻击者拦截。
访问令牌应设置过期时间。短生命周期的令牌可以在令牌被盗时减少损失。许多系统会使用刷新令牌来获取新的访问令牌,而无需用户反复登录。
安全不仅仅是验证身份——还包括保护用于验证身份的机制。
问题部分
1 / 5