Developer Guide
SSO API 对接文档
本文档说明如何将业务系统(Web 后台、移动 App、内部服务)接入 https://sso.xahrf.cn 企业统一身份平台。 平台提供 OAuth2 授权码单点登录,以及 REST JSON API 供 App 直接登录与组织数据查询。
概述
统一身份平台负责账号、部门、角色与应用权限管理。业务系统不再维护独立账号体系,通过以下能力完成认证与授权:
Web 单点登录
浏览器跳转 OAuth2 授权码流程,用户在 SSO 登录后自动回到业务系统。
App 账号密码登录
移动 App 或产线客户端调用 REST API,提交账号密码换取 access_token。
组织数据 API
按登录用户权限返回可见部门及员工列表,供任务分配、数据隔离等场景使用。
扫码登录
电脑端展示二维码,手机 App 或浏览器扫码确认,PC 自动完成 Web 会话登录。
/oauth/*)遵循标准 Bearer Token;REST API(/api/*)统一返回
{"ok": true/false, ...} 格式,并支持 CORS 跨域(Access-Control-Allow-Origin: *)。
接入准备
-
在管理后台创建应用
路径:管理后台 → 身份与权限 → 应用管理 → 新建应用。协议选择
OAuth2,记录client_id与client_secret。 -
配置回调地址
在应用的「回调地址 / Redirect URIs」中填写业务系统授权回调 URL,须与请求参数
redirect_uri完全一致。可配置多个,例如:https://your-app.example.com/oauth/callback.php https://your-app.example.com/oauth/index.php -
分配应用访问权限
为员工或角色勾选该应用的访问权限。未授权用户在登录时将收到
access_denied错误。 -
业务系统保存配置
在业务系统配置文件中写入 SSO 地址、
client_id、client_secret及回调地址。
认证方式对比
| 场景 | 推荐方式 | 主要接口 |
|---|---|---|
| Web 管理后台、浏览器应用 | OAuth2 授权码 | /oauth/authorize.php → /oauth/token.php |
| 移动 App、产线客户端 | REST 账号密码登录 | POST /api/auth/login.php |
| 桌面端 / 大屏 / 第三方客户端 | 扫码登录 API | POST /api/auth/qr/create.php → 轮询 → 获取 access_token |
| Web 登录页扫码(SSO 门户) | 扫码登录 Web 模式 | POST /api/auth/qr/create.php(无 client_id)→ Session 轮询 |
| 获取当前用户信息 | Bearer Token | /api/auth/userinfo.php 或 /oauth/userinfo.php |
| 服务端拉取组织架构 | 用户 Token 或服务端凭证 | GET /api/org/departments.php |
OAuth2 授权码流程(Web SSO)
适用于浏览器端单点登录,流程如下:
用户访问业务系统
→ 业务系统重定向到 SSO 授权页
→ 用户在 SSO 登录(若未登录)
→ SSO 302 跳回 redirect_uri?code=...&state=...
→ 业务系统服务端用 code 换取 access_token
→ 业务系统拉取用户信息并建立本地会话
Step 1:发起授权
将用户浏览器重定向至:
GET https://sso.xahrf.cn/oauth/authorize.php
?response_type=code
&client_id={client_id}
&redirect_uri={url_encoded_redirect_uri}
&state={random_state}
&scope=openid profile
| 参数 | 必填 | 说明 |
|---|---|---|
response_type | 是 | 固定为 code |
client_id | 是 | 应用 Client ID |
redirect_uri | 是 | 须与后台登记的回调地址完全一致 |
state | 推荐 | 随机字符串,回调时原样返回,用于防 CSRF |
scope | 否 | 可选,如 openid profile |
若用户未登录 SSO,会先跳转到登录页,登录成功后继续授权。授权成功后将 302 跳转至:
{redirect_uri}?code={authorization_code}&state={state}
Step 2:校验 state
业务系统回调页必须校验 state 与发起授权时存入 Session 的值一致,否则应拒绝处理。
换取 Access Token
POST https://sso.xahrf.cn/oauth/token.php
Content-Type: application/x-www-form-urlencoded
grant_type=authorization_code
&code={authorization_code}
&client_id={client_id}
&client_secret={client_secret}
&redirect_uri={redirect_uri}
成功响应(HTTP 200):
{
"access_token": "64位十六进制字符串",
"token_type": "Bearer",
"expires_in": 3600,
"scope": "openid profile"
}
失败时返回 {"error": "invalid_grant"} 等 OAuth 标准错误(HTTP 400)。
OAuth 用户信息
GET https://sso.xahrf.cn/oauth/userinfo.php
Authorization: Bearer {access_token}
也支持 Query / Body 传参:access_token={token}
成功响应示例:
{
"sub": "6",
"username": "zhangsan",
"name": "张三",
"email": "zhangsan@example.com",
"employee_no": "E001",
"dept_id": 7,
"roles": ["employee"]
}
账号密码登录 API
适用于 App、产线客户端等无法使用浏览器跳转的场景。与 OAuth 共用同一套 Token 存储。
POST https://sso.xahrf.cn/api/auth/login.php
Content-Type: application/json
请求体
账号标识 三选一(不可同时传多个),均需配合 password 与 client_id:
{
"username": "zhangsan",
"password": "your_password",
"client_id": "your_app_client",
"client_secret": "应用密钥(后台配置了则必填)"
}
或使用手机号 / 邮箱:
{ "mobile": "13800138000", "password": "...", "client_id": "...", "client_secret": "..." }
{ "email": "user@example.com", "password": "...", "client_id": "...", "client_secret": "..." }
成功响应
{
"ok": true,
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"user": {
"id": 6,
"username": "zhangsan",
"display_name": "张三",
"employee_no": "E001",
"email": "",
"mobile": "13800138000",
"account_type": "formal",
"status": "active",
"dept_id": 7,
"dept_name": "大表生产部",
"position_id": 1,
"position_name": "操作工",
"roles": ["employee"]
}
}
REST 用户信息
GET https://sso.xahrf.cn/api/auth/userinfo.php
Authorization: Bearer {access_token}
支持 GET 或 POST,Token 也可通过 Query / Body 的 access_token 传递。
{
"ok": true,
"sub": "6",
"user": {
"id": 6,
"username": "zhangsan",
"display_name": "张三",
"dept_id": 7,
"dept_name": "大表生产部",
"roles": ["dept_leader"]
}
}
REST 登出(撤销 Token)
POST https://sso.xahrf.cn/api/auth/logout.php
Authorization: Bearer {access_token}
或在 Body 中传 {"access_token": "..."}
{
"ok": true,
"revoked": true
}
revoked: false 表示 Token 已失效或不存在,可视为已登出。
组织部门 API
返回部门列表及各部门下的员工(仅含 employee 角色用户),用于任务分配、按部门隔离数据等。
GET https://sso.xahrf.cn/api/org/departments.php
Authorization: Bearer {access_token}
认证方式
| 方式 | 说明 | 数据范围 scope |
|---|---|---|
| 用户 Bearer Token | 携带登录用户的 access_token | all(平台管理员)或 department(仅本部门) |
| 服务端凭证 | Query:client_id + client_secret |
service(全租户部门,不含用户上下文) |
成功响应
{
"ok": true,
"scope": "department",
"departments": [
{
"id": 7,
"name": "大表生产部",
"code": "dabiao",
"parent_id": 1,
"users": [
{
"id": 12,
"username": "lisi",
"display_name": "李四",
"employee_no": "E012",
"dept_id": 7,
"roles": ["employee"]
}
]
}
]
}
super_admin:可见全部部门(scope=all)- 其他角色(含
dept_leader):仅可见本人所在部门(scope=department) - 各部门
users仅包含角色为employee的在职员工
扫码登录 API
支持两种模式:Web 模式(SSO 登录页 / 浏览器 Session)与 API 模式(第三方应用传入 client_id,轮询获取 access_token)。手机端确认方式共用。
| 模式 | 创建参数 | 轮询参数 | 确认后获得 |
|---|---|---|---|
web |
不传 client_id,需浏览器 Cookie |
qr_token + 同一浏览器 Session |
Web Session + redirect |
api |
client_id + client_secret |
qr_token + poll_key |
access_token + user(与密码登录相同) |
模式 A:Web 扫码(SSO 登录页)
PC 浏览器 手机 / App SSO
|-- POST /api/auth/qr/create (无 client_id) ----------------->|
|<- qr_token, qr_url, mode=web ------------------------------|
| |-- 扫码 / confirm ------------>|
|-- GET /api/auth/qr/status?qr_token=... (Cookie 轮询) ------>|
|<- status=confirmed, redirect ------------------------------|
POST https://sso.xahrf.cn/api/auth/qr/create.php
Content-Type: application/json
Cookie: UNIFIED_SSO_SID=...
{ "redirect": "/" }
{
"ok": true,
"mode": "web",
"qr_token": "...",
"qr_url": "https://sso.xahrf.cn/qr/scan.php?token=...",
"expires_in": 120,
"poll_interval": 2}
GET https://sso.xahrf.cn/api/auth/qr/status.php?qr_token={qr_token}
Cookie: UNIFIED_SSO_SID=...
模式 B:API 扫码(第三方应用对接)
桌面/大屏 App 手机 App SSO
|-- POST /api/auth/qr/create (client_id) -------------------->|
|<- qr_token, qr_url, poll_key, mode=api --------------------|
| (展示 qr_url 二维码) | |
| |-- POST /api/auth/qr/confirm ->|
|-- GET /api/auth/qr/status?qr_token&poll_key (轮询) -------->|
|<- access_token, user ----------------------------------------|
POST https://sso.xahrf.cn/api/auth/qr/create.php
Content-Type: application/json
{
"client_id": "your_app_client",
"client_secret": "应用密钥(若后台配置了则必填)"
}
{
"ok": true,
"mode": "api",
"qr_token": "...",
"qr_url": "https://sso.xahrf.cn/qr/scan.php?token=...",
"poll_key": "32位十六进制轮询密钥",
"expires_in": 120,
"poll_interval": 2}
poll_key 仅创建时返回一次,请客户端本地安全保存,用于后续轮询,不可泄露给手机端。GET https://sso.xahrf.cn/api/auth/qr/status.php?qr_token={qr_token}&poll_key={poll_key}
确认成功后首次轮询返回(与 /api/auth/login.php 结构一致):
{
"ok": true,
"status": "confirmed",
"access_token": "...",
"token_type": "Bearer",
"expires_in": 3600,
"user": {
"id": 6,
"username": "zhangsan",
"display_name": "张三",
"dept_id": 7,
"dept_name": "大表生产部",
"roles": ["employee"]
}
}
再次轮询时返回 status=confirmed 及提示「access_token 已发放」,不会重复签发令牌。
手机端确认(两种模式共用)
方式 A — 手机浏览器扫码:打开 qr_url,输入 SSO 账号密码确认。
方式 B — 企业 App API:
POST https://sso.xahrf.cn/api/auth/qr/confirm.php
Authorization: Bearer {access_token}
Content-Type: application/json
{ "qr_token": "..." }
也支持 Body 传 username + password。API 模式下会校验确认用户是否拥有该 client_id 应用访问权限。
标记已扫码(可选)
POST https://sso.xahrf.cn/api/auth/qr/scan.php
Content-Type: application/json
{ "qr_token": "..." }
状态说明
| status | 含义 |
|---|---|
pending | 待扫码 |
scanned | 已扫码,待手机确认 |
confirmed | 已确认(Web 返回 redirect;API 返回 access_token) |
expired | 已过期,需重新 create |
- 二维码有效期 120 秒
- Web 模式:
qr_token与浏览器 Session 绑定 - API 模式:须同时持有
qr_token与poll_key方可轮询 - 确认用户须为在职账号(
status=active)且拥有目标应用权限
全局单点登出
业务系统退出时,若需同时注销 SSO 会话及所有已签发的 Token,可将用户重定向至:
GET https://sso.xahrf.cn/logout.php?redirect={url_encoded_return_url}
SSO 会撤销当前用户全部 OAuth Token 与 Web Session,然后跳转到 redirect 指定地址。
redirect 仅允许 https 协议且域名为 xahrf.cn 或其子域(如 sf6.xahrf.cn),防止开放重定向攻击。
典型用法:业务系统 logout.php 先撤销本地 Token,再跳转:
https://sso.xahrf.cn/logout.php?redirect=https://your-app.xahrf.cn/login.php
角色与数据范围
| 角色 code | 说明 | 典型用途 |
|---|---|---|
super_admin | 平台超级管理员 | 管理 SSO 后台、可见全部组织数据 |
dept_leader | 部门负责人 | Web 后台主管权限,组织 API 仅返回本部门 |
employee | 普通员工 | 产线 App 登录,通常不允许 Web 后台 |
业务系统可根据 user.roles 映射本地角色,例如:
super_admin → admin
dept_leader → supervisor
employee → employee(仅 App)
错误码
REST API(/api/*)
| error | HTTP | 说明 |
|---|---|---|
invalid_request | 400 | 参数缺失或格式错误 |
invalid_client | 401 | client_id / client_secret 无效 |
invalid_credentials | 401 | 账号或密码错误 |
invalid_token | 401 | Token 缺失、无效或已过期 |
access_denied | 403 | 用户无权访问该应用 |
method_not_allowed | 405 | HTTP 方法不正确 |
错误响应格式:
{
"ok": false,
"error": "invalid_credentials",
"message": "用户名或密码错误"
}
OAuth 接口(/oauth/*)
返回标准 OAuth2 错误字段 error,如 invalid_grant、unsupported_grant_type、invalid_token。
调用示例
cURL:App 登录
curl -s -X POST 'https://sso.xahrf.cn/api/auth/login.php' \
-H 'Content-Type: application/json' \
-d '{
"username": "zhangsan",
"password": "your_password",
"client_id": "your_app_client",
"client_secret": "your_client_secret"
}'
cURL:获取部门列表
curl -s 'https://sso.xahrf.cn/api/org/departments.php' \
-H 'Authorization: Bearer YOUR_ACCESS_TOKEN'
cURL:API 扫码登录(创建 + 轮询)
# 1. 创建二维码
curl -s -X POST 'https://sso.xahrf.cn/api/auth/qr/create.php' \
-H 'Content-Type: application/json' \
-d '{"client_id":"your_app_client","client_secret":"your_client_secret"}'
# 2. 轮询(使用返回的 qr_token 与 poll_key)
curl -s 'https://sso.xahrf.cn/api/auth/qr/status.php?qr_token=QR_TOKEN&poll_key=POLL_KEY'
cURL:OAuth 换 Token
curl -s -X POST 'https://sso.xahrf.cn/oauth/token.php' \
-d 'grant_type=authorization_code' \
-d 'code=AUTHORIZATION_CODE' \
-d 'client_id=your_app_client' \
-d 'client_secret=your_client_secret' \
-d 'redirect_uri=https://your-app.xahrf.cn/oauth/callback.php'
PHP:发起 SSO 授权(Web)
$state = bin2hex(random_bytes(16));
$_SESSION['oauth_state'] = $state;
$params = http_build_query([
'response_type' => 'code',
'client_id' => SSO_CLIENT_ID,
'redirect_uri' => SSO_REDIRECT_URI,
'state' => $state,
'scope' => 'openid profile',
]);
header('Location: ' . SSO_BASE_URL . '/oauth/authorize.php?' . $params);
exit;
接入检查清单
- 已在 SSO 管理后台创建 OAuth2 应用并记录 client_id / client_secret
- redirect_uri 已在后台登记,且与代码中完全一致(含协议、路径、末尾斜杠)
- 目标用户已分配该应用的访问角色
- Web 接入已实现 state 校验与 Token 安全存储(Session / 服务端)
- App 接入使用 HTTPS,client_secret 保存在服务端或安全存储中
- 登出流程已对接全局 logout(如需单点登出)
- 业务系统已根据 roles / dept_id 实现本地权限与数据隔离
- 生产环境已启用 HTTPS,并限制 install.php 访问