第三方对接指南

5 步完成 UserMatrix OAuth 2.1 + PKCE 对接,附可运行完整 demo。

统一接口标准:云集生态的官方标准 = OAuth 2.1 + OIDC(覆盖网站/APP/小程序,家族产品互联唯一固定协议)。本文是标准对接的实操指南。完整对比见 对接方式总览

流程一览

你的应用                    UserMatrix                 用户
  │                            │                        │
  │── 1. 构造授权 URL ────────→│                        │
  │   (含 PKCE challenge)      │                        │
  │                            │── 2. 跳转授权页 ───────→│
  │                            │←── 3. 用户扫码/授权 ────│
  │←── 4. 带 code 回调 ────────│                        │
  │── 5. code + verifier 换 token →│                    │
  │←── 返回 access_token ──────│                        │
  │                            │                        │
  └─ 登录完成,用 access_token 调 userinfo

准备材料

um.yunjii.cn/console/apps 创建应用,获得:

材料说明示例
appid应用 ID(即 OAuth client_id)1001
appkey应用密钥(即 client_secret,切勿泄露a3f8b2c9d1e7...
回调域名你的回调地址域名yourapp.com

5 步对接(OAuth 2.1 + PKCE)

构造 OAuth 2.1 授权 URL,引导用户跳转到 UM 授权页。公开客户端(SPA/小程序)必须启用 PKCE

手动构造

GET https://um.yunjii.cn/oauth/authorize
参数必填说明
response_type固定 code
client_id应用 ID
redirect_uri回调地址(域名需在控制台配置的 domains 中)
state防 CSRF,随机字符串,原样返回
scopeopenid profile(默认)
code_challengePKCE challenge(推荐启用)
code_challenge_methodS256

PHP SDK 一行生成

$state    = bin2hex(random_bytes(16));
$verifier = $um->generateCodeVerifier();           // PKCE
$authUrl  = $um->authorizeUrl($state, $verifier);  // 自动算 challenge
header("Location: $authUrl");

JS SDK

const verifier = UM.generateCodeVerifier();
const challenge = await UM.generateCodeChallenge(verifier);
sessionStorage.setItem('um_pkce', verifier);
location.href = UM.authorizeUrl(state, challenge);

PKCE 流程:客户端生成 code_verifier(随机串)→ 计算 code_challenge = base64url(SHA256(verifier)) → 授权请求带 challenge → 换 token 时带 verifier → 服务端校验匹配。防止授权码被中间人劫持。

用户在 UM 授权页完成扫码(微信/支付宝)或登录(邮箱/密码)。

这一步你不需要做任何事,UM 会自动处理。

用户授权后,UM 会带 codestate 跳转回你的 redirect_uri

https://yourapp.com/callback?code=CODE_xxx&state=你传的state

你需要:

  1. 验证 state 与第一步生成的是否一致(防 CSRF)
  2. 取出 code,进入下一步

code 5 分钟内只能用一次,过期或重复消费返回 errcode=40163

接口POST https://um.yunjii.cn/oauth/token

参数

参数必填说明
grant_typeauthorization_code
code上一步拿到的 code
client_id应用 ID
client_secret应用密钥(appkey)
redirect_uri必须与授权时一致
code_verifierPKCE verifier(启用 PKCE 时必传)

响应

{
  "code": 0,
  "msg": "succ",
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 604800,
  "refresh_token": "rt_a1b2c3d4e5f6...",
  "user": {
    "id": 12345,
    "openid": "um_a1b2c3d4e5f6",
    "nickname": "张三",
    "avatar": "https://thirdwx.qlogo.cn/...",
    "login_type": "wx"
  }
}

字段说明

字段说明
access_token访问令牌(7 天有效),后续 API 调用凭证
refresh_token刷新令牌(30 天,轮换制)
user.openid应用内用户唯一 ID(同应用不变)
user.id用户内部 ID
user.login_type登录方式(wx / alipay / qq / douyin / email / self)

OAuth 2.1 标准端点用 code: 0 表示成功(旧版 REST 用 code: 1)。迁移时注意判断条件。

接口GET https://um.yunjii.cn/oauth/userinfo

Authorization: Bearer <access_token>

响应(标准 OIDC claims):

{
  "sub": "um_a1b2c3d4e5f6",
  "name": "张三",
  "nickname": "张三",
  "picture": "https://thirdwx.qlogo.cn/...",
  "email": "zhangsan@example.com",
  "email_verified": true,
  "login_type": "wx",
  "iss": "https://um.yunjii.cn"
}
字段说明
subUMID,跨应用唯一(同一用户在不同应用 UMID 相同)
name / nickname用户资料
picture头像 URL
email邮箱(可能为空)
login_type登录方式

Token 续期(Refresh Token 轮换)

access_token 过期后,用 refresh_token 换取新的 token:

接口POST https://um.yunjii.cn/oauth/token

参数必填说明
grant_typerefresh_token
refresh_token上一次获取的 refresh_token
client_id应用 ID
client_secret应用密钥

轮换制:每次刷新签发新的 refresh_token,旧的立即失效。客户端必须用最新的 refresh_token 进行下次刷新。


完整 PHP Demo

<?php
require_once 'UM.class.php';

session_start();

$um = new UM(
    '你的_appid',
    '你的_appkey',
    'https://yourapp.com/callback.php',
    'https://um.yunjii.cn/'
);

$act = $_GET['act'] ?? '';

if ($act === 'login') {
    // 1. 生成授权 URL + PKCE
    $state    = bin2hex(random_bytes(16));
    $verifier = $um->generateCodeVerifier();
    $_SESSION['oauth_state']    = $state;
    $_SESSION['oauth_verifier'] = $verifier;

    header('Location: ' . $um->authorizeUrl($state, $verifier));
    exit;
}

if (isset($_GET['code'])) {
    // 3-4. 回调:校验 state + 换 token
    if ($_GET['state'] !== $_SESSION['oauth_state']) {
        die('State 校验失败');
    }

    $tokenRes = $um->token($_GET['code'], $_SESSION['oauth_verifier']);
    if ($tokenRes['code'] !== 0) {
        die('换取 token 失败:' . $tokenRes['msg']);
    }

    // 5. 获取用户信息
    $user = $um->userinfo($tokenRes['access_token']);

    // 清理 PKCE 临时数据
    unset($_SESSION['oauth_state'], $_SESSION['oauth_verifier']);

    // 存储登录态
    $_SESSION['access_token']  = $tokenRes['access_token'];
    $_SESSION['refresh_token'] = $tokenRes['refresh_token'];
    $_SESSION['user']          = $user;

    echo "登录成功!<br>";
    echo "昵称:{$user['nickname']}<br>";
    echo "UMID:{$user['sub']}<br>";
    echo "头像:<img src='{$user['picture']}' width=64><br>";
}

扫码登录(二维码图片 · 兼容方式)

适合 PC 端不想跳转授权页的场景,直接 <img> 渲染二维码:

$qrUrl = $um->qrcodeUrl('wx', 200, 'state-xyz');
echo '<img src="' . htmlspecialchars($qrUrl) . '" width="200" height="200" alt="登录二维码">';

用户扫码后 UM 按 redirect_uri 回调 code,后续走上面的「5 步对接」第 3 步起。


用通用 OAuth 库接入(推荐)

UM 是标准 OAuth 2.1 + OIDC 服务,可直接用通用库接入,无需安装 UM SDK:

  • Next.js / Auth.js:配置 provider: um({ issuer: 'https://um.yunjii.cn' })
  • Python / authliboauth.register('um', server_metadata_url='https://um.yunjii.cn/.well-known/openid-configuration', ...)
  • Spring SecurityClientRegistration.withIssuer('https://um.yunjii.cn')...

通用库自动从 OIDC Discovery 读取所有端点配置。


常见问题

问题原因解决
errcode=102appid 不存在或应用未审核检查 appid,确认应用状态为"运行中"
errcode=103client_secret 不正确检查 appkey
errcode=104code 不存在/未授权/已过期code 5 分钟过期,重新发起授权
errcode=105timestamp 过期(旧版 REST)保证服务器时间正确,5 分钟内有效
errcode=107PKCE code_verifier 校验失败检查 verifier 与 challenge 是否匹配
errcode=40163code 重复消费code 只能用一次,5 分钟过期

下一步