Skip to content

Plugin GitHub Login CN

JAVA-Lw edited this page Sep 9, 2026 · 1 revision

示例:GitHub 一键登录认证插件

返回插件扩展 · 下一篇:新增模型供应商插件

目标是在 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: 设置宿主会话,跳转允许的站内页面
Loading

“一键登录”表示用户不用在 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 入口。

第二步:实现 OAuth 登录事务

可以用一条有过期时间的事务记录表达一次登录尝试:

登录事务 = {
  随机 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 不构成认证。

后续必须保留宿主既有检查:

  1. 登录入口仍启用,认证连接仍匹配。
  2. 外部身份能精确查到本地已绑定账号。
  3. 本地账号未停用。
  4. 由宿主解析有效租户、工作区和角色。
  5. 使用宿主会话签发与响应投影流程完成登录。

不要按同名 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 用户查询通过,不能单独证明登录插件可用。

源码与协议依据

1flowbase Wiki

Quickstart

License

Use Cases

Evaluation Checklists

插件扩展

Engineering

Project

Clone this wiki locally