统一认证平台接入流程及API接口文档(1)(1).md 20 KB

统一认证平台(LQAI-middle-platform)接入流程及 API 接口文档

参考样本: 样本中心(LQAdminPlatform)已实现的统一认证接入方案 统一认证平台地址: http://192.168.92.61:8200 统一认证平台前端: http://192.168.92.61:9200


一、系统架构概览

┌─────────────────────────────────────────────────────────────┐
│                统一认证平台 (LQAI-middle-platform)            │
│                    端口: 8200 (后端) / 9200 (前端)            │
│                                                             │
│  功能:                                                       │
│  • 用户注册 / 登录 / 密码管理                                  │
│  • 应用管理 (子应用注册、client_id/secret 生成)                │
│  • OAuth2 授权码流程                                          │
│  • RBAC 角色权限管理                                          │
│  • JWT Token 签发与验证                                       │
│  • 子应用工作台(点击子应用图标触发 SSO 跳转)                  │
│                                                             │
│  数据存储: MySQL (lq_ai_middle_platform) + Redis             │
└──────────────────────┬──────────────────────────────────────┘
                       │ OAuth2 / HTTP
                       │
        ┌──────────────┼──────────────┐
        │              │              │
   ┌────▼────┐  ┌─────▼─────┐  ┌────▼────┐
   │样本中心  │  │Agent平台   │  │ 标注平台 │  ... 其他子系统
   │(8000)   │  │ (8002)    │  │ (9003)  │
   └─────────┘  └───────────┘  └─────────┘

角色定位

角色 说明
统一认证平台 (LQAI-middle-platform) OAuth2 授权服务器(Authorization Server),同时也是一个 SSO 中心
子系统 (如样本中心 LQAdminPlatform) OAuth2 客户端(Client),同时自身也是一个小型 OAuth2 服务器,可以为下游系统提供授权
子系统前端 负责 SSO 回调处理和 Token 交换

二、SSO 单点登录接入流程

2.1 整体流程图

用户在统一认证平台工作台点击子系统图标
            │
            ▼
① 统一认证平台后端生成 OAuth2 授权码 code
   POST /auth/sso-redirect  →  返回重定向URL: {frontend_url}/auth/callback?code=xxx
            │
            ▼
② 302 重定向到子系统前端 /auth/callback?code=xxx
            │
            ▼
③ 子系统前端 POST /api/oauth/exchange-code { "code": "xxx" }
            │
            ▼
④ 子系统后端与统一认证平台进行后端到后端通信:
   4a. POST {SSO_BASE_URL}/oauth/token  →  换取 SSO access_token
   4b. GET  {SSO_BASE_URL}/oauth/userinfo →  获取用户信息+角色
            │
            ▼
⑤ 子系统后端同步用户到本地数据库(查找或创建用户、同步角色)
            │
            ▼
⑥ 子系统后端签发本地 JWT,返回 { token, refresh_token, user }
            │
            ▼
⑦ 子系统前端保存 Token,跳转首页

2.2 详细步骤说明

Step 1: 统一认证平台生成授权码

当用户在统一认证平台前端工作台的"应用列表"中点击某个子系统图标时:

  • 统一认证平台后端调用 POST /auth/sso-redirect 接口
  • 后端为当前登录用户生成一个 OAuth2 授权码(authorization code),存入 Redis,有效期 10 分钟
  • 返回子系统的回调 URL,格式为 {REDIRECT_URI}?code={auth_code}

Step 2: 重定向到子系统前端

  • 统一认证平台前端通过 302 重定向将用户引导至子系统前端的回调页面
  • URL 格式: http://localhost:3000/auth/callback?code=xxxxxx

Step 3: 子系统前端调用换码接口

子系统前端从 URL 参数中提取 code,调用子系统后端的换码接口:

// 示例代码
const code = new URLSearchParams(window.location.search).get('code');
const response = await fetch('/api/oauth/exchange-code', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ code })
});
const result = await response.json();
// result.data.token       → 本地 JWT access_token
// result.data.refresh_token → 刷新令牌
// result.data.user         → 用户信息(含角色)

Step 4-5: 子系统后端与统一认证平台交互 + 同步用户

子系统后端收到 code 后执行 _sso_exchange_code 核心流程:

  1. 用 code 换 SSO access_token — 调用统一认证平台的 /oauth/token 端点
  2. 获取用户信息 — 调用统一认证平台的 /oauth/userinfo 端点
  3. 同步用户 — 在本地数据库查找或创建用户,同步角色信息

Step 6-7: 签发本地 JWT 并返回

  • 子系统后端用自己的 SECRET_KEY 签发本地 JWT
  • 返回给前端 { token, refresh_token, user }
  • 前端保存 Token 到 localStorage/sessionStorage,跳转首页

三、子系统接入前准备

3.1 在统一认证平台注册子应用

通过统一认证平台的系统管理模块(或数据库直接插入)在 t_sys_app 表中注册子系统:

字段 说明 示例值
name 子系统名称 "样本中心"
app_key 客户端 ID(client_id),32 位随机字符串 WviiGL8KQE20tQhmhQPQhhJ5QpFK51F6
app_secret 客户端密钥(client_secret),64 位随机字符串 9WXP88hEHJiHRSiUdmx7ip5oQPzY0bnJNsEswQoO4sk6juCplyJTcnAiZsv7e3lJ
redirect_uris 允许的重定向 URI(JSON 数组) ["http://localhost:3000/auth/callback"]
scope 授权范围(JSON 数组) ["profile", "email"]
is_active 是否启用 1
is_trusted 是否信任(跳过授权确认页) 1
home_url 子系统首页 URL http://localhost:3000
icon_url 子系统图标 URL 可选

3.2 子系统侧配置

在子系统的配置文件中添加 SSO 配置段:

[sso]
SSO_BASE_URL=http://192.168.92.61:8200
CLIENT_ID=WviiGL8KQE20tQhmhQPQhhJ5QpFK51F6
CLIENT_SECRET=9WXP88hEHJiHRSiUdmx7ip5oQPzY0bnJNsEswQoO4sk6juCplyJTcnAiZsv7e3lJ
REDIRECT_URI=http://localhost:3000/auth/callback
FRONTEND_URL=http://localhost:3000
SCOPE=email
SSO_LOGOUT_REDIRECT_URL=http://192.168.92.61:9200/login

注意: CLIENT_IDCLIENT_SECRET 必须与统一认证平台 t_sys_app 表中注册的 app_keyapp_secret 一致。

3.3 角色映射

子系统需要确保本地 t_sys_role 表中存在与统一认证平台对应的角色。样本中心的角色包括:

统一认证平台角色 code 说明
super_admin 超级管理员
sam_sys_admin 样本中心系统管理员
sam_data_operator 样本中心数据操作员

统一认证平台 /oauth/userinfo 返回的 roles 字段格式为对象数组:

{
  "roles": [
    { "name": "超级管理员", "code": "super_admin" },
    { "name": "样本中心系统管理员", "code": "sam_sys_admin" }
  ]
}

子系统从每个对象中提取 code 字段进行角色匹配和本地同步。


四、统一认证平台核心 API 接口

以下接口由 统一认证平台(LQAI-middle-platform,端口 8200) 提供,子系统需要调用。

4.1 获取 SSO 授权 URL

供子系统前端构建"跳转到统一认证平台登录"的链接

  • 接口: GET /oauth/authorize
  • 认证: 不需要
参数 类型 必填 说明
response_type string 固定值 code
client_id string 子应用的 app_key
redirect_uri string 回调地址(必须在 t_sys_app 中注册过)
scope string 授权范围,空格分隔,默认 profile
state string 防 CSRF 状态参数

响应: 302 重定向(如果用户已登录则重定向到 redirect_uri?code=xxx,未登录则重定向到登录页面)

4.2 获取授权码 URL(SSO 免登)

统一认证平台内部使用,当用户点击子系统图标时调用

  • 接口: POST /auth/sso-redirect
  • 认证: 需要用户已登录统一认证平台
  • 请求体:

    {
    "client_id": "WviiGL8KQE20tQhmhQPQhhJ5QpFK51F6",
    "redirect_uri": "http://localhost:3000/auth/callback"
    }
    
  • 响应:

    {
    "code": "000000",
    "message": "success",
    "data": {
    "redirect_url": "http://localhost:3000/auth/callback?code=xxxxxx"
    }
    }
    

4.3 令牌交换端点

子系统后端调用此接口,用授权码换取 SSO access_token

  • 接口: POST /oauth/token
  • Content-Type: application/x-www-form-urlencoded
  • 认证: 不需要
参数 类型 必填 说明
grant_type string 固定值 authorization_code
code string 授权码
redirect_uri string 与 Step 1 中使用的 redirect_uri 一致
client_id string 子应用的 app_key
client_secret string 子应用的 app_secret

成功响应 (200):

{
  "access_token": "eyJhbGciOiJIUzI1NiIs...",
  "token_type": "Bearer",
  "expires_in": 7200,
  "refresh_token": "xxxxxxxxxxxxxxxxxxxx",
  "scope": "profile email"
}

失败响应:

{
  "error": "invalid_grant",
  "error_description": "授权码无效"
}
error 值 说明
invalid_request 缺少必填参数
unsupported_grant_type grant_type 不支持
invalid_client client_id 或 client_secret 错误
invalid_grant 授权码无效/已使用/过期,或 redirect_uri 不匹配

4.4 获取用户信息

子系统后端调用此接口,获取当前登录用户的详细信息

  • 接口: GET /oauth/userinfo
  • 认证: Bearer Token(使用 4.3 返回的 access_token)

请求头:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

成功响应 (200):

{
  "sub": "user_xxx",
  "username": "admin",
  "email": "admin@example.com",
  "avatar_url": "https://...",
  "real_name": "管理员",
  "company": "四川路桥",
  "department": "技术部",
  "position": "工程师",
  "roles": [
    { "name": "超级管理员", "code": "super_admin" },
    { "name": "样本中心系统管理员", "code": "sam_sys_admin" }
  ]
}

返回的字段根据 token 的 scope 过滤:profile scope 返回基本信息,email scope 返回邮箱,phone scope 返回手机号。

失败响应:

{
  "error": "invalid_token",
  "error_description": "User not found or inactive"
}

五、子系统侧需要实现的 API 接口

以下是子系统(如样本中心)自身需要实现的接口,用于完成 SSO 接入。

5.1 授权码交换接口(核心免登接口)

  • 接口: POST /api/oauth/exchange-code
  • Content-Type: application/json
  • 认证: 不需要
  • 用途: 前端收到 SSO 回调的 code 后,调用此接口换取本地 JWT

请求体:

{
  "code": "xxxxxx"
}

成功响应:

{
  "code": "000000",
  "message": "登录成功",
  "data": {
    "token": "eyJhbGciOiJIUzI1NiIs...",
    "refresh_token": "xxxxxxxxxxxxxxxxxxxx",
    "user": {
      "id": "user_xxx",
      "username": "admin",
      "email": "admin@example.com",
      "phone": "138xxxx",
      "is_superuser": true,
      "is_active": true,
      "roles": ["super_admin", "sam_sys_admin"]
    }
  }
}

失败响应:

{
  "code": "100001",
  "message": "缺少授权码",
  "data": null
}
{
  "code": "500001",
  "message": "登录失败: 获取令牌失败",
  "data": null
}

5.2 获取 SSO 授权 URL

  • 接口: GET /auth/sso/authorize
  • 认证: 不需要
参数 类型 必填 说明
redirect bool 为 true 时直接 302 重定向到 SSO 授权页

响应 (redirect=false):

{
  "code": "000000",
  "message": "获取授权URL成功",
  "data": {
    "authorize_url": "http://192.168.92.61:8200/oauth/authorize?client_id=xxx&redirect_uri=xxx&response_type=code&scope=email"
  }
}

5.3 SSO 回调端点(旧流程,后端 302 重定向方式)

  • 接口: GET /auth/callback
  • 认证: 不需要
参数 类型 必填 说明
code string SSO 授权码
error string SSO 返回的错误码
error_description string 错误描述
state string 状态参数

响应: 302 重定向到 前端URL/oauth/callback?token=xxx&refresh_token=xxx

注意: 这是旧流程,建议使用 POST /api/oauth/exchange-code 的新流程(前端直接调用 API 换码,不依赖后端 302 重定向)。


六、子系统侧的其他认证相关 API

除了 SSO 接入外,子系统还需要提供标准认证接口供前端使用。

6.1 本地密码登录

  • 接口: POST /api/v1/auth/login
  • Content-Type: application/json

请求体:

{
  "username": "admin",
  "password": "Admin123456",
  "remember_me": false
}

响应:

{
  "code": "000000",
  "message": "登录成功",
  "data": {
    "access_token": "eyJ...",
    "refresh_token": "xxx...",
    "token_type": "Bearer",
    "expires_in": 1200
  }
}

6.2 刷新 Token

  • 接口: POST /api/v1/auth/refresh
  • 请求体: { "refresh_token": "xxx" }

6.3 登出

  • 接口: POST /api/v1/auth/logout
  • 请求体: { "token": "xxx", "refresh_token": "xxx" }
  • 响应 (含 SSO 登出重定向 URL):

    {
    "code": "000000",
    "message": "登出成功",
    "data": {
    "sso_logout_url": "http://192.168.92.61:9200/login"
    }
    }
    

6.4 获取当前用户信息

  • 接口: GET /api/v1/auth/userinfoGET /api/v1/auth/me
  • 认证: Bearer Token
  • 响应:

    {
    "code": "000000",
    "data": {
    "id": "user_xxx",
    "username": "admin",
    "email": "admin@example.com",
    "phone": "138xxxx",
    "roles": ["super_admin"],
    "permissions": []
    }
    }
    

6.5 获取验证码

  • 接口: GET /api/v1/auth/captcha
  • 认证: 不需要

七、统一认证平台的 OAuth2 服务端 API

统一认证平台自身也是一个 OAuth2 授权服务器,可以为下游子系统提供 OAuth2 服务。

7.1 应用管理(系统管理员操作)

通过统一认证平台的系统管理模块管理子应用,相关接口前缀 /api/v1

方法 路径 说明
GET /api/v1/system/app/list 获取应用列表
POST /api/v1/system/app/create 创建应用(自动生成 app_key/app_secret)
PUT /api/v1/system/app/update/{id} 更新应用信息
DELETE /api/v1/system/app/delete/{id} 删除应用
POST /api/v1/system/app/reset_secret/{id} 重置应用密钥
GET /api/v1/system/app/accessible 获取当前用户可访问的应用列表

7.2 角色管理

方法 路径 说明
GET /api/v1/system/role/list 获取角色列表
POST /api/v1/system/role/create 创建角色
PUT /api/v1/system/role/update/{id} 更新角色
DELETE /api/v1/system/role/delete/{id} 删除角色
GET /api/external/v1/system/role/user_list/{role_code} 按角色 code 查询用户列表

八、Token 机制说明

8.1 统一认证平台侧 Token

Token 类型 有效期 存储方式 说明
Access Token 30 分钟(默认) Redis (auth:access:{user_id}:{token}) 访问令牌,含用户身份和角色
Refresh Token 30 天 Redis (auth:refresh:{user_id}:{token}) 刷新令牌,用于换取新 Access Token
OAuth Access Token 120 分钟 Redis (auth:oauth_access:{client_id}:{token}) OAuth2 流程中颁发给子应用的令牌
OAuth Authorization Code 10 分钟 Redis (auth:oauth_code:{code}) 一次性授权码,使用后即失效

8.2 子系统侧 Token

Token 类型 有效期 存储方式 说明
Access Token 20 分钟 MySQL + Redis 子系统本地登录令牌
Refresh Token 24 小时 MySQL + Redis 刷新令牌

8.3 滑动过期机制

子系统实现了 JWT Token 的滑动过期机制:

  • 当 Token 使用时间超过其总生命周期的 50% 时,中间件会自动生成新 Token
  • 新 Token 通过响应头 X-New-Token 返回给前端
  • 前端检测到 X-New-Token 后替换本地旧 Token
  • 无需前端主动刷新即可保持登录状态

九、前端接入参考代码

9.1 SSO 免登流程(推荐方式)

// 1. 统一认证平台重定向到子系统前端,URL 携带 code 参数
// 例如: http://localhost:3000/auth/callback?code=xxxxxx

// 2. 在回调页面中提取 code 并调用换码接口
const code = new URLSearchParams(window.location.search).get('code');

if (code) {
  const response = await fetch('/api/oauth/exchange-code', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ code })
  });
  const result = await response.json();

  if (result.code === '000000') {
    // 3. 保存 Token
    localStorage.setItem('token', result.data.token);
    localStorage.setItem('refresh_token', result.data.refresh_token);
    localStorage.setItem('user', JSON.stringify(result.data.user));

    // 4. 跳转到首页
    router.push('/home');
  } else {
    // 登录失败,跳回登录页
    router.push(`/login?error=${result.message}`);
  }
}

9.2 前端请求拦截器(携带 Token)

// Axios 请求拦截器示例
axios.interceptors.request.use(config => {
  const token = localStorage.getItem('token');
  if (token) {
    config.headers.Authorization = `Bearer ${token}`;
  }
  return config;
});

// 响应拦截器处理 Token 刷新
axios.interceptors.response.use(
  response => {
    const newToken = response.headers['x-new-token'];
    if (newToken) {
      localStorage.setItem('token', newToken);
    }
    return response;
  },
  error => {
    if (error.response?.status === 401) {
      // Token 过期,清除并跳转登录
      localStorage.removeItem('token');
      localStorage.removeItem('refresh_token');
      router.push('/login');
    }
    return Promise.reject(error);
  }
);

十、接入 Checklist

  • 在统一认证平台注册子应用,获取 client_idclient_secret
  • 在子应用配置文件中添加 [sso] 配置段
  • 子应用后端实现 POST /api/oauth/exchange-code 换码接口
  • 子应用前端实现回调页面 /auth/callback,从 URL 提取 code 并调换码接口
  • 子应用本地数据库初始化角色表(t_sys_role),确保角色 code 与统一认证平台一致
  • 子应用配置 CORS 允许前端域名访问
  • 配置 Token 滑动过期中间件
  • 配置登出时返回 SSO 登出重定向 URL
  • 测试完整 SSO 流程:统一认证平台登录 → 点击子系统 → 自动免登进入子系统

十一、错误码说明

统一响应格式

所有接口使用统一的响应格式:

{
  "code": "000000",
  "message": "success",
  "data": { ... },
  "timestamp": "2026-05-10T12:00:00Z"
}

业务错误码

错误码 说明
000000 成功
100001 缺少授权码
400001 SSO 授权码无效
400002 SSO 用户信息格式异常
500001 服务器内部错误

OAuth2 标准错误

error 说明
invalid_request 请求参数不完整或格式错误
invalid_client client_id 或 client_secret 错误
invalid_grant 授权码无效、已使用、过期或 redirect_uri 不匹配
invalid_scope 请求的 scope 超出应用注册范围
unsupported_response_type response_type 不支持(仅支持 code)
unsupported_grant_type grant_type 不支持(仅支持 authorization_code)
access_denied 用户拒绝授权
server_error 服务器内部错误