外观
OPC · SSO
统一登录接入(SSO)
让访客用沉思波账号登录你的网站——授权码模式,你的服务端拿授权码换令牌、再取身份,浏览器全程拿不到 secret。
SSO计费
前提
已在控制台「开放能力」建好应用,手里有 site_key(公开)与 secret(仅服务端);建应用时登记了回跳地址(allowed_origins 或站点地址,写进应用的允许来源)。
有后端才能走完整链路(code 换令牌必须在服务端做)。纯前端站见下文「没有后端怎么办」。
授权码时序
text
用户浏览器 你的前端 你的服务端 沉思波
| 点「用沉思波登录」 | | |
|------------------>| 跳转授权地址 | |
|----------------------------------------|----------------->|
| (未登录则先到沉思波登录页,登录后回跳授权地址) |
|<----------------------------------------------------------|
| 302 回你的 redirect_uri?code=...&state=... |
|------------------>| 把 code 交给服务端 | |
| |------------------->| POST /sso/token |
| | |------------------>|
| | |<------------------|
| | | access_token+user |
| |<-------------------| (写入会话/下发) |
|<------------------| 进入已登录态 | |三个关键点
授权码(code)一次性、约 90 秒过期,只能在你的服务端用一次,用完作废。
state 原样回显:你发起授权时带一串随机 state,回跳时校验一致,防跨站请求伪造(CSRF)。
redirect_uri 登记制:回跳地址必须与应用登记的允许来源精确同源(登记了完整回调地址则精确相等,登记了域名则该域下任意路径均可),没登记的地址直接拒。
接口契约
开放接口前缀以你部署的 community-api 为准(官网同源 /api/open/...)。路径与参数与服务端实现对齐,变更以控制台公告为准。
1. 发起授权(浏览器跳转)
http
GET /api/open/sso/authorize
?client_id={site_key}
&redirect_uri={你登记的回跳地址}
&state={随机串}
&scope={可选}- 未登录:302 到沉思波登录页(带回跳);已登录:302 到
redirect_uri,带上code与state; - 浏览器 fetch 场景可加
?json=1(或Accept: application/json),未登录回 401 +loginUrl,成功回 JSON:
json
{
"redirect": "https://your.example/callback?code=opc_code_...&state=abc",
"code": "opc_code_...",
"state": "abc",
"expires_in": 90
}2. 授权码换令牌(仅服务端)
http
POST /api/open/sso/token
Content-Type: application/json
{
"code": "opc_code_...",
"client_id": "{site_key}",
"client_secret": "{secret,只在这里出现}",
"redirect_uri": "https://your.example/callback"
}成功响应:
json
{
"access_token": "opc_at_...",
"token_type": "Bearer",
"expires_in": 7200,
"scope": "",
"user": { "id": 12, "nickname": "示例用户", "avatar": null }
}失败回 401,文案统一为「授权码无效或已过期」(不区分是密钥错还是码错——不给试探留缝)。
3. 取用户信息
http
GET /api/open/sso/userinfo
Authorization: Bearer {access_token}json
{
"id": 12,
"nickname": "示例用户",
"avatar": null,
"email_masked": "ab***@cd.com"
}邮箱一律脱敏,不回明文。
4. 吊销令牌(可选)
http
POST /api/open/sso/revoke
Content-Type: application/json
{ "access_token": "opc_at_..." }回 { "ok": true }——成功失败都只回这一句,不区分令牌是否存在。
服务端示例(Node)
js
// 仅示意:secret 从环境变量读,不写进代码仓库
async function exchangeCode(code, redirectUri) {
const r = await fetch('https://your-api-host/api/open/sso/token', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({
code,
client_id: process.env.OPC_SITE_KEY,
client_secret: process.env.OPC_SECRET,
redirect_uri: redirectUri
})
})
if (!r.ok) throw new Error('授权码兑换失败')
return r.json() // { access_token, user: { id, nickname, avatar } }
}两种接法
有后端(推荐)
完整链路:前端只把用户导向授权地址(带 client_id / redirect_uri / state)。code 回跳到你的回调接口,服务端兑换令牌、建自己的会话,之后怎么管登录态是你的事。
纯前端(没有后端)
secret 不能进浏览器,没法安全地走 code 换令牌。两条务实路线:
1)只做「跳过去登录」:跳授权地址,用户在沉思波侧登录后回跳你的静态页——适合「引导注册 / 领取」这类不要求站内登录态的场景;
2)登录交给托管侧或后端即服务:把兑换动作放在任意一处你信任的服务端(云函数、小后端),前端只收「已登录」的结果。
常见坑
redirect_uri没登记:回 400「redirect_uri 未在应用登记范围内」——建应用时就把回调地址写进允许来源,改地址先去后台改登记;- state 不校验:等于把登录接口开给跨站伪造;state 用随机串、绑定会话、回跳时比对;
- code 重复使用:code 一次一用,第二次兑换必失败;重试要走完整授权,不要重放旧 code;
- token 过期不续:
access_token默认约 2 小时(以响应expires_in为准),过期就重新走授权码流,别当永久票据; - 把
secret写进前端或命令行历史:见下文安全边界。
安全边界
红线
secret 只在服务端:不进前端仓库、不进页面、不进 URL、不进日志;只在 code 换令牌时出现在请求体里。
泄露就轮换:secret 一旦可能外泄,到后台 · 密钥与轮换轮换,旧值立即作废。
令牌当凭证保管:access_token 等同登录态,只走 HTTPS,只存在你的服务端或 HttpOnly Cookie 里。
我们不代管你的业务数据:SSO 只给身份字段(标识、昵称、脱敏邮箱一类),你的用户资料、订单、内容归你自己管。隐私口径见隐私政策。

本页讨论
0 条评论还没有评论,来说第一句。