接入
UC Card 快捷登录
让用户使用 UC Card 账号登录你的网站或 App,基于 OAuth 2.0 和 OpenID Connect。
UC Card 快捷登录让用户使用已有的 UC Card 账号登录你的网站或 App,无需再注册新的用户名和密码。
UC Card 是基于 OAuth 2.0 的 OpenID Connect(OIDC)身份提供方。作为 UC Card Partner,你只需在登录页添加 「使用 UC Card 继续」 按钮,并采用标准的授权码模式 + PKCE,任何通过认证的 OIDC 库均可使用。
用户登录并授权你的应用后,你将获得:
- ID Token:签名的 JWT(
RS256),通过sub标识用户。同一用户的sub永久不变,且在你的开发者账号下唯一。 - 用户资料:如姓名、头像,仅包含用户已授权的 scope。
- Access Token:用于调用用户信息接口;申请
offline_access时还会返回 Refresh Token。
快捷登录可以单独使用,也可以与现有登录方式并存。它也是收款的前提:支付接口通过 sub 识别用户。
工作原理
- 用户在你的登录页点击 「使用 UC Card 继续」。
- 你的服务端把用户重定向到 UC Card,用户使用 UC Card 账号登录(或已处于登录状态)并授权你的 App。
- UC Card 携带一次性
code重定向回你的redirect_uri。 - 你的服务端用 code 换取令牌,并从
id_token中读取用户的sub。 - 按
sub在数据库中查找或创建用户,并建立你自己的会话。
用户需要拥有 UC Card 账号
只有 UC Card 用户可以使用此按钮。请为其他用户保留原有登录方式,或引导他们在 UC Card App 中注册账号。
准备工作
在控制台创建 App
在开发者控制台创建 App(见控制台配置),获得 client_id;服务端 App 还会获得 client_secret。
登记回调地址
精确登记所有回调地址,例如 https://partner.example.com/auth/uccard/callback。UC Card 只会重定向到已登记的地址。
添加测试用户
新 App 处于沙箱状态:在审核发布前,只有你本人和最多 20 名测试用户可以登录。
设计规范
在登录和注册页面放置 「使用 UC Card 继续」 按钮,链接到你自己服务端上发起登录流程的路由(下文为 /auth/uccard/login)。HTML 和 CSS 可从登录按钮生成器获取。
下方示意图展示按钮在 UC Card Partner 网站桌面端和移动端上的样式,以及用户点击后看到的界面。
欢迎回来
登录你的账号。
你将跳转到 UC Card 完成登录。
还没有账号?立即注册
按钮放在你自己的登录表单下方,用「或」分隔,宽度一致。
欢迎回来
登录你的账号。
你将跳转到 UC Card 完成登录。
还没有账号?立即注册
按钮占满宽度、便于拇指点击,并保留下方提示文字。
UC Card Partner 请求访问你的 UC Card 账号
UC Card Partner 将可以:
- 查看你的姓名和头像
- 使用唯一标识识别你的身份
🔒 UC Card 不会分享你的密码或支付 PIN。
继续即表示你同意 UC Card Partner 的隐私政策和服务条款。
用户接下来看到的 UC Card 授权卡片:展示你的应用名称、标志和申请的数据。
| 推荐 | 避免 |
|---|---|
| 在登录和注册页面都放置按钮 | 把按钮藏在「更多方式」链接后面 |
| 用 「或」 分隔线与你自己的表单隔开 | 放在密码输入框内部或上方 |
| 与你自己的登录按钮宽度一致 | 比其他登录按钮更小 |
| 移动端占满宽度,放在拇指易点击的位置 | 在小屏幕上放到需要滚动才能看到的位置 |
| 保留提示「你将跳转到 UC Card 完成登录。」 | 使用「HTP」或其他名称,名称始终为 UC Card |
| 在控制台上传应用名称和标志,它们会显示在 UC Card 授权卡片上(第 3 步) | 使用与你网站不一致的名称或标志 |
UC Card 授权卡片上的应用名称和标志
UC Card 登录卡片展示的是你在控制台 App 资料中填写的名称、标志和申请的数据。已发布 App 修改这些信息需重新审核。
服务端接入
任何通过认证的 OpenID Connect 库都可以使用:配置发现地址即可自动获取所有端点。以下是使用 openid-client v6 的完整 Node.js(Express)示例,它会自动处理 PKCE、state、nonce 和 ID Token 校验。
import express from 'express';
import session from 'express-session';
import * as client from 'openid-client';
const config = await client.discovery(
new URL('https://auth.htp.example'),
process.env.UCCARD_CLIENT_ID,
process.env.UCCARD_CLIENT_SECRET,
);
const REDIRECT_URI = 'https://partner.example.com/auth/uccard/callback';
const app = express();
app.use(session({ secret: process.env.SESSION_SECRET, resave: false, saveUninitialized: false }));
// 1. 按钮链接到这里
app.get('/auth/uccard/login', async (req, res) => {
const verifier = client.randomPKCECodeVerifier();
req.session.oidc = { verifier, state: client.randomState(), nonce: client.randomNonce() };
const url = client.buildAuthorizationUrl(config, {
redirect_uri: REDIRECT_URI,
scope: 'openid profile',
code_challenge: await client.calculatePKCECodeChallenge(verifier),
code_challenge_method: 'S256',
state: req.session.oidc.state,
nonce: req.session.oidc.nonce,
});
res.redirect(url.href);
});
// 2. UC Card 重定向回这里
app.get('/auth/uccard/callback', async (req, res) => {
const { verifier, state, nonce } = req.session.oidc ?? {};
const tokens = await client.authorizationCodeGrant(config, new URL(req.originalUrl, 'https://partner.example.com'), {
pkceCodeVerifier: verifier,
expectedState: state,
expectedNonce: nonce,
});
const claims = tokens.claims(); // 已校验的 id_token
const user = await db.users.findOrCreateBySub(claims.sub, { name: claims.name, picture: claims.picture });
delete req.session.oidc;
req.session.userId = user.id;
res.redirect('/');
});其他语言
任何通过 OIDC 认证的库均可:Authlib(Python)、coreos/go-oidc + golang.org/x/oauth2(Go)、league/oauth2-client(PHP)、Spring Security OAuth2 Client(Java)、AppAuth(iOS/Android)。配置发现地址、client_id / client_secret 并启用 PKCE S256 即可。
端点
用发现文档配置你的 OIDC 库:
GET https://auth.htp.example/.well-known/openid-configuration| 用途 | 路径 |
|---|---|
| 授权 | /oauth2/authorize |
| 令牌 | /oauth2/token |
| 用户信息 | /oauth2/userinfo |
| 公钥(JWKS) | /oauth2/jwks |
| 撤销 | /oauth2/revoke |
授权码模式 + PKCE S256(SPA / 原生 App 必须,Web 推荐)。ID Token 使用 RS256 签名。客户端认证:client_secret_basic(推荐)、client_secret_post,公开客户端为 none。
Scope
| Scope | Claims |
|---|---|
openid(必填) |
sub |
profile |
name、given_name、family_name、nickname、picture、gender、birthdate、updated_at |
email |
email、email_verified —— 需审核 |
phone |
phone_number、phone_number_verified —— 需审核 |
offline_access |
返回 refresh_token |
开放平台 App 默认可用 openid profile offline_access。只申请你需要的 scope,用户会在授权页看到你申请的权限。
原始流程
如果不使用库,实际的请求如下:
GET https://auth.htp.example/oauth2/authorize
?response_type=code
&client_id=<client_id>
&redirect_uri=https%3A%2F%2Fpartner.example.com%2Fauth%2Fuccard%2Fcallback
&scope=openid%20profile%20offline_access
&state=<state>
&nonce=<nonce>
&code_challenge=<code_challenge>
&code_challenge_method=S256回调时校验 state 和 iss,然后用授权码换取令牌(只能使用一次,5 分钟内有效):
curl -X POST https://auth.htp.example/oauth2/token \
-u "<client_id>:<client_secret>" \
-d grant_type=authorization_code \
-d code=<code> \
-d redirect_uri=https://partner.example.com/auth/uccard/callback \
-d code_verifier=<code_verifier>校验 id_token(用 JWKS 验签,校验 iss、aud = 你的 client_id、exp、nonce),然后读取 sub。
关联已有账号
如果你已有自己的账号体系,可让已登录用户在账号设置中绑定 UC Card:把 sub 保存到现有用户记录上,之后用户点击按钮时按 sub 匹配。
不要按邮箱自动合并账号
不要仅因邮箱相同就把 UC Card 登录关联到已有账号。应先让用户登录已有账号,再绑定 UC Card。
sub 是 pairwise 的
- 同一开发者的所有 App 拿到同一用户的同一个
sub,可以在你的多个 App 间共享用户。 - 不同开发者拿到的
sub不同 —— 无法跨开发者关联用户。 sub永久不变。请与用户记录一起保存;如果同时接入收付款,将其作为payer_sub/payee_sub传入。
用户可以取消授权
用户可在 UC Card App 的「已授权应用」中移除你的 App。之后 refresh token 和 userinfo 失效,你也无法再向该用户收款或付款(USER_NOT_AUTHORIZED),直到用户重新登录。
沙箱 App
App 发布前,只有你本人和测试用户能登录,其他人返回 access_denied。登录页会向用户标注该应用尚未经过 UC Card 审核。