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

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

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

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

  • 为什么 sessionToken 要唯一?

  • 为什么 expiresDateTime,而 Account 的 expires_atInt

  • 为什么 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
  → 你的系统中的一次登录会话

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

相关推荐
10年前端老司机2 小时前
别卷CRUD了!前端用Next.js+LangChain.js,低成本冲进AI高薪赛道
前端·langchain·next.js
退休倒计时2 小时前
【每日五题】leetcode TypeScript
算法·leetcode·职场和发展·typescript
wangfpp2 小时前
原生NodeJS维护Agent Memory实践
后端·agent·全栈
我就是DaLing呀!3 小时前
vue3 + 独立的数据管理 Store实现视频剪辑功能
前端·typescript·vue3·canvas·store
Aolith20 小时前
我在React全栈项目中搭建了一个完整题库
数据库·react.js·全栈
BillKu2 天前
TypeScript中,字符串字面量联合类型(Union Type)、enum的用法说明
前端·javascript·typescript
西瓜太郎4992 天前
用 TypeScript 写一个健壮的 SSE 流式响应解析器
typescript
为你学会写情书2 天前
用 Redis 当数据库?Next.js 笔记系统的数据层设计
next.js
用户0934077735142 天前
HarmonyOS WPS Open SDK 实践:OpenFileRequest 打开链路与沙箱拷贝
android·typescript·harmonyos