本文最后更新于 2026年8月21日。
接入 SSO 之后,应用本身(如 Memos)的用户表与 SSO(如 Pocket ID)的用户表并不是替代关系,而是“一对一”或“多对一”的映射绑定的关联关系。
应用并不会因为接了 SSO 就删掉自己的用户表,而是通过外键标识(Federated ID / Subject ID)将本地用户与 SSO 身份链接起来。
一、 核心数据模型
在数据库底层,通常存在以下几种映射结构:
1. 两表中的关键字段映射
| 数据表 | 关键字段 | 作用 |
|---|---|---|
| SSO 用户表 (Pocket ID) | sub (Subject / User ID) |
SSO 系统中该用户的唯一不变标识(通常是一串 UUID) |
| 应用本地用户表 (Memos) | id (Local User ID) |
应用内部的自增主键/本地 ID,用于关联笔记、标签等数据 |
| 应用本地用户表 / SSO 绑定表 | sso_sub / provider_id |
连接桥梁:存放 SSO 返回的 sub |
2. 映射关系示意
Plaintext
【SSO 用户表 - Pocket ID】 【应用本地用户表 - Memos】
┌────────────────────────┐ ┌────────────────────────┐
│ id (sub): "usr_9x2a..."│ ────映射────> │ id: 102 │
│ username: "alice" │ │ username: "alice" │
│ email: "alice@a.com" │ │ sso_provider: "pocket" │
└────────────────────────┘ │ sso_sub: "usr_9x2a..." │
└────────────────────────┘
│
▼
【Memos 业务数据】
(memos, tags, resources...)
二、 两种常见的首次登录与绑定逻辑
当用户通过 SSO 登录应用时,应用内部会触发以下判断流程:
1. JIT(Just-In-Time)自动创建账号(最常见)
-
用户点击 SSO 登录,Pocket ID 验证身份后返回 Token/UserInfo,其中包含
sub: "usr_9x2a..."。 -
Memos 拿着这个
sub去本地用户表查询是否存在sso_sub = "usr_9x2a..."的记录。 -
未找到记录:Memos 自动在本地
Users表里插入一条新用户,把 SSO 返回的用户名、邮箱填入,并将sso_sub记为"usr_9x2a..."。 -
已存在记录:直接登录该本地账号。
2. 手动绑定已有本地账号
如果用户在接 SSO 之前已经在 Memos 里注册了账号:
-
允许用户在 Memos 个人设置中点击“绑定 Pocket ID 账号”。
-
完成 SSO 认证后,把该 SSO 的
sub写入当前已登录本地账号的sso_sub字段。 -
下次直接点击 SSO 按钮,系统匹配到
sso_sub即可登录原账号。
三、 为什么必须保留应用本地的用户表?
-
业务数据外键绑定:Memos 里的每一条笔记、图片、评论,数据库外键关联的都是 Memos 本地的
user_id(如102)。如果不保留本地用户表,本地的所有业务数据外键都将失效。 -
权限与本地配置:SSO 只负责“认证你是谁”,不负责“你在具体应用里的权限”。Memos 需要本地表来存储该用户是
ADMIN(管理员)还是USER(普通用户),以及用户的本地偏好设置。 -
解耦与容灾:如果未来更换或关闭 SSO 系统,应用只需修改映射字段,本地的业务数据和用户资产不会丢失。