huace-aigc-auth-client 1.1.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- huace_aigc_auth_client-1.1.0/LICENSE +22 -0
- huace_aigc_auth_client-1.1.0/MANIFEST.in +7 -0
- huace_aigc_auth_client-1.1.0/PKG-INFO +616 -0
- huace_aigc_auth_client-1.1.0/QUICK_START.txt +119 -0
- huace_aigc_auth_client-1.1.0/README.md +591 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client/__init__.py +93 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client/legacy_adapter.py +483 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client/sdk.py +704 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client.egg-info/PKG-INFO +616 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client.egg-info/SOURCES.txt +13 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client.egg-info/dependency_links.txt +1 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client.egg-info/requires.txt +1 -0
- huace_aigc_auth_client-1.1.0/huace_aigc_auth_client.egg-info/top_level.txt +1 -0
- huace_aigc_auth_client-1.1.0/pyproject.toml +41 -0
- huace_aigc_auth_client-1.1.0/setup.cfg +4 -0
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Huace
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
22
|
+
|
|
@@ -0,0 +1,616 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: huace-aigc-auth-client
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: 华策AIGC Auth Client - 提供 Token 验证、用户信息获取、权限检查、旧系统接入等功能
|
|
5
|
+
Author-email: Huace <support@huace.com>
|
|
6
|
+
License: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/huace/huace-aigc-auth-client
|
|
8
|
+
Project-URL: Repository, https://github.com/huace/huace-aigc-auth-client
|
|
9
|
+
Keywords: aigc,auth,huace,sdk,authentication
|
|
10
|
+
Classifier: Development Status :: 4 - Beta
|
|
11
|
+
Classifier: Intended Audience :: Developers
|
|
12
|
+
Classifier: License :: OSI Approved :: MIT License
|
|
13
|
+
Classifier: Programming Language :: Python :: 3
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.7
|
|
15
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
16
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
20
|
+
Requires-Python: >=3.7
|
|
21
|
+
Description-Content-Type: text/markdown
|
|
22
|
+
License-File: LICENSE
|
|
23
|
+
Requires-Dist: requests>=2.20.0
|
|
24
|
+
Dynamic: license-file
|
|
25
|
+
|
|
26
|
+
# AIGC Auth Python SDK
|
|
27
|
+
|
|
28
|
+
[](https://pypi.org/project/huace-aigc-auth-client/)
|
|
29
|
+
[](https://pypi.org/project/huace-aigc-auth-client/)
|
|
30
|
+
|
|
31
|
+
Python 后端服务接入华策 AIGC 鉴权中心的 SDK 工具包。
|
|
32
|
+
|
|
33
|
+
## 安装
|
|
34
|
+
|
|
35
|
+
```bash
|
|
36
|
+
pip install huace-aigc-auth-client
|
|
37
|
+
```
|
|
38
|
+
|
|
39
|
+
## 环境变量配置
|
|
40
|
+
|
|
41
|
+
在项目根目录创建 `.env` 文件:
|
|
42
|
+
|
|
43
|
+
```bash
|
|
44
|
+
# 必填:应用 ID 和密钥(在鉴权中心创建应用后获取)
|
|
45
|
+
AIGC_AUTH_APP_ID=your_app_id
|
|
46
|
+
AIGC_AUTH_APP_SECRET=your_app_secret
|
|
47
|
+
|
|
48
|
+
# 可选:鉴权服务地址(默认为生产环境)
|
|
49
|
+
AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/api/v1
|
|
50
|
+
```
|
|
51
|
+
|
|
52
|
+
如需通过 Nginx 代理:
|
|
53
|
+
|
|
54
|
+
```nginx
|
|
55
|
+
location /aigc-auth/ {
|
|
56
|
+
proxy_pass https://aigc-auth.huacemedia.com/aigc-auth/;
|
|
57
|
+
proxy_set_header Host $host;
|
|
58
|
+
proxy_set_header X-Real-IP $remote_addr;
|
|
59
|
+
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
|
|
60
|
+
proxy_set_header X-Forwarded-Proto $scheme;
|
|
61
|
+
}
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
## 快速开始
|
|
65
|
+
|
|
66
|
+
### 1. 初始化客户端
|
|
67
|
+
|
|
68
|
+
```python
|
|
69
|
+
from huace_aigc_auth_client import AigcAuthClient
|
|
70
|
+
|
|
71
|
+
# 方式一:从环境变量读取配置
|
|
72
|
+
client = AigcAuthClient()
|
|
73
|
+
|
|
74
|
+
# 方式二:直接传入参数
|
|
75
|
+
client = AigcAuthClient(
|
|
76
|
+
app_id="your_app_id",
|
|
77
|
+
app_secret="your_app_secret",
|
|
78
|
+
base_url="https://aigc-auth.huacemedia.com/api/v1"
|
|
79
|
+
)
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
### 2. 验证 Token
|
|
83
|
+
|
|
84
|
+
```python
|
|
85
|
+
result = client.verify_token(token)
|
|
86
|
+
|
|
87
|
+
if result.valid:
|
|
88
|
+
print(f"用户 ID: {result.user_id}")
|
|
89
|
+
print(f"用户名: {result.username}")
|
|
90
|
+
print(f"过期时间: {result.expires_at}")
|
|
91
|
+
else:
|
|
92
|
+
print("Token 无效")
|
|
93
|
+
```
|
|
94
|
+
|
|
95
|
+
### 3. 获取用户信息
|
|
96
|
+
|
|
97
|
+
```python
|
|
98
|
+
from huace_aigc_auth_client import AigcAuthClient, AigcAuthError
|
|
99
|
+
|
|
100
|
+
client = AigcAuthClient()
|
|
101
|
+
|
|
102
|
+
try:
|
|
103
|
+
user = client.get_user_info(token)
|
|
104
|
+
|
|
105
|
+
print(f"用户名: {user.username}")
|
|
106
|
+
print(f"昵称: {user.nickname}")
|
|
107
|
+
print(f"邮箱: {user.email}")
|
|
108
|
+
print(f"角色: {user.roles}")
|
|
109
|
+
print(f"权限: {user.permissions}")
|
|
110
|
+
|
|
111
|
+
# 检查角色
|
|
112
|
+
if user.has_role("admin"):
|
|
113
|
+
print("是管理员")
|
|
114
|
+
|
|
115
|
+
# 检查权限
|
|
116
|
+
if user.has_permission("user:write"):
|
|
117
|
+
print("有用户写权限")
|
|
118
|
+
|
|
119
|
+
except AigcAuthError as e:
|
|
120
|
+
print(f"错误: {e.message}")
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 4. 批量检查权限
|
|
124
|
+
|
|
125
|
+
```python
|
|
126
|
+
results = client.check_permissions(token, ["user:read", "user:write", "admin:access"])
|
|
127
|
+
|
|
128
|
+
for permission, has_permission in results.items():
|
|
129
|
+
print(f"{permission}: {'✓' if has_permission else '✗'}")
|
|
130
|
+
```
|
|
131
|
+
|
|
132
|
+
## FastAPI 集成
|
|
133
|
+
|
|
134
|
+
### 方式一:使用中间件(推荐)
|
|
135
|
+
|
|
136
|
+
```python
|
|
137
|
+
from fastapi import FastAPI, Request, HTTPException
|
|
138
|
+
from huace_aigc_auth_client import AigcAuthClient, AuthMiddleware
|
|
139
|
+
|
|
140
|
+
app = FastAPI()
|
|
141
|
+
|
|
142
|
+
# 初始化客户端和中间件
|
|
143
|
+
client = AigcAuthClient()
|
|
144
|
+
auth_middleware = AuthMiddleware(
|
|
145
|
+
client,
|
|
146
|
+
exclude_paths=["/health", "/docs", "/openapi.json"],
|
|
147
|
+
exclude_prefixes=["/public/"]
|
|
148
|
+
)
|
|
149
|
+
|
|
150
|
+
# 注册中间件
|
|
151
|
+
@app.middleware("http")
|
|
152
|
+
async def auth(request: Request, call_next):
|
|
153
|
+
return await auth_middleware.fastapi_middleware(request, call_next)
|
|
154
|
+
|
|
155
|
+
# 在路由中获取用户信息
|
|
156
|
+
@app.get("/me")
|
|
157
|
+
async def get_current_user(request: Request):
|
|
158
|
+
user = request.state.user_info
|
|
159
|
+
return {
|
|
160
|
+
"username": user.username,
|
|
161
|
+
"roles": user.roles
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
@app.get("/admin")
|
|
165
|
+
async def admin_only(request: Request):
|
|
166
|
+
user = request.state.user_info
|
|
167
|
+
if not user.has_role("admin"):
|
|
168
|
+
raise HTTPException(status_code=403, detail="需要管理员权限")
|
|
169
|
+
return {"message": "欢迎管理员"}
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### 方式二:使用依赖注入
|
|
173
|
+
|
|
174
|
+
```python
|
|
175
|
+
from fastapi import FastAPI, Depends, HTTPException
|
|
176
|
+
from huace_aigc_auth_client import AigcAuthClient, create_fastapi_auth_dependency, UserInfo
|
|
177
|
+
|
|
178
|
+
app = FastAPI()
|
|
179
|
+
client = AigcAuthClient()
|
|
180
|
+
|
|
181
|
+
# 创建认证依赖
|
|
182
|
+
get_current_user = create_fastapi_auth_dependency(client)
|
|
183
|
+
|
|
184
|
+
@app.get("/me")
|
|
185
|
+
async def get_me(user: UserInfo = Depends(get_current_user)):
|
|
186
|
+
return {"username": user.username}
|
|
187
|
+
|
|
188
|
+
# 创建权限检查依赖
|
|
189
|
+
def require_permission(permission: str):
|
|
190
|
+
async def check(user: UserInfo = Depends(get_current_user)):
|
|
191
|
+
if not user.has_permission(permission):
|
|
192
|
+
raise HTTPException(status_code=403, detail="权限不足")
|
|
193
|
+
return user
|
|
194
|
+
return check
|
|
195
|
+
|
|
196
|
+
@app.get("/users")
|
|
197
|
+
async def list_users(user: UserInfo = Depends(require_permission("user:read"))):
|
|
198
|
+
return {"users": [...]}
|
|
199
|
+
```
|
|
200
|
+
|
|
201
|
+
### 方式三:使用装饰器
|
|
202
|
+
|
|
203
|
+
```python
|
|
204
|
+
from fastapi import FastAPI, Request
|
|
205
|
+
from huace_aigc_auth_client import AigcAuthClient, require_auth, UserInfo
|
|
206
|
+
|
|
207
|
+
app = FastAPI()
|
|
208
|
+
client = AigcAuthClient()
|
|
209
|
+
|
|
210
|
+
@app.get("/protected")
|
|
211
|
+
@require_auth(client)
|
|
212
|
+
async def protected_route(request: Request, user_info: UserInfo):
|
|
213
|
+
return {"user": user_info.username}
|
|
214
|
+
|
|
215
|
+
@app.get("/admin")
|
|
216
|
+
@require_auth(client, permissions=["admin:access"])
|
|
217
|
+
async def admin_route(request: Request, user_info: UserInfo):
|
|
218
|
+
return {"admin": True}
|
|
219
|
+
|
|
220
|
+
# 只需要任意一个权限
|
|
221
|
+
@app.get("/editor")
|
|
222
|
+
@require_auth(client, permissions=["article:write", "article:edit"], any_permission=True)
|
|
223
|
+
async def editor_route(request: Request, user_info: UserInfo):
|
|
224
|
+
return {"editor": True}
|
|
225
|
+
```
|
|
226
|
+
|
|
227
|
+
## Flask 集成
|
|
228
|
+
|
|
229
|
+
```python
|
|
230
|
+
from flask import Flask, g, jsonify
|
|
231
|
+
from functools import wraps
|
|
232
|
+
from huace_aigc_auth_client import AigcAuthClient, AuthMiddleware
|
|
233
|
+
|
|
234
|
+
app = Flask(__name__)
|
|
235
|
+
|
|
236
|
+
# 初始化客户端和中间件
|
|
237
|
+
client = AigcAuthClient()
|
|
238
|
+
auth_middleware = AuthMiddleware(
|
|
239
|
+
client,
|
|
240
|
+
exclude_paths=["/health", "/login"],
|
|
241
|
+
exclude_prefixes=["/public/"]
|
|
242
|
+
)
|
|
243
|
+
|
|
244
|
+
# 注册 before_request
|
|
245
|
+
@app.before_request
|
|
246
|
+
def before_request():
|
|
247
|
+
return auth_middleware.flask_before_request()
|
|
248
|
+
|
|
249
|
+
# 在路由中获取用户信息
|
|
250
|
+
@app.route("/me")
|
|
251
|
+
def get_me():
|
|
252
|
+
user = g.user_info
|
|
253
|
+
return jsonify({
|
|
254
|
+
"username": user.username,
|
|
255
|
+
"roles": user.roles
|
|
256
|
+
})
|
|
257
|
+
|
|
258
|
+
# 权限检查装饰器
|
|
259
|
+
def require_permission(permission):
|
|
260
|
+
def decorator(f):
|
|
261
|
+
@wraps(f)
|
|
262
|
+
def decorated_function(*args, **kwargs):
|
|
263
|
+
user = g.user_info
|
|
264
|
+
if not user.has_permission(permission):
|
|
265
|
+
return jsonify({"error": "权限不足"}), 403
|
|
266
|
+
return f(*args, **kwargs)
|
|
267
|
+
return decorated_function
|
|
268
|
+
return decorator
|
|
269
|
+
|
|
270
|
+
@app.route("/admin")
|
|
271
|
+
@require_permission("admin:access")
|
|
272
|
+
def admin_only():
|
|
273
|
+
return jsonify({"message": "欢迎管理员"})
|
|
274
|
+
```
|
|
275
|
+
|
|
276
|
+
## API 参考
|
|
277
|
+
|
|
278
|
+
### UserInfo 对象
|
|
279
|
+
|
|
280
|
+
| 属性 | 类型 | 说明 |
|
|
281
|
+
|------|------|------|
|
|
282
|
+
| `id` | int | 用户 ID |
|
|
283
|
+
| `username` | str | 用户名 |
|
|
284
|
+
| `nickname` | str | 昵称 |
|
|
285
|
+
| `email` | str | 邮箱 |
|
|
286
|
+
| `phone` | str | 手机号 |
|
|
287
|
+
| `avatar` | str | 头像 URL |
|
|
288
|
+
| `roles` | List[str] | 角色代码列表 |
|
|
289
|
+
| `permissions` | List[str] | 权限代码列表 |
|
|
290
|
+
| `department` | str | 部门 |
|
|
291
|
+
| `company` | str | 公司 |
|
|
292
|
+
|
|
293
|
+
| 方法 | 说明 |
|
|
294
|
+
|------|------|
|
|
295
|
+
| `has_role(role)` | 检查是否拥有指定角色 |
|
|
296
|
+
| `has_permission(permission)` | 检查是否拥有指定权限 |
|
|
297
|
+
| `has_any_permission(permissions)` | 检查是否拥有任意一个权限 |
|
|
298
|
+
| `has_all_permissions(permissions)` | 检查是否拥有所有权限 |
|
|
299
|
+
|
|
300
|
+
### 异常处理
|
|
301
|
+
|
|
302
|
+
```python
|
|
303
|
+
from huace_aigc_auth_client import AigcAuthClient, AigcAuthError
|
|
304
|
+
|
|
305
|
+
client = AigcAuthClient()
|
|
306
|
+
|
|
307
|
+
try:
|
|
308
|
+
user = client.get_user_info(token)
|
|
309
|
+
except AigcAuthError as e:
|
|
310
|
+
print(f"错误码: {e.code}")
|
|
311
|
+
print(f"错误信息: {e.message}")
|
|
312
|
+
```
|
|
313
|
+
|
|
314
|
+
| 错误码 | 说明 |
|
|
315
|
+
|--------|------|
|
|
316
|
+
| 401 | 未授权(Token 无效或已过期) |
|
|
317
|
+
| 403 | 禁止访问(用户被禁用或权限不足) |
|
|
318
|
+
| 404 | 用户不存在 |
|
|
319
|
+
| -1 | 网络请求失败 |
|
|
320
|
+
|
|
321
|
+
---
|
|
322
|
+
|
|
323
|
+
## 旧系统接入(用户同步)
|
|
324
|
+
|
|
325
|
+
如果你的系统已有用户表,可通过 SDK 提供的「旧系统适配器」实现低成本接入,**无需修改历史代码和表结构**。
|
|
326
|
+
|
|
327
|
+
### 接入原理
|
|
328
|
+
|
|
329
|
+
```
|
|
330
|
+
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
331
|
+
│ aigc-auth │────▶│ SDK 同步层 │────▶│ 旧系统 │
|
|
332
|
+
│ (鉴权中心) │ │ (字段映射) │ │ (用户表) │
|
|
333
|
+
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
334
|
+
│ │ │
|
|
335
|
+
│ 1. 初始化同步 │ │
|
|
336
|
+
│◀──────────────────────────────────────────────│
|
|
337
|
+
│ (批量同步旧用户到 auth) │
|
|
338
|
+
│ │ │
|
|
339
|
+
│ 2. 增量同步 │ │
|
|
340
|
+
│──────────────────────▶│──────────────────────▶│
|
|
341
|
+
│ (auth 新用户自动同步到旧系统) │
|
|
342
|
+
│ │ │
|
|
343
|
+
│ 3. Webhook 推送 │ │
|
|
344
|
+
│──────────────────────────────────────────────▶│
|
|
345
|
+
│ (用户变更主动通知) │
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
### 快速开始
|
|
349
|
+
|
|
350
|
+
#### 1. 配置环境变量
|
|
351
|
+
|
|
352
|
+
```bash
|
|
353
|
+
# .env 文件
|
|
354
|
+
AIGC_AUTH_APP_ID=your_app_id
|
|
355
|
+
AIGC_AUTH_APP_SECRET=your_app_secret
|
|
356
|
+
AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/api/v1
|
|
357
|
+
|
|
358
|
+
# 同步配置
|
|
359
|
+
AIGC_AUTH_SYNC_ENABLED=true
|
|
360
|
+
AIGC_AUTH_SYNC_PASSWORD=Abc@123456
|
|
361
|
+
AIGC_AUTH_WEBHOOK_URL=https://your-domain.com/api/v1/webhook/auth
|
|
362
|
+
AIGC_AUTH_WEBHOOK_SECRET=your_secret
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
#### 2. 创建字段映射
|
|
366
|
+
|
|
367
|
+
```python
|
|
368
|
+
from huace_aigc_auth_client import (
|
|
369
|
+
FieldMapping,
|
|
370
|
+
SyncConfig,
|
|
371
|
+
PasswordMode,
|
|
372
|
+
create_sync_config
|
|
373
|
+
)
|
|
374
|
+
|
|
375
|
+
# 定义字段映射
|
|
376
|
+
field_mappings = [
|
|
377
|
+
FieldMapping(
|
|
378
|
+
auth_field="username",
|
|
379
|
+
legacy_field="username",
|
|
380
|
+
required=True
|
|
381
|
+
),
|
|
382
|
+
FieldMapping(
|
|
383
|
+
auth_field="email",
|
|
384
|
+
legacy_field="email"
|
|
385
|
+
),
|
|
386
|
+
FieldMapping(
|
|
387
|
+
auth_field="nickname",
|
|
388
|
+
legacy_field="nickname"
|
|
389
|
+
),
|
|
390
|
+
# 状态字段转换:auth 的 status 映射到旧系统的 is_active
|
|
391
|
+
FieldMapping(
|
|
392
|
+
auth_field="status",
|
|
393
|
+
legacy_field="is_active",
|
|
394
|
+
transform_to_legacy=lambda s: s == "active",
|
|
395
|
+
transform_to_auth=lambda a: "active" if a else "disabled"
|
|
396
|
+
),
|
|
397
|
+
# 角色字段转换:auth 的 roles 列表映射到旧系统的 role 字符串
|
|
398
|
+
FieldMapping(
|
|
399
|
+
auth_field="roles",
|
|
400
|
+
legacy_field="role",
|
|
401
|
+
transform_to_legacy=lambda r: r[0] if r else "viewer",
|
|
402
|
+
transform_to_auth=lambda r: [r] if r else ["viewer"]
|
|
403
|
+
),
|
|
404
|
+
]
|
|
405
|
+
|
|
406
|
+
# 创建同步配置
|
|
407
|
+
sync_config = create_sync_config(
|
|
408
|
+
field_mappings=field_mappings,
|
|
409
|
+
password_mode=PasswordMode.UNIFIED,
|
|
410
|
+
unified_password="Abc@123456",
|
|
411
|
+
webhook_url="https://your-domain.com/api/v1/webhook/auth",
|
|
412
|
+
)
|
|
413
|
+
```
|
|
414
|
+
|
|
415
|
+
#### 3. 实现旧系统适配器
|
|
416
|
+
|
|
417
|
+
```python
|
|
418
|
+
from huace_aigc_auth_client import LegacySystemAdapter, LegacyUserData
|
|
419
|
+
|
|
420
|
+
class MyLegacyAdapter(LegacySystemAdapter):
|
|
421
|
+
"""实现与旧系统用户表的交互"""
|
|
422
|
+
|
|
423
|
+
def __init__(self, db, sync_config):
|
|
424
|
+
super().__init__(sync_config)
|
|
425
|
+
self.db = db
|
|
426
|
+
|
|
427
|
+
def get_user_by_unique_field(self, username: str):
|
|
428
|
+
"""通过用户名获取旧系统用户"""
|
|
429
|
+
user = self.db.query(User).filter(User.username == username).first()
|
|
430
|
+
if not user:
|
|
431
|
+
return None
|
|
432
|
+
return LegacyUserData({
|
|
433
|
+
"id": user.id,
|
|
434
|
+
"username": user.username,
|
|
435
|
+
"email": user.email,
|
|
436
|
+
# ... 其他字段
|
|
437
|
+
})
|
|
438
|
+
|
|
439
|
+
def create_user(self, user_data: dict):
|
|
440
|
+
"""在旧系统创建用户"""
|
|
441
|
+
user = User(
|
|
442
|
+
username=user_data["username"],
|
|
443
|
+
email=user_data.get("email"),
|
|
444
|
+
hashed_password=hash_password(user_data["password"]),
|
|
445
|
+
# ... 其他字段
|
|
446
|
+
)
|
|
447
|
+
self.db.add(user)
|
|
448
|
+
self.db.commit()
|
|
449
|
+
return user.id
|
|
450
|
+
|
|
451
|
+
def update_user(self, username: str, user_data: dict):
|
|
452
|
+
"""更新旧系统用户"""
|
|
453
|
+
user = self.db.query(User).filter(User.username == username).first()
|
|
454
|
+
if user:
|
|
455
|
+
for key, value in user_data.items():
|
|
456
|
+
setattr(user, key, value)
|
|
457
|
+
self.db.commit()
|
|
458
|
+
|
|
459
|
+
def get_all_users(self):
|
|
460
|
+
"""获取所有用户(用于初始化同步)"""
|
|
461
|
+
users = self.db.query(User).all()
|
|
462
|
+
return [LegacyUserData({"username": u.username, ...}) for u in users]
|
|
463
|
+
```
|
|
464
|
+
|
|
465
|
+
#### 4. 集成到登录流程
|
|
466
|
+
|
|
467
|
+
```python
|
|
468
|
+
from huace_aigc_auth_client import AigcAuthClient, UserSyncService
|
|
469
|
+
|
|
470
|
+
client = AigcAuthClient()
|
|
471
|
+
adapter = MyLegacyAdapter(db, sync_config)
|
|
472
|
+
sync_service = UserSyncService(client, adapter)
|
|
473
|
+
|
|
474
|
+
# 在获取用户信息后调用同步
|
|
475
|
+
@app.middleware("http")
|
|
476
|
+
async def auth_middleware(request, call_next):
|
|
477
|
+
response = await auth.fastapi_middleware(request, call_next)
|
|
478
|
+
|
|
479
|
+
# 登录成功后,同步用户到旧系统
|
|
480
|
+
if hasattr(request.state, "user_info"):
|
|
481
|
+
user_info = request.state.user_info
|
|
482
|
+
sync_service.sync_on_login(user_info)
|
|
483
|
+
|
|
484
|
+
return response
|
|
485
|
+
```
|
|
486
|
+
|
|
487
|
+
#### 5. 添加 Webhook 接收端点
|
|
488
|
+
|
|
489
|
+
```python
|
|
490
|
+
@app.post("/api/v1/webhook/auth")
|
|
491
|
+
async def receive_auth_webhook(request: Request, db: Session = Depends(get_db)):
|
|
492
|
+
"""接收 aigc-auth 的用户变更通知"""
|
|
493
|
+
data = await request.json()
|
|
494
|
+
event = data.get("event")
|
|
495
|
+
user_data = data.get("data", {})
|
|
496
|
+
|
|
497
|
+
# 验证签名
|
|
498
|
+
signature = request.headers.get("X-Webhook-Signature")
|
|
499
|
+
# ... 验证逻辑
|
|
500
|
+
|
|
501
|
+
if event == "user.created":
|
|
502
|
+
adapter = MyLegacyAdapter(db, sync_config)
|
|
503
|
+
if not adapter.get_user_by_unique_field(user_data["username"]):
|
|
504
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
505
|
+
legacy_data["password"] = sync_config.unified_password
|
|
506
|
+
adapter.create_user(legacy_data)
|
|
507
|
+
db.commit()
|
|
508
|
+
|
|
509
|
+
elif event == "user.updated":
|
|
510
|
+
adapter = MyLegacyAdapter(db, sync_config)
|
|
511
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
512
|
+
adapter.update_user(user_data["username"], legacy_data)
|
|
513
|
+
db.commit()
|
|
514
|
+
|
|
515
|
+
return {"success": True}
|
|
516
|
+
```
|
|
517
|
+
|
|
518
|
+
#### 6. 执行初始化同步
|
|
519
|
+
|
|
520
|
+
```python
|
|
521
|
+
# 一次性脚本:将旧系统用户同步到 aigc-auth
|
|
522
|
+
async def init_sync():
|
|
523
|
+
adapter = MyLegacyAdapter(db, sync_config)
|
|
524
|
+
users = adapter.get_all_users()
|
|
525
|
+
|
|
526
|
+
for user in users:
|
|
527
|
+
auth_data = adapter.transform_legacy_to_auth(user)
|
|
528
|
+
auth_data["password"] = sync_config.unified_password
|
|
529
|
+
client.sync_user_to_auth(auth_data)
|
|
530
|
+
|
|
531
|
+
print(f"同步完成:{len(users)} 个用户")
|
|
532
|
+
|
|
533
|
+
# 运行
|
|
534
|
+
asyncio.run(init_sync())
|
|
535
|
+
```
|
|
536
|
+
|
|
537
|
+
### 密码处理策略
|
|
538
|
+
|
|
539
|
+
| 模式 | 说明 | 适用场景 |
|
|
540
|
+
|------|------|----------|
|
|
541
|
+
| `UNIFIED` | 统一初始密码 | 推荐,安全性高 |
|
|
542
|
+
| `CUSTOM_MAPPING` | 自定义映射函数 | 需要保留原密码时 |
|
|
543
|
+
|
|
544
|
+
```python
|
|
545
|
+
from huace_aigc_auth_client import PasswordMode, create_sync_config
|
|
546
|
+
|
|
547
|
+
# 统一密码模式(推荐)
|
|
548
|
+
sync_config = create_sync_config(
|
|
549
|
+
password_mode=PasswordMode.UNIFIED,
|
|
550
|
+
unified_password="Abc@123456"
|
|
551
|
+
)
|
|
552
|
+
|
|
553
|
+
# 自定义映射模式
|
|
554
|
+
def password_mapper(user_data):
|
|
555
|
+
return user_data.get("hashed_password", "default")
|
|
556
|
+
|
|
557
|
+
sync_config = create_sync_config(
|
|
558
|
+
password_mode=PasswordMode.CUSTOM_MAPPING,
|
|
559
|
+
password_mapper=password_mapper
|
|
560
|
+
)
|
|
561
|
+
```
|
|
562
|
+
|
|
563
|
+
### 同步方向配置
|
|
564
|
+
|
|
565
|
+
```python
|
|
566
|
+
from huace_aigc_auth_client import SyncDirection, create_sync_config
|
|
567
|
+
|
|
568
|
+
# 仅从 auth 同步到旧系统(默认)
|
|
569
|
+
sync_config = create_sync_config(
|
|
570
|
+
direction=SyncDirection.AUTH_TO_LEGACY
|
|
571
|
+
)
|
|
572
|
+
|
|
573
|
+
# 仅从旧系统同步到 auth(初始化用)
|
|
574
|
+
sync_config = create_sync_config(
|
|
575
|
+
direction=SyncDirection.LEGACY_TO_AUTH
|
|
576
|
+
)
|
|
577
|
+
|
|
578
|
+
# 双向同步(需谨慎使用)
|
|
579
|
+
sync_config = create_sync_config(
|
|
580
|
+
direction=SyncDirection.BIDIRECTIONAL
|
|
581
|
+
)
|
|
582
|
+
```
|
|
583
|
+
|
|
584
|
+
---
|
|
585
|
+
|
|
586
|
+
## 导出清单
|
|
587
|
+
|
|
588
|
+
```python
|
|
589
|
+
from huace_aigc_auth_client import (
|
|
590
|
+
# 核心类
|
|
591
|
+
AigcAuthClient,
|
|
592
|
+
require_auth,
|
|
593
|
+
AuthMiddleware,
|
|
594
|
+
UserInfo,
|
|
595
|
+
TokenVerifyResult,
|
|
596
|
+
AigcAuthError,
|
|
597
|
+
create_fastapi_auth_dependency,
|
|
598
|
+
|
|
599
|
+
# 旧系统接入
|
|
600
|
+
LegacySystemAdapter,
|
|
601
|
+
LegacyUserData,
|
|
602
|
+
SyncConfig,
|
|
603
|
+
SyncDirection,
|
|
604
|
+
PasswordMode,
|
|
605
|
+
FieldMapping,
|
|
606
|
+
UserSyncService,
|
|
607
|
+
WebhookSender,
|
|
608
|
+
SyncResult,
|
|
609
|
+
create_sync_config,
|
|
610
|
+
create_default_field_mappings,
|
|
611
|
+
)
|
|
612
|
+
```
|
|
613
|
+
|
|
614
|
+
## 许可证
|
|
615
|
+
|
|
616
|
+
MIT License
|