mirror of
https://github.com/SECTL/SecScore.git
synced 2026-07-19 06:04:22 +08:00
7a59572f11
- 新增 OAuth 登录组件和回调页面 - 集成 Tauri 深度链接插件处理 OAuth 回调 - 添加账户设置页面显示登录信息 - 更新 CI 配置添加 OAuth 环境变量 - 扩展 API 接口支持 OAuth 相关操作 - 添加国际化支持
12 KiB
12 KiB
平台接入指南
本文档介绍如何将第三方平台与 SECTL Auth 集成,实现统一认证和远程退登功能。
目录
概述
SECTL Auth 提供以下核心功能:
- 统一认证 - 用户使用 SECTL Auth 账号登录第三方平台
- 远程退登 - 用户在 SECTL Auth 中心退出后,平台自动退出
- 用户管理 - 查看已授权用户、统计信息等
工作流程
┌─────────────┐ 登录请求 ┌─────────────┐
│ 用户 │ ─────────────> │ SECTL Auth │
│ │ │ │
│ 平台A │ <───────────── │ 认证中心 │
│ │ Access Token │ │
└──────┬──────┘ └──────┬──────┘
│ │
│ 远程退登通知 │
│ <─────────────────────────── │
│ (Realtime) │
▼ ▼
自动退出登录 用户点击退出
快速开始
1. 注册平台
在 SECTL Auth 平台管理页面 (PlatformManagementView.vue) 申请接入,获取:
| 参数 | 说明 | 示例 |
|---|---|---|
| platform_id | 平台唯一标识 | pf_AHmIhAiptyLFxk8x |
| platform_token | 平台认证密钥 | sk_UyMHuFf6oKXh8ZcHSb7lfOSgzumoOeg1 |
| callback_url | 回调地址 | http://localhost:5000/callback |
2. 平台状态说明
平台在管理后台有以下状态:
| 状态 | 说明 | 可操作 |
|---|---|---|
| active | 运行中 | 正常授权 |
| pending | 审核中 | 等待审核 |
| disabled | 已停用 | 无法授权 |
3. 查看统计信息
在平台管理页面可以查看:
- 总平台数 - 已创建的平台数量
- 运行中 - 活跃平台数量
- 审核中 - 待审核申请数量
- 总用户数 - 授权用户总数
管理后台功能
平台列表 (PlatformManagementView.vue)
平台管理页面提供以下功能:
1. 平台卡片展示
每个平台显示:
- 平台名称和描述
- 状态标签(运行中/审核中/已停用)
- 创建时间
- 授权用户数
- 管理按钮
2. 搜索和过滤
- 按名称搜索平台
- 按状态过滤
- 分页展示
3. 快捷操作
- 新建平台 - 跳转到申请页面
- 我的申请 - 查看自己的平台申请
- 审核申请 - 审核其他用户的申请(需 >=18 权限)
平台详情 (PlatformDetailView.vue)
查看平台详细信息:
基本信息
- 平台 ID (Client ID)
- 平台密钥 (Client Secret)
- 回调地址
- 创建时间
安全设置
- Token 过期时间配置
- 密钥重置
- 回调地址修改
用户统计
- 授权用户列表
- 登录时间
- 最后活跃时间
平台申请 (PlatformApplyView.vue)
申请创建新平台:
// 申请参数
{
name: "我的应用", // 平台名称
description: "应用描述", // 平台描述
callback_url: "http://..." // 回调地址
}
申请后状态为 pending,等待管理员审核。
申请审核 (PlatformApplicationsView.vue)
管理员审核平台申请:
- 查看申请详情
- 批准申请(状态变为
active) - 拒绝申请(状态变为
disabled)
OAuth 集成
授权流程
1. 引导用户到授权页面
GET https://sectl.top/oauth/authorize
参数:
| 参数名 | 必填 | 说明 |
|---|---|---|
| client_id | ✅ | 平台 ID |
| redirect_uri | ✅ | 回调地址 |
| response_type | ✅ | 固定值 code |
示例:
https://sectl.top/oauth/authorize?client_id=pf_xxx&redirect_uri=http://localhost:5000/callback&response_type=code
2. 处理回调
用户授权后,会重定向到:
{callback_url}?code={authorization_code}
3. 换取访问令牌
POST https://sectl.top/api/oauth/token
Content-Type: application/json
{
"grant_type": "authorization_code",
"code": "授权码",
"client_id": "pf_xxx",
"client_secret": "sk_xxx",
"redirect_uri": "http://localhost:5000/callback"
}
响应:
{
"access_token": "eyJhbGciOiJIUzI1NiIs...",
"refresh_token": "xxx",
"token_type": "Bearer",
"expires_in": 3600
}
4. 获取用户信息
GET https://sectl.top/api/oauth/userinfo
Authorization: Bearer {access_token}
响应:
{
"user_id": "69bd422960018cf4d0e5",
"email": "user@example.com",
"name": "张三",
"github_username": "zhangsan"
}
远程退登
实现原理
- 用户在 SECTL Auth 点击退出登录
- 系统创建
logout_events文档 - 第三方应用通过 Appwrite Realtime 订阅该集合
- 收到匹配的事件后执行本地退出
集成步骤
1. 安装 Appwrite SDK
C#
dotnet add package Appwrite
Python
pip install appwrite
2. 配置 Realtime 订阅
C# 示例:
using Appwrite;
using Appwrite.Services;
var client = new Client()
.SetEndpoint("https://cloud.appwrite.io/v1")
.SetProject("your-project-id");
var realtime = new Realtime(client);
// 订阅 logout_events 集合
realtime.Subscribe("databases.{databaseId}.collections.logout_events.documents",
callback: (message) => {
var logoutEvent = message.Payload;
if (logoutEvent.UserId == currentUserId) {
// 执行本地退出
LocalLogout();
}
});
Python 示例:
from appwrite.client import Client
from appwrite.services.realtime import Realtime
client = Client()
client.set_endpoint('https://cloud.appwrite.io/v1')
client.set_project('your-project-id')
realtime = Realtime(client)
def on_logout_event(message):
event = message['payload']
if event['user_id'] == current_user_id:
# 执行本地退出
local_logout()
# 订阅 logout_events 集合
realtime.subscribe(
'databases.{database_id}.collections.logout_events.documents',
callback=on_logout_event
)
数据结构
logout_events 集合字段:
| 字段 | 类型 | 说明 |
|---|---|---|
| user_id | String | 退出登录的用户ID |
| platform_id | String | 特定平台ID(可选) |
| global | Boolean | 是否全局退出 |
| created_at | String | 创建时间 |
代码示例
C# 完整示例
详见 csharp-example 目录。
// SectlAuthClient.cs
public class SectlAuthClient
{
private readonly string _platformId;
private readonly string _platformSecret;
private readonly string _callbackUrl;
private readonly HttpClient _httpClient;
public SectlAuthClient(string platformId, string platformSecret, string callbackUrl)
{
_platformId = platformId;
_platformSecret = platformSecret;
_callbackUrl = callbackUrl;
_httpClient = new HttpClient();
}
// 获取授权 URL
public string GetAuthorizationUrl()
{
return $"https://sectl.top/oauth/authorize?" +
$"client_id={_platformId}&" +
$"redirect_uri={Uri.EscapeDataString(_callbackUrl)}&" +
$"response_type=code";
}
// 换取访问令牌
public async Task<TokenResponse> ExchangeCodeAsync(string code)
{
var request = new
{
grant_type = "authorization_code",
code = code,
client_id = _platformId,
client_secret = _platformSecret,
redirect_uri = _callbackUrl
};
var response = await _httpClient.PostAsJsonAsync(
"https://sectl.top/api/oauth/token", request);
return await response.Content.ReadFromJsonAsync<TokenResponse>();
}
// 获取用户信息
public async Task<UserInfo> GetUserInfoAsync(string accessToken)
{
_httpClient.DefaultRequestHeaders.Authorization =
new AuthenticationHeaderValue("Bearer", accessToken);
var response = await _httpClient.GetAsync(
"https://sectl.top/api/oauth/userinfo");
return await response.Content.ReadFromJsonAsync<UserInfo>();
}
}
Python 完整示例
详见 python-example 目录。
# sectl_auth/client.py
import requests
class SectlAuthClient:
BASE_URL = "https://sectl.top"
AUTH_URL = "https://sectl.top"
def __init__(self, platform_id: str, platform_secret: str, callback_url: str):
self.platform_id = platform_id
self.platform_secret = platform_secret
self.callback_url = callback_url
def get_authorization_url(self) -> str:
"""获取授权 URL"""
return (
f"{self.AUTH_URL}/oauth/authorize?"
f"client_id={self.platform_id}&"
f"redirect_uri={self.callback_url}&"
f"response_type=code"
)
def exchange_code(self, code: str) -> dict:
"""用授权码换取访问令牌"""
response = requests.post(
f"{self.BASE_URL}/api/oauth/token",
json={
"grant_type": "authorization_code",
"code": code,
"client_id": self.platform_id,
"client_secret": self.platform_secret,
"redirect_uri": self.callback_url
}
)
response.raise_for_status()
return response.json()
def get_user_info(self, access_token: str) -> dict:
"""获取用户信息"""
response = requests.get(
f"{self.BASE_URL}/api/oauth/userinfo",
headers={"Authorization": f"Bearer {access_token}"}
)
response.raise_for_status()
return response.json()
常见问题
Q: 如何获取 platform_id 和 platform_token?
A: 在 SECTL Auth 平台管理页面申请创建平台,审核通过后会获得:
- platform_id (Client ID)
- platform_token (Client Secret)
Q: 授权码有效期多久?
A: 授权码有效期为 10 分钟,且只能使用一次。
Q: Access Token 过期后怎么办?
A: 使用 refresh_token 换取新的 access_token:
POST /api/oauth/token
{
"grant_type": "refresh_token",
"refresh_token": "your-refresh-token",
"client_id": "your-platform-id",
"client_secret": "your-platform-secret"
}
Q: 如何配置 Token 过期时间?
A: 在平台设置页面 (PlatformSettingsView.vue) 可以配置:
- access_token 过期时间(默认 3600 秒)
- 设置为 -1 表示永不过期
Q: 远程退登不生效怎么办?
A: 检查以下几点:
- 是否正确订阅了
logout_events集合 - 检查 user_id 是否匹配
- 确认 Appwrite Realtime 连接正常
- 查看浏览器控制台是否有错误
Q: 平台状态显示"审核中"怎么办?
A: 新创建的平台需要管理员审核。审核通过后状态会变为 active。
相关页面
- PlatformManagementView.vue - 平台管理
- PlatformDetailView.vue - 平台详情
- PlatformApplyView.vue - 申请平台
- PlatformApplicationsView.vue - 审核申请
- PlatformSettingsView.vue - 平台设置
- LoginPlatformsView.vue - 登录平台列表