最难的不是发 JWT,而是控制谁能做什么

你以为认证只是“发个 JWT”,直到客户要 SSO、组织隔离、角色权限、邀请成员、CLI 登录、MCP 授权,你才发现自己正在手搓半个 Auth0。


很多程序员创业做 SaaS,前几天都很乐观。

第一天:

POST /login
→ 校验密码
→ 签发 JWT
→ 前端存 token
→ 完事

第二周:

加一个 Google 登录吧。

第一个客户来了:

能不能支持邀请同事?

第二个客户来了:

我们公司有多个部门,不同部门权限不一样。

第三个客户来了:

我们用 Azure AD,能接企业 SSO 吗?

然后 AI Agent 来了:

这个 Agent 能不能代表用户调用工具?
这个 MCP Server 到底该拿谁的权限?
CLI 登录怎么办?
机器之间调用又怎么办?

到这一步你才发现:

登录,从来不是一个页面。
JWT,也从来不是权限系统。
认证真正难的地方,是“谁在什么上下文里,可以访问什么”。

最近读了 Logto 的源码,我最大的感受是:

它不是想帮你做一个更好看的登录页。
它想把 SaaS 最容易失控的一整套身份、组织、权限、协议和登录体验,收拢成一层基础设施。

Logto 官方将自己定位为面向 SaaS 和 AI 应用的开源身份认证与授权基础设施,覆盖 OIDC、OAuth 2.1、多租户、企业 SSO、RBAC、组织能力及 MCP / Agent 场景。(GitHub)

但如果只把它理解成“开源 Auth0”或者“Supabase Auth 替代品”,其实低估它了。

它真正想解决的,是一个更现实的问题:

当你的产品从“一个 App”
变成“多个应用 + 多个客户 + 多种登录方式 + 多层权限 + 多个 Agent”
身份系统还能不能不崩?

一、程序员最容易低估的坑:认证不是 Login,权限才是无底洞

很多项目一开始的权限模型,都长这样:

user.role === 'admin'

或者:

if (token.role === 'editor') {
  allow();
}

早期完全没问题。

但当产品开始卖给企业客户后,问题会突然爆发。

一个用户可能同时属于多个公司。

同一个用户在 A 公司是管理员,在 B 公司只是普通成员。

同一个用户能管理项目 X,却不能看项目 Y。

同一个企业可能有自己的 SSO、自己的域名、自己的管理员、自己的成员邀请流程。

于是你原来的权限判断开始变成:

if (
  user.role === 'admin' &&
  user.organizationId === currentOrganizationId &&
  project.organizationId === currentOrganizationId &&
  user.permissions.includes('project:write')
) {
  allow();
}

再过几个月,代码库里会出现几十处这样的判断。

没人知道哪一处漏了组织隔离。

没人知道某个 API 是否真的校验了 scope。

更没人敢轻易改 JWT 结构。

这就是为什么很多 SaaS 最后不是死在业务逻辑,而是死在“权限债务”。

Logto 的源码里,组织、组织邀请、组织角色、组织 scope、应用、用户、SSO、登录体验、验证流程等能力,并不是散落在几个可选插件里,而是直接被拆进核心路由和数据模型边界中。(GitHub)

这意味着它的思路不是:

先做登录,
以后再补权限。

而是:

身份
→ 应用
→ 组织
→ 资源
→ Scope
→ 角色
→ Token Claim
→ API 访问

从一开始就必须是一条链。


二、Logto 最像“基础设施”的地方:它不是一个认证服务,而是一套 Tenant Runtime

读源码时,最值得注意的不是登录界面。

而是它处理请求的方式。

Logto 的核心服务是一个 Koa 应用,但请求进来后,不会直接进入固定的认证逻辑。

它会先根据 URL、域名或自定义域名,识别请求属于哪个 Tenant;再从 Tenant Pool 中拿到对应的运行时实例,交给该 Tenant 自己的 Koa App、OIDC Provider、数据库连接、配置、Connector 和业务库去处理。(GitHub)

简单理解:

请求进入 Logto
        ↓
识别当前租户
        ↓
加载该租户的配置、Issuer、数据库连接
        ↓
加载该租户的登录方式、连接器、SSO 配置
        ↓
进入该租户自己的认证运行时

这不是一个普通的“多租户字段隔离”。

它更像:

Tenant = 一套独立身份运行环境

源码里甚至专门处理了一个很细的细节:

如果用户通过租户的自定义域名访问,OIDC 的 issuer 也要基于这个自定义域名构建。

这看起来只是 URL 问题。

实际上却是身份系统里非常要命的问题。

因为 OIDC 世界中,issuer、redirect URI、cookie、JWKS、token audience、客户端配置,全都不能乱。

你不能让:

customer-a.example.com

最后签发一个:

issuer = auth.yourcompany.com

却又让客户以为这是自己的企业认证入口。

Logto 在请求层先识别 Tenant,再根据是否为自定义域名构建不同 endpoint 的设计,本质是在处理“身份边界”和“品牌边界”同时存在的复杂场景。(GitHub)

这才是很多团队手写认证系统时,最容易后知后觉的坑。


三、真正难的不是 JWT,而是 OIDC 生命周期

很多人对认证系统的理解,还停留在:

账号密码正确
→ 返回 token

但真实世界里,一次认证至少可能涉及:

登录
注册
社交登录
短信验证
邮件验证
MFA
设备授权
刷新 Token
Token 吊销
退出登录
第三方应用授权
用户同意 Scope
企业 SSO
机器对机器调用
账号关联
风险验证

这不是一个 API。

这是一整套协议状态机。

Logto 没有试图从零造一个 OAuth Server,而是基于 oidc-provider 构建 OIDC 核心,再把自己的租户、组织、资源、用户、Token Claim、审计、Connector 和应用策略塞进这条协议链。源码中启用了 UserInfo、Token Revocation、Introspection、Client Credentials、Backchannel Logout、Device Flow、RP-Initiated Logout、Resource Indicators 等能力。(GitHub)

你可以把它理解成:

OIDC Provider
+
PostgreSQL 状态存储
+
多租户运行时
+
组织授权模型
+
用户登录体验
+
企业级连接器

这才是 Logto 的底座。

而不是一个:

login()

函数。


四、它最关键的一层:把 OIDC 的“协议能力”,翻译成 SaaS 的“业务权限”

OIDC 很强。

但它天然不懂你的 SaaS 业务。

OIDC 不知道:

谁是某个组织的管理员;
谁能邀请成员;
谁能导出财务报表;
谁能调用某个 AI Agent;
谁能访问某个 MCP 工具;
谁只能读,谁可以写;
谁的权限仅限某一个组织。

这些事情,不能只靠一个 sub

所以 Logto 的实现里,有一层非常关键的东西:

Application
Resource
Scope
Organization
Role
Claim

比如第三方应用申请权限时,不是“给了 token 就能干所有事”。

源码里会先查询该应用允许的用户 scope,并限制第三方客户端可请求的 scope;资源 scope 和组织 scope 则会继续在资源服务信息处理过程中筛选。(GitHub)

换句话说,它不是:

拿到 Access Token
→ 默认拥有一切权限

而是:

用户身份
+ 当前应用
+ 当前组织
+ 当前资源
+ 当前 Scope
+ 当前客户端配置
→ 最终得到什么 Token
→ Token 能访问什么 API

这才是 SaaS 权限设计最该有的样子。

不是问:

这个用户是不是管理员?

而是问:

这个用户,代表哪个组织,通过哪个应用,试图访问哪个资源,用什么 scope 做什么动作?

这两个问题,差了一个企业级权限系统。


五、为什么很多“登录 SDK”最后都会烂掉?因为它们没有管理身份状态

很多人以为认证服务的状态很简单:

User
Session
Token

实际上,认证系统会产生大量短生命周期状态。

比如:

authorization code
interaction session
consent
device code
refresh token
grant
access token
logout session
verification state

这些状态不是简单放 Redis 就完事。

它们要考虑:

什么时候失效;
什么时候消费;
什么时候撤销;
什么时候关联用户;
什么时候关联组织;
什么时候被刷新;
什么时候被强制吊销;
什么时候能被审计。

Logto 的 OIDC Adapter 把 oidc-provider 的模型状态写入自己的持久化层,包含按 ID、UID、User Code 查找,消费实例、销毁实例、按 Grant 撤销、更新过期时间等操作。(GitHub)

程序员看到这里应该会意识到:

Logto 做的不是“Token 生成器”。
它是在维护一套身份状态机。

而身份状态机,才是认证系统真正容易翻车的地方。

你可以自己发 JWT。

但你很难优雅解决:

用户换手机了,如何让旧设备退出?
员工离职后,如何撤销所有会话?
企业管理员关闭某个成员权限后,旧 Token 怎么办?
用户切换组织后,Token 里的权限还算不算数?
第三方应用取消授权后,Refresh Token 怎么处理?

这些问题,最后都会从产品需求,变成安全事故。


六、Logto 最不“性感”、却最值钱的设计:Connector 不是功能,是扩展体系

很多身份产品支持 Google 登录。

再好一点,支持 GitHub、Apple、Microsoft。

但 Logto 的 Connector 目录里,不只是社交登录,还包括邮箱、短信、企业身份、云通信、国内生态和多种第三方服务。

例如代码库中可以看到 Google、GitHub、GitLab、Apple、Azure AD、Discord、飞书、钉钉、支付宝、阿里云邮件、阿里云短信、AWS SES、Mailgun 等 Connector。(GitHub)

这说明它不是单纯在堆“登录按钮”。

它在做一个 Connector Framework。

你可以把它理解成:

Logto 核心负责:
协议、用户、组织、权限、Token、流程。

Connector 负责:
Google 怎么登录;
飞书怎么登录;
短信怎么发;
邮件怎么发;
企业 IdP 怎么接;
某个国家或地区的身份渠道怎么接。

这套拆法非常工程化。

因为认证系统最容易变成一锅粥的地方,就是把所有第三方身份提供商、短信服务商、邮件服务商、企业 IdP 的差异,全塞进核心逻辑。

最后一改 Google 登录,短信验证码坏了。

一接企业 SSO,邮箱注册流程又崩了。

Logto 把这些渠道拆到 Connector 层,本质是在保护认证核心不被第三方生态绑架。


七、登录体验为什么也必须是基础设施,而不是“前端顺手写一下”?

很多工程师会说:

协议我懂,后端我会写,登录页面我让前端做一下不就行了?

问题是,登录体验不是一个页面。

它是一整套“身份交互状态”。

比如:

输入邮箱后,是登录还是注册?
账号不存在时要不要自动创建?
用户先绑手机号还是邮箱?
企业 SSO 放在第几步?
验证码失败后怎么重试?
MFA 在什么节点触发?
用户同意授权页面怎么展示?
用户退出时怎么清理会话?

这些不是 UI 细节。

这些都会影响协议状态、用户状态、账户安全和转化率。

Logto 的代码库里将面向终端用户的注册和登录体验单独拆成 experience 包,而核心 Tenant Runtime 则负责挂载 Experience、Account Center、Consent、Session Guard、SSR 和安全头。(GitHub)

这个设计背后的判断很重要:

登录页不是业务页面。
登录页是身份系统的一部分。

一旦你把它当成普通页面,后面接 MFA、SSO、Consent、账号绑定、设备登录、密码策略时,就会开始痛苦。


八、AI Agent 出现后,认证系统又被重新洗牌了

过去,认证系统的主角是:

人
→ 浏览器
→ Web App
→ API

现在变成了:

人
→ AI Agent
→ MCP Server
→ 外部工具
→ 第三方 API
→ 企业资源

问题一下子复杂了。

一个 Agent 到底拿谁的身份?

拿用户身份?
拿系统身份?
拿组织身份?
拿临时委托权限?
拿机器账号?
拿某个 Tool 的独立 Scope?

如果没有一套清晰的授权模型,AI Agent 很容易变成:

一个权限极大的机器人,
拿着用户 Token 到处调用工具。

这非常危险。

Logto 在 README 里明确把 MCP 和 Agent-based architectures 放在支持范围内;源码里也同时具备 Device Flow、Client Credentials、Resource Indicators、第三方客户端 scope 限制、Token Claim 扩展等能力。(GitHub)

我的判断是:

Logto 想做的不只是“用户登录”。
它也在为未来的 Agent 授权模型铺路。

未来一个成熟的 Agent 系统,至少应该能回答:

这个 Agent 代表谁?
它属于哪个组织?
它能访问什么资源?
它调用某个 MCP Tool 时,获得的是长期权限还是短期授权?
用户撤销权限后,Agent 还能不能继续跑?

这些问题,最终都不是 Prompt 能解决的。

它们只能靠身份系统解决。


九、但别误会:上了 Logto,不等于你不用设计权限

这也是最需要提醒程序员的一点。

Logto 可以解决很多基础问题:

认证协议;
Token 生命周期;
用户目录;
社交登录;
企业 SSO;
组织;
RBAC;
资源 Scope;
连接器;
登录体验;
多租户基础设施。

但它不会自动替你定义:

什么角色应该拥有退款权限;
什么人可以删除项目;
某个 AI Agent 是否可以代表用户发邮件;
不同套餐客户看到哪些功能;
你的业务数据如何按组织隔离;
某个“管理员”是否可以越权访问其他企业数据。

这些仍然是你的产品和业务逻辑。

最危险的做法是:

有了 RBAC
→ 就以为权限问题解决了。

真正成熟的做法是:

Logto 管身份与授权基础设施;
你的业务系统管理领域权限与数据边界;
两者通过 Scope、Claim、Organization Context 对齐。

这才是可维护的分工。


最后:真正值钱的认证系统,不是“让用户登录”,而是“让系统敢于授权”

过去,登录功能只是产品边角料。

现在,身份系统已经变成 SaaS 的核心基础设施。

因为你的产品越复杂,身份关系就越复杂:

用户越来越多;
组织越来越多;
应用越来越多;
权限越来越细;
企业客户越来越多;
AI Agent 越来越多;
外部工具越来越多。

到最后,最难的问题不再是:

用户能不能登录?

而是:

系统凭什么相信他?
他代表谁?
他在哪个组织里?
他能访问什么?
他的权限什么时候应该失效?
他让 Agent 做事时,Agent 又该拿什么权限?

Logto 的价值,不在于它能帮你少写一个登录页面。

而在于它试图把这些原本会散落在前端、后端、JWT、中间件、数据库和第三方 SDK 里的复杂度,重新收拢成一套身份基础设施。

真正厉害的 SaaS,不是用户登录后就放行。

而是它知道:

谁来了,
为什么能进来,
进来后能做什么,
以及什么时候必须让他离开。

图片[1]-最难的不是发 JWT,而是控制谁能做什么-新觅源码库
© 版权声明
THE END
觉得不错?点个赞吧!
点赞6 分享
评论 抢沙发

请登录后发表评论

    暂无评论内容