Repository navigation
Plugin GitHub Login CN
目标是在 1flowbase 登录页增加“使用 GitHub 登录”:用户跳转 GitHub 完成授权,返回后由宿主识别本地账号并建立正常会话。
本文是基于当前认证边界的实现设计示例,不是已发布插件的安装说明。 基线 2143c8d4 已有认证提供者声明、登录入口、外部身份映射和会话能力;尚未提供本文的 GitHub OAuth 处理器、回调路由及完整生产装配。文中的 acme.github-auth、新路径和目录均为示例命名。
GitHub 登录需要验证外部身份,再由宿主决定它属于哪个本地用户。应把这一能力接入 HostExtension 的认证边界,按宿主启动和重启管理。
需要区分三个相近名称:
| 入口 | 职责 | 与本例的关系 |
|---|---|---|
auth_providers / AuthenticatorProvider
|
定义登录方式及验证外部身份 | 本例的主要接入点 |
interface_authentication_adapters |
把请求凭据转换为指定类型的可信主体 | 用于接口调用认证,不等于一套 GitHub OAuth 登录流程 |
Provider 协议中的 auth
|
获取或维护上游模型供应商凭据 | 不用于登录 1flowbase |
现有 model_definitions.create Hook 面向数据建模定义创建,不能在其中代替登录处理器,也不能让受管 worker 返回一个用户编号就取得本地身份。
sequenceDiagram
participant U as 用户浏览器
participant P as 可信 GitHub 认证扩展
participant G as GitHub
participant H as 宿主认证与会话
U->>P: 点击“使用 GitHub 登录”
P->>P: 检查登录入口,创建一次性登录事务
P-->>U: 跳转 GitHub 授权页
U->>G: 登录并同意授权
G-->>U: 携带 code、state 返回回调
U->>P: 回调请求
P->>P: 验证并领取一次性事务
P->>G: 服务端兑换 access token
P->>G: 使用 token 获取当前用户
P->>H: 提交经验证的外部身份
H->>H: 查找已绑定账号,检查状态与作用域
H-->>U: 设置宿主会话,跳转允许的站内页面
“一键登录”表示用户不用在 1flowbase 再输入一套密码。首次使用仍可能需要在 GitHub 登录或同意授权。
本例采用已绑定账号才能登录的最小范围。当前 AuthKernel::login 也是查找已有外部身份绑定,查不到就拒绝。自动注册、按邮箱合并账号和自动加入工作区,需要单独确定规则并实现,不在示例中默认开启。
在 GitHub 创建 OAuth App,并配置部署环境的首页与回调地址。以 https://flow.example.com 为示例站点:
| 配置 | 示例或说明 | 持有者 |
|---|---|---|
| OAuth App 的客户端标识 | client_id |
宿主配置;本身不是密钥 |
| OAuth App 的客户端密钥 | client_secret |
仅后端秘密配置 |
| 回调地址 | https://flow.example.com/api/public/auth/acme.github-auth/callback |
固定配置,与 GitHub 登记值一致 |
| 认证类型 | acme.github-auth.github |
插件声明并由宿主注册 |
| 认证连接 | connection_id |
宿主持久身份域 |
| 登录入口 | login_entry_id |
宿主选择本次登录使用的入口 |
本例针对 GitHub.com。GitHub Enterprise Server 的地址、版本能力和身份域应另行配置与验证,不能共享一个含糊的 issuer。
只为读取 GitHub 公开身份时,空 scope 可以满足最小目的;确需非公开邮箱再申请 user:email。不要为了登录申请 repo。GitHub 对已有授权的 scope 有复用行为,收到 token 后仍应检查实际授予范围。
| 部分 | 认证扩展负责 | 宿主负责 |
|---|---|---|
| 登录方式 | 声明认证类型、专有配置和登录按钮 | 注册定义、管理连接与登录入口、投影公开字段 |
| OAuth 协议 | 构造授权请求、校验回调、兑换 token、获取 GitHub 用户 | 提供受控配置、路由装配与所需状态存储入口 |
| 外部身份 | 根据 GitHub 的可信响应构造验证结果 | 检查连接归属并查找本地绑定 |
| 本地权限 | 不自行赋予管理员、租户或工作区身份 | 检查用户状态、加载有效作用域与权限 |
| 会话 | 把验证结果交给宿主 | 签发会话、设置 Cookie、沿用 CSRF 与过期策略 |
| 发布 | 提供实现与声明 | 在启动流程装配真实实现并重启生效 |
下面是职责目录示意,不是现有仓库内已经生成的插件:
acme.github-auth/
├─ manifest.yaml 安装与宿主扩展身份
├─ host-extension.yaml 认证类型、配置、路由贡献
└─ src/
├─ lib.rs 可信实现的注册入口
├─ oauth.rs GitHub 授权、兑换与用户查询
├─ login_transaction.rs state、PKCE 与一次性事务
├─ provider.rs 外部身份验证与宿主接缝
├─ routes.rs 发起和回调处理器
└─ public_login.tsx “使用 GitHub 登录”公开区块
若需要新增持久结构,应由宿主支持的存储和 migration 入口接入。多实例部署不能只把 OAuth 事务保存在某个进程的内存里。
AuthProviderContributionManifest 当前包含:
| 字段 | 本例用途 |
|---|---|
auth_type |
使用扩展拥有的类型名,例如 acme.github-auth.github
|
display_name |
GitHub 登录 |
config_schema |
声明 client_id、client_secret、callback_url 等专有配置 |
default_public_ui_block |
实际登录区块源码字符串,不能只填一个组件名字 |
public_variable_keys |
允许公开给登录区块的配置键白名单 |
public_route_ids |
本扩展在 routes 中实际声明的公开认证路由标识 |
配置片段如下,仅展示 config_schema,不是完整可安装清单:
config_schema:
- key: client_id
label: GitHub 客户端标识
type: string
required: true
- key: client_secret
label: GitHub 客户端密钥
type: secret
required: true
- key: callback_url
label: GitHub 回调地址
type: string
required: true
public_variable_keys: []最小登录按钮只需当前 login_entry_id 和固定的宿主发起入口,无需向浏览器下发客户端密钥。public_variable_keys 不能引用 secret / password 类型字段;配置也不能覆盖核心的 enabled、title、public_ui_block 等字段。
示例拟新增的两个路由如下,当前服务没有这两个端点:
| 标识 | 方法与路径 | 职责 |
|---|---|---|
acme.github-auth.start |
GET /api/public/auth/acme.github-auth/start |
接收 login_entry_id,创建登录事务并跳转 |
acme.github-auth.callback |
GET /api/public/auth/acme.github-auth/callback |
校验回调并完成登录 |
清单中的公开认证路由必须同时出现在 routes 与该提供者的 public_route_ids 中,路径位于 /api/public/auth/。路由还要有真实处理器及宿主要求的资源、动作与调用契约装配;声明本身不会创建可执行 HTTP 入口。
可以用一条有过期时间的事务记录表达一次登录尝试:
登录事务 = {
随机 state 的摘要,
浏览器绑定标识的摘要,
login_entry_id,
connection_id,
固定 callback_url,
PKCE code_verifier,
允许的站内返回路径,
过期时间,
消费状态
}
这些是示例逻辑字段,不是已经存在的数据库表。code_verifier 留在后端受保护的状态中;回调必须检查 state、浏览器绑定、入口与连接,并用原子操作领取一次性事务。并发回调和重放只能有一次成功取得处理权;失败后由用户重新发起登录。
GitHub.com 当前支持 PKCE 的 S256 方法。生成独立的高熵 code_verifier,计算:
code_challenge = BASE64URL(SHA256(ASCII(code_verifier))),去掉末尾填充符
向 https://github.com/login/oauth/authorize 发送 URL 编码后的 client_id、固定 redirect_uri、state、所需 scope、code_challenge 和 code_challenge_method=S256。PKCE 不能代替 state 与浏览器绑定。
回调校验通过后,由后端请求 https://github.com/login/oauth/access_token,提交 client_id、client_secret、code、同一个 redirect_uri 和原 code_verifier,并请求 JSON 响应。不要在浏览器兑换 token,也不要把 token 放进站内跳转 URL。
随后携带 token 调用 GET https://api.github.com/user,按 GitHub REST 要求设置请求头。可信身份来自这次服务端查询,不能相信浏览器提交的 github_user_id。
使用 GitHub 返回的稳定 id 作为主体值,login 与邮箱作为展示资料。建议的身份映射如下;github_user_id 是本例定义的主体类型名:
| 宿主领域字段 | 本例值 |
|---|---|
connection_id |
本次事务冻结并校验的认证连接 |
subject_type |
github_user_id |
subject_value |
GitHub id 的字符串形式 |
issuer |
https://github.com |
realm |
本例无额外身份域时为空 |
profile |
经过选择的用户名、头像等展示资料 |
GitHub OAuth App 的访问 token 不是本地会话,也不能按一个未验证的 OIDC ID token 来处理。宿主的 VerifiedExternalIdentity 是进程内类型,不提供直接反序列化;它必须由可信验证流程构造。把外部 JSON 中的 verified 改成 true 不构成认证。
后续必须保留宿主既有检查:
- 登录入口仍启用,认证连接仍匹配。
- 外部身份能精确查到本地已绑定账号。
- 本地账号未停用。
- 由宿主解析有效租户、工作区和角色。
- 使用宿主会话签发与响应投影流程完成登录。
不要按同名 GitHub 用户名或相同邮箱自动接管已有账号。绑定应在已认证的本地账号上下文中完成,并验证该次外部身份;本例不额外定义一个未经授权的绑定接口。
当前源码有两个需要开发时明确处理的接缝:
定义注册与实现注册分开。 AuthenticatorRegistry::from_host_extensions 会读取 auth_providers 生成定义;当前生产启动使用这条路径,它不会自动实例化 GitHub 的 AuthenticatorProvider。from_providers 可以构造实现映射,但不能把它单独替换到启动流程就认为配置定义也已完整。需要把声明与可信实现一起装配,并校验对应关系。
现有登录调用仍使用 identifier / password 输入。 AuthenticatorProvider::authenticate 当前接受 login_entry、identifier、password 和 repository。OAuth 回调并不是天然匹配的密码表单。实现时需要为经验证的 OAuth 结果增加清晰的宿主完成登录接缝,复用既有账号、权限与会话步骤;不能虚构一个已经存在的 complete_oauth_login API,也不应把任意客户端身份 JSON 塞进 password。
本示例建议以明确类型表达 OAuth 登录完成输入,具体内部端口和 API 契约需在开发任务中确定。登录按钮区块可参考当前密码登录区块的 ctx.inputs.login_entry_id、错误展示及返回认证方式选择器机制;按钮点击后的整页跳转与回调成功后的会话刷新仍需真实浏览器验证。
native.library / entry_symbol 也必须对应宿主实际支持的实现入口。不要把一个不存在的 builtin://acme.github-auth 写进 YAML 当成已完成装配。首次交付宜与宿主可信实现一起发布并重启验证。
| 场景 | 应观察到的结果 |
|---|---|
| 已绑定且启用的用户完成 GitHub 授权 | 得到正常宿主会话,只拥有本地有效权限 |
| 未绑定用户 | 不登录、不自动注册,也不自动合并同邮箱账号 |
| 用户取消授权 | 返回明确可重试的登录状态,不签发会话 |
| state 缺失、过期、浏览器绑定不匹配或回放 | 拒绝,不兑换或重复消费凭据 |
| 两次回调并发 | 一次性事务只有一个处理者 |
| GitHub code 无效、PKCE 不匹配或 token 兑换失败 | 不签发会话,失败原因可诊断 |
| GitHub 邮箱为空或用户名变更 | 身份仍按稳定 id 解析 |
| 用户或登录入口在跳转期间被停用 | 回调完成阶段拒绝登录 |
| 返回路径指向外部站点 | 拒绝该跳转或使用预设站内目标 |
| 多实例、进程重启 | 不串用事务;无法恢复的尝试要求重新登录 |
| 成功登录后的受保护页面与注销 | 沿用宿主会话、CSRF、过期和注销规则 |
验收必须覆盖真实 GitHub 测试 OAuth App、宿主启动装配与浏览器往返。声明可解析或 mock 用户查询通过,不能单独证明登录插件可用。