企业统一身份平台

Developer Guide

SSO API 对接文档

本文档说明如何将业务系统(Web 后台、移动 App、内部服务)接入 https://sso.xahrf.cn 企业统一身份平台。 平台提供 OAuth2 授权码单点登录,以及 REST JSON API 供 App 直接登录与组织数据查询。

Base URL:https://sso.xahrf.cn Token 有效期:3600 秒 授权码有效期:600 秒 扫码有效期:120 秒

概述

统一身份平台负责账号、部门、角色与应用权限管理。业务系统不再维护独立账号体系,通过以下能力完成认证与授权:

Web 单点登录

浏览器跳转 OAuth2 授权码流程,用户在 SSO 登录后自动回到业务系统。

App 账号密码登录

移动 App 或产线客户端调用 REST API,提交账号密码换取 access_token

组织数据 API

按登录用户权限返回可见部门及员工列表,供任务分配、数据隔离等场景使用。

扫码登录

电脑端展示二维码,手机 App 或浏览器扫码确认,PC 自动完成 Web 会话登录。

说明:OAuth 接口(/oauth/*)遵循标准 Bearer Token;REST API(/api/*)统一返回 {"ok": true/false, ...} 格式,并支持 CORS 跨域(Access-Control-Allow-Origin: *)。

接入准备

  1. 在管理后台创建应用

    路径:管理后台 → 身份与权限 → 应用管理 → 新建应用。协议选择 OAuth2,记录 client_idclient_secret

  2. 配置回调地址

    在应用的「回调地址 / Redirect URIs」中填写业务系统授权回调 URL,须与请求参数 redirect_uri 完全一致。可配置多个,例如:

    https://your-app.example.com/oauth/callback.php
    https://your-app.example.com/oauth/index.php
  3. 分配应用访问权限

    为员工或角色勾选该应用的访问权限。未授权用户在登录时将收到 access_denied 错误。

  4. 业务系统保存配置

    在业务系统配置文件中写入 SSO 地址、client_idclient_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}
授权码一次性有效,有效期 600 秒,请尽快换取 Token。

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

请求体

账号标识 三选一(不可同时传多个),均需配合 passwordclient_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_tokenpoll_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/*)

errorHTTP说明
invalid_request400参数缺失或格式错误
invalid_client401client_id / client_secret 无效
invalid_credentials401账号或密码错误
invalid_token401Token 缺失、无效或已过期
access_denied403用户无权访问该应用
method_not_allowed405HTTP 方法不正确

错误响应格式:

{
  "ok": false,
  "error": "invalid_credentials",
  "message": "用户名或密码错误"
}

OAuth 接口(/oauth/*)

返回标准 OAuth2 错误字段 error,如 invalid_grantunsupported_grant_typeinvalid_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 访问