⚠️ Alpha内测版本警告:此为早期内部构建版本,尚不完整且可能存在错误,欢迎大家提Issue反馈问题或建议
Skip to content

8.2 认证方式与方案选择

本节目标:理解主流认证方式的原理和适用场景,选择适合项目的认证库,让 AI 帮你完成配置。


登录之后,服务器怎么记住我?

小明在 8.0 跑通了用户系统——注册、登录、受保护页面都能用。但他好奇一个问题:每次访问 /dashboard,服务器怎么知道"这个请求来自小明,而不是别人"?难道每次都要重新输密码?

这就涉及到会话管理——用户登录一次之后,后续请求怎么证明"我还是我"。你每次打开一个新页面、点一个按钮、提交一个表单,浏览器都会向服务器发一个新的 HTTP 请求。HTTP 协议本身是"无状态"的——服务器处理完一个请求就忘了,下一个请求来了它不知道这是同一个人。所以需要一种机制,让服务器在多次请求之间"记住"你是谁。业界有两种主流方案。

第一种是 Session(会话)。 你去图书馆借书,第一次去,前台给你办了一张借书卡,卡上只有一个编号。图书馆的电脑里记录了这个编号对应的姓名、借书记录等信息。以后每次去,你出示借书卡,前台查编号就知道你是谁。Session 的工作方式一样:登录成功后,服务器在数据库里创建一条 session 记录(就像图书馆电脑里的那条记录),把 session ID 通过 Cookie 发给浏览器(就像那张借书卡)。之后浏览器每次请求都会自动带上这个 Cookie——你不需要手动做任何事,浏览器帮你处理了。就像你进了一家商场,门口给你贴了个会员贴纸,之后你走到每一层每一家店,店员都能看到这个贴纸——你不需要每次都重新出示会员卡。服务器收到请求后,根据 Cookie 里的 session ID 去数据库查到对应的用户信息,就知道"这是小明"。优点是服务器完全掌控——想让某个用户立刻下线,删掉数据库里的 session 记录就行,下次请求来了查不到记录,用户就被踢出去了。缺点是每次请求都要查数据库,如果你的应用部署在多台服务器上,还需要让它们共享 session 存储(否则用户在 A 服务器登录,请求被分配到 B 服务器时就找不到 session 了)。

第二种是 Token(令牌,通常是 JWT)。 换个场景:你去游乐园,入口给你盖了个手背章,章上用隐形墨水写了你的姓名和票种(普通票/VIP)。每个项目入口的工作人员用紫外灯一照就能看到信息,不需要打电话回入口确认。Token 的工作方式类似:登录成功后,服务器把用户信息(用户名、角色、过期时间等)加密签名生成一个 token 字符串,发给浏览器。之后浏览器每次请求带上这个 token,服务器收到后解密验证签名,确认没被篡改,就直接从 token 里读取用户信息——不需要查数据库。优点是不需要服务端存储,天然支持多服务器(因为信息都在 token 里,任何服务器都能验证)。缺点是签发后无法撤销——token 一旦发出去,在过期之前一直有效,就像游乐园的手背章,盖上去就擦不掉,工作人员没法远程让它失效,只能等它自然褪色。即使你想让某个用户立刻下线也做不到(除非维护一个"黑名单",但那又回到了需要服务端存储的老路)。

对于大多数 Web 应用,你不需要做这个选择——认证库会帮你处理。Better Auth 默认使用数据库 Session(兼具安全性和可控性),你不需要手动管理 Cookie 或 Token。了解这两种方式的意义在于:当你看到 AI 生成的代码里出现 sessiontokenJWTCookie 这些词时,你知道它们在说什么,不会一头雾水。

Session 流程
1用户登录
2服务器创建 Session,存入数据库
3返回 Session ID (Cookie)
4后续请求带 Cookie
5服务器查数据库验证
Token 流程
1用户登录
2服务器生成 JWT Token
3返回 Token
4后续请求带 Token (Header)
5服务器验证签名(不查数据库)
SessionToken
存储位置服务端(数据库)客户端(localStorage / Cookie)
撤销能力可随时撤销无法主动撤销(等过期)
数据库依赖每次请求查数据库无需数据库查询

不只是密码:现代认证方式

密码登录是最基础的方式,但不是唯一的。小明的朋友们试用"个人豆瓣"时,第一个反馈就是:"又要注册?我已经记不住多少个密码了。能不能用 GitHub 账号直接登录?"这个需求引出了现代认证的几种主流方式。

OAuth 2.0 就是你在各种网站上看到的"用 Google/GitHub 登录"按钮背后的技术。点一下,跳到 Google 的页面确认授权,然后自动回到原网站,已经登录了。原理就像酒店入住:你不需要向酒店证明你的身份证是真的——你出示身份证,酒店去公安系统验证。OAuth 里,Google/GitHub 就是那个"公安系统",你的网站是"酒店"。用户不把密码告诉你的网站,而是让 Google 替他担保——"这个人确实是 xxx@gmail.com 的主人"。对用户来说,不用记新密码,一键登录;对开发者来说,不用处理密码存储和加密,安全责任转移给了 Google/GitHub。小明给"个人豆瓣"加了 GitHub OAuth 登录后,注册率明显提高了——朋友们不用再填邮箱、想密码、收验证邮件,点一下就进来了。

跟 AI 说:"在 Better Auth 配置中添加 GitHub OAuth 登录。"你需要先去 GitHub 创建 OAuth App,获取 Client ID 和 Secret,填到 .env 里。

Passkeys 是无密码认证的未来趋势。你用手机解锁时,按一下指纹或看一眼屏幕就解锁了。Passkeys 把这个体验带到了网站登录——用指纹、面容或硬件密钥代替密码。为什么说它是未来?因为它从根本上消灭了密码带来的所有问题:没有密码就没有密码泄露,没有钓鱼攻击(因为 Passkey 绑定了具体的网站域名,假网站 g00gle.com 无法触发 google.com 的 Passkey),也不需要用户记住任何东西。Better Auth 内置了 Passkeys 支持,如果你的用户群体主要用现代设备(2022 年之后的手机和电脑基本都支持),值得考虑加上这个选项。

Magic Link 是另一种无密码方案:输入邮箱,收到一封邮件,点击链接直接登录。不需要记密码,不需要注册流程。小明后来做了一个内部工具给几个朋友用,用的就是 Magic Link——朋友们可能几周才登录一次,记不住密码很正常。输入邮箱、点链接、进来了,整个过程不超过 30 秒。适合低频使用的工具类产品,缺点是依赖邮箱——如果邮件延迟或进了垃圾箱,用户体验就打折扣了。

还有 SSO(企业单点登录)——一个账号登录公司所有系统。你登录了企业邮箱,打开 OA、CRM、项目管理工具都不用再登录。这是企业场景的标配,个人项目一般用不到。

为什么不自己写认证

小明在 8.0 跑通了 Better Auth 的用户系统,但他好奇:为什么不自己写?登录不就是"查数据库比对密码"吗?他试着自己实现了一个简单版本:用户注册时把密码存进数据库,登录时查出来比对。能用,而且代码也不复杂,几十行就搞定了。他甚至有点得意——这不挺简单的吗,为什么大家都说不要自己写?

但老师傅看了一眼代码,给他列了一串他没想到的问题:密码是明文存的吗?数据库被攻破,所有用户密码直接泄露。密码哈希用的什么算法?MD5 早就不安全了,bcrypt 的 cost factor 设了多少?Session 存在哪里?Cookie 的 HttpOnlySecureSameSite 属性设了吗?这三个属性各守一道门:HttpOnly 防止 JavaScript 读取 Cookie(防 XSS 偷 Cookie),Secure 确保只在 HTTPS 下传输(防网络窃听),SameSite 限制跨站请求携带 Cookie(防 CSRF 冒充你发请求)——少设一个都是安全隐患。密码重置的链接有过期时间吗?Token 是一次性的吗?如果重置链接永不过期,攻击者截获一次就能反复使用。登录失败次数有限制吗?不限制的话,攻击者可以写脚本每秒尝试几千个密码组合,暴力破解只是时间问题。CSRF 防护做了吗?

小明听完就放弃了自己写的念头。这些细节,每一个都是安全隐患,而且互相关联——漏掉一个就可能被攻破。他写的那几十行代码看起来"能用",但在安全专家眼里漏洞百出。不要自己写认证逻辑——这是编程界的铁律。不是因为你写不出来,而是因为安全领域的"魔鬼在细节里",成熟的认证库已经帮你踩过了所有的坑,经过了无数项目的实战检验。

认证库怎么选

主流方案有几个:Better Auth 开源免费,数据存在你自己的数据库里,TypeScript 原生支持,和 Drizzle 无缝集成,内置 2FA、Passkeys、组织管理等高级功能,适合需要完整控制的项目。NextAuth(Auth.js) 也是开源免费的,但类型支持一般,Drizzle 需要额外适配器,适合只需要简单第三方登录的场景。Clerk 提供完整的 UI 组件开箱即用,但不是开源的(有免费额度),数据存在第三方,适合快速上线且不在意成本的项目。Supabase Auth 和 Supabase 深度集成,支持 RLS(行级安全),但不支持 Drizzle,适合已经在用 Supabase 的项目。

本教程选 Better Auth 的核心理由是数据自主——用户表、会话表都在你自己的 PostgreSQL 中,不依赖第三方服务,不被平台捆绑。而且 Auth.js(NextAuth)团队现已加入 Better Auth,后者被官方推荐为新项目的首选。Auth.js 进入维护模式——仍会收到安全补丁,但不再有重大新功能。新项目直接用 Better Auth,现有 Auth.js 项目如果运行稳定,不用急着迁移。

加载 Skill 让 AI 更懂 Better Auth

在让 AI 配置认证系统之前,加载 better-auth-best-practices Skill。加载后,AI 会自动遵循 Better Auth 的最佳实践——Session 管理策略、插件配置顺序、安全默认值等都会更规范。加了 Skill 的 AI 不太可能犯"忘了配置 CSRF 保护"或"Session 过期时间设太长"这类错误。

配置认证系统时,这样给 AI 下指令:

"在我的 Next.js 项目中集成 Better Auth,使用 Drizzle ORM 和 PostgreSQL。需要:邮箱密码注册/登录、GitHub OAuth 登录、登出功能、受保护的 /dashboard 页面(未登录跳转到 /login)。"

AI 会帮你完成:安装依赖、配置环境变量、创建数据库表、配置 Middleware 路由保护、生成登录/注册页面。你只需要把 OAuth 密钥填到 .env 里。如果后续需要更多功能,比如双因素认证(2FA)或组织管理,Better Auth 的插件系统让这些扩展变得很简单——告诉 AI 你要什么,它会帮你配置对应的插件。

开发中的另一种认证:公私钥

除了 Web 登录,你在开发中还会遇到另一种认证方式:公私钥。你用 git push 推代码到 GitHub 时,GitHub 怎么知道是你?就是通过 SSH 密钥——你的电脑上有私钥(只有你知道),GitHub 上存着对应的公钥,推代码时两把钥匙配对成功就证明了你的身份。还有 GPG 签名,给 Git 提交加一个"防伪标签",别人看到你的提交上有 Verified 标记,就知道这确实是你提交的,不是有人冒充。这些在你配置开发环境时就会用到,如果还没配置,告诉 AI:"帮我生成 SSH 密钥并配置到 GitHub。"


本节核心要点

  • Session 存服务端可控性强,Token 不存服务端扩展性好——认证库会帮你选择
  • OAuth 让用户用已有账号登录,Passkeys 是无密码的未来趋势
  • 不要自己写认证逻辑,用成熟的认证库
  • 新项目首选 Better Auth,加载 better-auth-best-practices Skill 提升 AI 输出质量

下一步

认证方式选好了,接下来去 路由保护与权限控制——学会用 Middleware 守住每一个路由,确保未授权的请求进不来。