什么是身份验证?登录、会话与 OAuth 详解
身份验证是应用确认用户身份的方式,通常通过检查用户所知道的内容(如密码)、所拥有的东西(如发送到手机或邮箱的验证码),或来自另一个可信服务的身份(例如“使用 Google 登录”)来完成。用户通过身份验证后,应用会借助会话或令牌记住他们,这样他们就无需在每个页面都重新登录。至于已识别的用户被允许做什么,则是另一个称为授权的步骤。
用 AI 构建应用时为什么它很重要
添加登录功能是人们向 AI 构建工具提出的最常见的需求之一,同时也是最容易在细节上出错的功能之一。登录页面很容易生成,真正困难的是页面背后的一切:
- 密码是否被安全地存储?
- 每个私密页面和每个 API 端点是否真正检查了请求者的身份?
- 登录的客户能否通过修改 URL 中的数字,看到其他客户的数据?
- 用户忘记密码时会发生什么?
一个应用看起来可能非常安全,却在上述每一项上都存在问题。理解这些组成部分,能让你提出正确的问题,并测试正确的内容。
一个日常类比
想象一下在酒店办理入住。
在前台,你需要出示证件。这就是身份验证:证明你是谁。随后,接待人员会给你一张房卡。这张卡就是你的会话:在整个住宿期间,你无需再次出示证件,只需刷卡即可。
房卡可以打开你的房间、健身房以及通往你所在楼层的电梯,但无法打开其他客人的房间或员工办公室。这就是授权:你的身份被允许访问的范围。如果你丢了房卡,酒店可以在前台将其停用(撤销会话)。退房后,房卡也会失效(登出或过期)。
“使用 Google 登录”就像酒店接受一位可信合作伙伴的信函,信中写明“这位是谁”,而不是自己核对你的证件。
主要的登录方式
| 方式 | 工作原理 | 优点 | 缺点 |
|---|---|---|---|
| 邮箱 + 密码 | 用户设置一个密码;应用存储其哈希值 | 熟悉,不依赖外部服务 | 必须安全地存储哈希值并处理重置 |
| 魔法链接 / 一次性验证码 | 应用通过邮件发送链接或验证码,帮用户登录 | 无需担心密码泄露或遗忘 | 依赖邮件送达;登录速度较慢 |
| 社交登录(OAuth / OpenID Connect) | 用户使用 Google、Apple、GitHub 等账户登录 | 对用户来说很快;你无需存储密码 | 需要在每个服务商处进行设置;没有这些账户的用户无法使用 |
| 托管式身份验证服务 | Clerk、Auth0 或 Supabase Auth 等服务负责注册、登录和重置 | 你需要做的安全工作更少 | 规模变大后有月费;多了一项依赖 |
| 多因素认证(MFA / 2FA) | 在第一步之后增加第二重验证,例如身份验证器应用中的验证码 | 账户更难被入侵 | 操作稍显繁琐 |
密码应该如何存储
安全的应用从不存储你的真实密码。它存储的是哈希值:一种单向函数的输出结果,能将密码转换为固定长度的字符串。登录时,应用对你输入的内容计算哈希,并将结果与已存储的哈希值进行比对。
有两个细节让这一做法变得安全:
- 盐值(Salt)——在哈希之前为每个密码添加的随机值,这样即使两个人使用相同的密码,得到的哈希也不同,预先计算好的查找表也就失去了作用。
- 专为密码设计的慢速算法——例如 Argon2、bcrypt 或 scrypt。通用哈希算法如 MD5 或 SHA-256 本身速度太快,攻击者可以尝试数十亿次猜测。
哈希与加密并不相同。加密后的数据可以用密钥解密;而密码哈希从设计上就不可逆。
会话与令牌
登录之后,应用需要在每次请求时识别你。常见的做法有两种。
| 会话(Cookie) | 令牌(如 JWT) | |
|---|---|---|
| 浏览器保存的内容 | Cookie 中的随机会话 ID | 包含用户信息和过期时间的已签名令牌 |
| 登录状态存放在哪里 | 服务器上,位于数据库或存储中 | 存在于令牌本身中 |
| 在所有设备上登出某人 | 容易:在服务器上删除会话 | 较难:除非维护一个黑名单,否则令牌在过期前一直有效 |
| 典型用途 | 传统网站应用 | API、移动应用、服务之间的通信 |
对于 Cookie,有三个设置尤为重要:HttpOnly(页面上的 JavaScript 无法读取该 Cookie)、Secure(仅通过 HTTPS 发送)和 SameSite(限制来自其他网站的请求携带该 Cookie)。将令牌存储在浏览器的 localStorage 中很常见,但这会使其暴露给页面上运行的任何脚本。
OAuth 与“使用 Google 登录”
OAuth 2.0 是一种委托授权标准:它让应用在无需知道你 Google 密码的情况下,获得你在另一项服务上账户的有限访问权限,例如读取你的 Google 日历。你会被引导到 Google,批准特定的权限(称为作用域(scope)),Google 则只为应用颁发针对这些权限的令牌。
OAuth 本身的设计目的是授予访问权限,而不是说明你是谁。OpenID Connect(OIDC) 是建立在 OAuth 2.0 之上的一层,增加了身份信息,“使用 Google 登录”或“使用 Apple 登录”正是基于它。设置时,你需要在服务商处注册应用,并获得客户端 ID(client ID)和客户端密钥(client secret);密钥必须保留在你的服务器上。
实例演示:客户门户的登录功能
假设你要构建一个门户,设计公司的客户可以在其中查看自己的项目和发票。
- **身份验证:**客户使用邮箱和魔法链接登录,因此无需管理密码。公司员工使用 Google Workspace 账户登录。
- **角色:**每位用户都有一个角色——
client(客户)或staff(员工)。 - 授权规则:
| 操作 | 客户 | 员工 |
|---|---|---|
| 查看自己公司的项目 | 是 | 是 |
| 查看其他公司的项目 | 否 | 是 |
| 向项目上传文件 | 仅限自己的项目 | 是 |
| 将发票标记为已支付 | 否 | 是 |
- **在哪里执行:**在服务器上,针对每一个请求执行。服务器先查找已登录的用户,然后只返回
project.company_id与该用户所属公司匹配的项目。仅仅隐藏“标记为已支付”按钮是不够的——端点本身必须拒绝这类请求。
常见术语解释
| 术语 | 含义 |
|---|---|
| 身份验证(AuthN,Authentication) | 确认某人的身份。 |
| 授权(AuthZ,Authorization) | 决定其可以做什么。 |
| 会话(Session) | 应用在多次请求之间记住你已登录的状态。 |
| Cookie | 浏览器在每次请求时随请求一同发回网站的一小段数据。 |
| JWT | JSON Web Token:一种已签名的紧凑令牌,携带用户 ID、过期时间等声明信息。 |
| 角色 / 权限(Role / permission) | 如 admin(管理员)或 member(成员)等决定访问范围的标签。 |
| MFA / 2FA | 要求第二重凭证,例如来自身份验证器应用的验证码。 |
| SSO | 单点登录:一次登录即可访问多个应用(通常是企业账户)。 |
| 401 与 403 | “你是谁?”(未通过身份验证)与“你不能这样做”(未获授权)。 |
常见错误与误解
- 只在页面中检查权限。 如果浏览器隐藏了某个按钮,但 API 没有进行检查,任何人都可以直接调用该 API。
- 信任 URL 中的 ID。
/invoices/1042必须检查发票 1042 是否属于当前登录的用户。 - 自行编写加密逻辑。 请使用广为人知的库或服务商;不要让 AI 发明自己的哈希方案。
- 密码重置机制薄弱。 重置链接应为一次性使用,快速过期,并且不应泄露某个邮箱是否注册过账户。
- 混淆你的登录与构建工具的登录。 应用的用户与你在所用构建工具上的账户是相互独立的。
- 登录没有频率限制。 缺少限制时,攻击者可以无限次地尝试密码。
向你的 AI 构建工具提出的要求
- “使用 [某个广为人知的库或服务商] 添加注册和登录功能。不要编写自定义的密码哈希逻辑。”
- “使用 bcrypt 或 Argon2 对密码进行哈希存储。”
- “会话使用带 HttpOnly 和 Secure 属性的 Cookie。”
- “添加角色:admin 和 member。列出每个端点,以及哪些角色可以调用它。”
- “在服务器端强制执行:用户只能读取和编辑自己的记录。然后向我展示你是如何检查的。”
- “添加密码重置功能,使用一次性链接,并在一小时后过期。”
- “对登录尝试进行频率限制。”
之后,请自行测试:创建两个账户,在登录其中一个账户的状态下,尝试访问另一个账户的数据。想深入了解的话,可以阅读我们的添加登录功能指南和AI 构建应用安全清单。
Mythex 中的身份验证
Mythex 不为你应用的用户提供内置的身份验证产品。你需要自行选择方案:将邮箱和密码存储在项目的数据库中,或使用托管服务商的 SDK,然后请智能体为你添加。服务商的密钥应放入项目机密,而不要放在聊天中。这与你如何登录 Mythex 本身是两回事。文档中有一份关于为应用添加登录功能的配方,附带可修改的入门提示词;什么是 API 则解释了这些服务端检查位于何处。
常见问题
身份验证和授权有什么区别?
身份验证检查你是谁,例如通过验证你的密码。授权则在确认你的身份之后,决定你被允许做什么,例如你能否访问管理员页面,或能否修改别人的预订。应用两者都需要。
什么是 OAuth?
OAuth 2.0 是一种标准,它让应用在无需获取你密码的情况下,获得你在另一项服务上账户的有限访问权限。“使用 Google 登录”则使用 OpenID Connect,这是建立在 OAuth 2.0 之上的身份层,因此应用可以从 Google 得知你是谁。
我的应用应该存储密码吗?
绝不能以明文形式存储。如果你使用邮箱和密码登录,密码必须以加盐哈希的形式存储,并使用专为密码设计的慢速算法,例如 Argon2 或 bcrypt。许多应用通过使用托管式身份验证服务、社交登录或邮件魔法链接来避免这个问题。
我的应用应该使用会话还是令牌?
两者都可行。会话将登录状态保存在服务器上,并通过 Cookie 向浏览器提供一个随机 ID,因此很容易撤销。像 JWT 这样的令牌本身携带已签名的信息,适合 API 和移动客户端,但在过期前较难取消。对于典型的网站应用,基于 Cookie 的会话是一个可靠的默认选择。