my-first-ai-web_学习记录05——NextAuth Adapter 存储用户信息

day008 的核心问题是:上一节的登录状态只存在于 Session Cookie 中,虽然 session.user 能拿到 GitHub 用户信息,但数据库里没有一个稳定的用户实体。

开始学习之前让我们带着这几个问题一起往下看:

  • 为什么不能只建一张 User 表,还要额外建 Account 和 Session?

  • 为什么 sessionToken 要唯一?

  • 为什么 expires 是 DateTime,而 Account 的 expires_at 是 Int?

  • 为什么 Session 也需要 userId 外键?

这一节要引入:

markdown 复制代码
GitHub OAuth
    ↓
NextAuth
    ↓
Prisma Adapter
    ↓
PostgreSQL

先把几层关系重新捋一遍

arduino 复制代码
PostgreSQL
  ↓
真正存储数据的数据库服务

Prisma Schema
  ↓
用 Prisma 描述数据库表结构的文件

Prisma Client
  ↓
根据 Schema 生成的 TypeScript 数据库操作 API

src/db/db.ts 中的 db
  ↓
Prisma Client 的一个实例

PrismaAdapter(db)
  ↓
把这个 Prisma Client 交给 NextAuth 使用

src/db/db.ts:

arduino 复制代码
export const db = globalForPrisma.prisma ?? createPrismaClient()

这个 db 可以理解成:

arduino 复制代码
一个已经连接 PostgreSQL、可以执行查询的 Prisma Client 对象

例如项目中的代码:

scss 复制代码
db.doc.findMany()
db.doc.create(...)
db.doc.update(...)

这些都不是直接调用 PostgreSQL,而是调用 Prisma Client。Prisma Client 在底层把它们转换成 SQL,再通过 PostgreSQL 驱动执行。

Prisma 到底是什么

Prisma 不是 PostgreSQL,也不是数据库本身。

它是一套 Node.js / TypeScript 数据库工具,主要包括:

arduino 复制代码
Prisma Schema
  → 定义模型

Prisma Client
  → 在 TypeScript 中操作数据

Prisma CLI
  → generate、db push、migrate 等命令

例如:

kotlin 复制代码
model Doc {
  id      Int    @id @default(autoincrement())
  title   String
  content String
}

执行:

arduino 复制代码
npm run db:push

大致过程是:

bash 复制代码
读取 prisma/schema.prisma
  ↓
连接 DATABASE_URL 指向的 PostgreSQL
  ↓
创建或调整数据库中的表结构

执行:

arduino 复制代码
npm run db:generate

则是:

arduino 复制代码
读取 prisma/schema.prisma
  ↓
生成 TypeScript Prisma Client

所以:

perl 复制代码
db push      → 同步数据库表结构
db generate  → 生成代码 API

这两个动作不是一回事。

NextAuth 是什么

NextAuth 也是一个 npm 包,但它解决的是另一个领域:

复制代码
NextAuth
  → 登录、OAuth、Session、Cookie、Provider、授权流程

它不是数据库工具,也不是 GitHub 本身。

可以这样分工:

arduino 复制代码
GitHub
  → 外部身份提供商

NextAuth
  → 认证流程管理器

Prisma Adapter
  → NextAuth 与 Prisma Client 之间的翻译层

Prisma Client
  → TypeScript 数据库操作 API

PostgreSQL
  → 最终存储数据

完整关系:

scss 复制代码
GitHub OAuth
    ↓
NextAuth
    ↓
PrismaAdapter(db)
    ↓
Prisma Client
    ↓
PostgreSQL

Adapter 是什么

Adapter 可以理解成 NextAuth 和数据库之间的"翻译层"。

NextAuth 需要完成这些操作:

复制代码
查找用户
创建用户
保存 GitHub 账号关联
创建 Session
查询 Session
删除 Session
保存邮箱验证码

但 NextAuth 不知道你使用 PostgreSQL、MySQL 还是 MongoDB,也不知道你的 ORM 是 Prisma 还是 Drizzle。

所以它定义了一套 Adapter 接口:

arduino 复制代码
NextAuth
  ↓ 调用统一的 Adapter 方法
Prisma Adapter
  ↓ 翻译成 Prisma API
Prisma Client
  ↓
PostgreSQL

例如,用户第一次用 GitHub 登录时,NextAuth 可能需要:

scss 复制代码
adapter.getUserByAccount(...)
adapter.createUser(...)
adapter.linkAccount(...)
adapter.createSession(...)

@auth/prisma-adapter 负责把这些操作翻译成 Prisma 查询。

它不是把整个 session.user 随便存进数据库,而是按照认证领域的数据模型拆成多张表。

Adapter 为什么需要 db

NextAuth 只知道自己需要调用一些"存储用户"的操作,例如:

复制代码
createUser
getUser
getUserByAccount
linkAccount
createSession
getSessionAndUser
deleteSession

但它不知道你项目使用什么数据库。

PrismaAdapter(db) 做的事情就是告诉 NextAuth:

arduino 复制代码
如果你需要 createUser,
我会用 Prisma Client 的方式帮你执行。

如果你需要 getUserByAccount,
我也会把它翻译成 Prisma 查询。

所以它不是"Adapter 解释 db 给 Prisma",而是:

Adapter 使用你提供的 Prisma Client,把 NextAuth 的标准存储操作翻译成 Prisma 查询。

例如概念上可能类似:

vbnet 复制代码
NextAuth:
  createUser(user)

PrismaAdapter:
  db.user.create({ data: user })

Prisma:
  INSERT INTO "User" ...

PostgreSQL:
  真正写入记录

为什么需要多张表

标准 Prisma Adapter 通常需要这些模型:

sql 复制代码
User
  用户的基本身份信息

Account
  用户和 GitHub 等登录平台的关联

Session
  当前登录会话

VerificationToken
  邮箱登录时的一次性验证码或验证链接

关系大致是:

sql 复制代码
User 1 ─── N Account
User 1 ─── N Session

同一个用户未来可能绑定多个登录方式:

sql 复制代码
一个 User
  ├── GitHub Account
  ├── 微信 Account
  └── 邮箱登录记录

所以不能只把 GitHub 返回的用户对象直接塞进一个表里。

登录后的数据库变化

第一次 GitHub 登录,数据库大致会发生:

markdown 复制代码
1. 查询 Account:这个 GitHub 账号以前登录过吗?
2. 没有找到:
   - 创建 User
   - 创建 Account,记录 GitHub 账号关联
3. 创建 Session
4. 浏览器仍然拿到 Session Cookie

再次登录时通常是:

markdown 复制代码
1. 根据 GitHub provider 和 providerAccountId 找到 Account
2. 通过 Account 找到 User
3. 创建或更新 Session
4. 不重复创建 User

这里要区分:

sql 复制代码
GitHub Access Token
  → 第三方授权凭证

User
  → 你的系统中的用户实体

Session
  → 你的系统中的一次登录会话

现在你能试着回答文章一开始的几个问题了吧?

相关推荐
孟陬5 小时前
Foobar 技术周刊#160:大模型让大规模形式化软件验证成为现实丨AI写C++代码之后会发生什么?丨我们真的需要alpha() 函数吗丨重试,有时会让故障更
前端·后端·typescript
狂师8 小时前
AI 测试 Skill 大全,我日常在用的 27个,夯爆了!
人工智能·测试·全栈
SL_staff1 天前
制造业订单交付崩盘?用四层协同框架重建交付可信度(技术实践)
java·产品·全栈
SL_staff1 天前
打破风控迭代死循环:用决策编排重构业务与技术协作链路
java·产品·全栈
SL_staff1 天前
JVS-APS的7个刚性约束设计:从无限产能幻觉到可执行排产的工程实践
java·spring cloud·全栈
螺丝钉tina1 天前
[Playwright ][16]Playwright + TypeScript API 自动化测试实战:API测试
前端·javascript·typescript
梯度下降者1 天前
3天时间,我使用 Cursor 开发了一个提示词生成器
ai编程·next.js·cursor·产品开发·提示词生成器
华玥作者1 天前
Vue 3 + TypeScript + uni-app 组件库推荐:hy-app(华玥组件库)
vue.js·typescript·uni-app
锋行天下2 天前
Langgraph-cli 本地构建失败,改用服务器docker构建的流程
人工智能·前端框架·全栈
SL_staff2 天前
HR系统对接钉钉考勤总失败?根源在于缺乏业务语义级逻辑中枢
java·开源·全栈