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 生成的代码里出现 session、token、JWT、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 的 HttpOnly、Secure、SameSite 属性设了吗?这三个属性各守一道门: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-practicesSkill 提升 AI 输出质量
下一步
认证方式选好了,接下来去 路由保护与权限控制——学会用 Middleware 守住每一个路由,确保未授权的请求进不来。
