huace-aigc-auth-client 1.1.5__tar.gz → 1.1.7__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.5/huace_aigc_auth_client.egg-info → huace_aigc_auth_client-1.1.7}/PKG-INFO +132 -17
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/README.md +131 -16
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client/__init__.py +1 -1
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client/legacy_adapter.py +5 -2
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client/sdk.py +8 -1
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7/huace_aigc_auth_client.egg-info}/PKG-INFO +132 -17
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/pyproject.toml +1 -1
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/LICENSE +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/MANIFEST.in +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/QUICK_START.txt +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client/webhook.py +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client.egg-info/SOURCES.txt +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client.egg-info/dependency_links.txt +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client.egg-info/requires.txt +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client.egg-info/top_level.txt +0 -0
- {huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/setup.cfg +0 -0
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: huace-aigc-auth-client
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.7
|
|
4
4
|
Summary: 华策AIGC Auth Client - 提供 Token 验证、用户信息获取、权限检查、旧系统接入等功能
|
|
5
5
|
Author-email: Huace <support@huace.com>
|
|
6
6
|
License: MIT
|
|
@@ -45,7 +45,7 @@ pip install huace-aigc-auth-client
|
|
|
45
45
|
AIGC_AUTH_APP_ID=your_app_id
|
|
46
46
|
AIGC_AUTH_APP_SECRET=your_app_secret
|
|
47
47
|
|
|
48
|
-
#
|
|
48
|
+
# 可选:鉴权服务地址(默认为生产环境)- 测试环境鉴权地址:https://auth-test.aigc.huacemedia.com/aigc-auth/api/v1
|
|
49
49
|
AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/aigc-auth/api/v1
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -328,21 +328,21 @@ except AigcAuthError as e:
|
|
|
328
328
|
|
|
329
329
|
```
|
|
330
330
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
331
|
-
│ aigc-auth │────▶│ SDK 同步层
|
|
332
|
-
│ (鉴权中心)
|
|
331
|
+
│ aigc-auth │────▶│ SDK 同步层 │────▶│ 旧系统 │
|
|
332
|
+
│ (鉴权中心) │ │ (字段映射) │ │ (用户表) │
|
|
333
333
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
334
334
|
│ │ │
|
|
335
|
-
│ 1. 初始化同步
|
|
335
|
+
│ 1. 初始化同步 │ │
|
|
336
336
|
│◀──────────────────────────────────────────────│
|
|
337
|
-
│ (批量同步旧用户到 auth)
|
|
337
|
+
│ (批量同步旧用户到 auth) │
|
|
338
338
|
│ │ │
|
|
339
|
-
│ 2. 增量同步
|
|
339
|
+
│ 2. 增量同步 │ │
|
|
340
340
|
│──────────────────────▶│──────────────────────▶│
|
|
341
|
-
│ (auth 新用户自动同步到旧系统)
|
|
341
|
+
│ (auth 新用户自动同步到旧系统) │
|
|
342
342
|
│ │ │
|
|
343
|
-
│ 3. Webhook 推送
|
|
343
|
+
│ 3. Webhook 推送 │ │
|
|
344
344
|
│──────────────────────────────────────────────▶│
|
|
345
|
-
│ (用户变更主动通知)
|
|
345
|
+
│ (用户变更主动通知) │
|
|
346
346
|
```
|
|
347
347
|
|
|
348
348
|
### 快速开始
|
|
@@ -357,7 +357,7 @@ AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/aigc-auth/api/v1
|
|
|
357
357
|
|
|
358
358
|
# 同步配置
|
|
359
359
|
AIGC_AUTH_SYNC_ENABLED=true
|
|
360
|
-
AIGC_AUTH_SYNC_PASSWORD
|
|
360
|
+
AIGC_AUTH_SYNC_PASSWORD=通用密码
|
|
361
361
|
AIGC_AUTH_WEBHOOK_URL=https://your-domain.com/api/v1/webhook/auth
|
|
362
362
|
AIGC_AUTH_WEBHOOK_SECRET=your_secret
|
|
363
363
|
```
|
|
@@ -407,7 +407,7 @@ field_mappings = [
|
|
|
407
407
|
sync_config = create_sync_config(
|
|
408
408
|
field_mappings=field_mappings,
|
|
409
409
|
password_mode=PasswordMode.UNIFIED,
|
|
410
|
-
unified_password="
|
|
410
|
+
unified_password="通用密码",
|
|
411
411
|
webhook_url="https://your-domain.com/api/v1/webhook/auth",
|
|
412
412
|
)
|
|
413
413
|
```
|
|
@@ -486,18 +486,94 @@ async def auth_middleware(request, call_next):
|
|
|
486
486
|
|
|
487
487
|
#### 5. 添加 Webhook 接收端点
|
|
488
488
|
|
|
489
|
+
**推荐方式:使用 SDK 提供的通用 Webhook 路由**
|
|
490
|
+
|
|
489
491
|
```python
|
|
492
|
+
from fastapi import APIRouter
|
|
493
|
+
from huace_aigc_auth_client import register_webhook_router
|
|
494
|
+
|
|
495
|
+
api_router = APIRouter()
|
|
496
|
+
|
|
497
|
+
# 定义 webhook 处理函数
|
|
498
|
+
async def handle_webhook(data: dict) -> dict:
|
|
499
|
+
"""
|
|
500
|
+
处理来自 aigc-auth 的 webhook 通知
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
data: webhook 数据,包含 event 和 data 字段
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
dict: 处理结果
|
|
507
|
+
"""
|
|
508
|
+
from your_app.db import get_db_session
|
|
509
|
+
|
|
510
|
+
event = data.get("event")
|
|
511
|
+
user_data = data.get("data", {})
|
|
512
|
+
|
|
513
|
+
# 创建数据库会话
|
|
514
|
+
async with get_db_session() as db:
|
|
515
|
+
adapter = MyLegacyAdapter(db, sync_config)
|
|
516
|
+
|
|
517
|
+
if event == "user.created":
|
|
518
|
+
# 处理用户创建事件
|
|
519
|
+
if not adapter.get_user_by_unique_field(user_data["username"]):
|
|
520
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
521
|
+
legacy_data["password"] = sync_config.unified_password
|
|
522
|
+
adapter.create_user(legacy_data)
|
|
523
|
+
await db.commit()
|
|
524
|
+
|
|
525
|
+
elif event == "user.updated":
|
|
526
|
+
# 处理用户更新事件
|
|
527
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
528
|
+
adapter.update_user(user_data["username"], legacy_data)
|
|
529
|
+
await db.commit()
|
|
530
|
+
|
|
531
|
+
return {"status": "ok", "event": event}
|
|
532
|
+
|
|
533
|
+
# 注册 webhook 路由(自动处理签名验证)
|
|
534
|
+
register_webhook_router(
|
|
535
|
+
api_router,
|
|
536
|
+
handler=handle_webhook,
|
|
537
|
+
prefix="/webhook", # 可选,默认 "/webhook"
|
|
538
|
+
secret_env_key="aigc-auth-webhook-secret", # 可选,在 auth 后台配置
|
|
539
|
+
tags=["Webhook"] # 可选,默认 ["Webhook"]
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
# webhook 端点将自动创建在: /webhook/auth
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**传统方式:手动实现 Webhook 端点**
|
|
546
|
+
|
|
547
|
+
```python
|
|
548
|
+
import hmac
|
|
549
|
+
import hashlib
|
|
550
|
+
import os
|
|
551
|
+
|
|
490
552
|
@app.post("/api/v1/webhook/auth")
|
|
491
553
|
async def receive_auth_webhook(request: Request, db: Session = Depends(get_db)):
|
|
492
554
|
"""接收 aigc-auth 的用户变更通知"""
|
|
555
|
+
# 获取原始请求体
|
|
556
|
+
body = await request.body()
|
|
557
|
+
|
|
558
|
+
# 验证签名
|
|
559
|
+
signature = request.headers.get("X-Webhook-Signature", "")
|
|
560
|
+
secret = os.getenv("AIGC_AUTH_WEBHOOK_SECRET", "")
|
|
561
|
+
|
|
562
|
+
if secret:
|
|
563
|
+
expected = hmac.new(
|
|
564
|
+
secret.encode('utf-8'),
|
|
565
|
+
body,
|
|
566
|
+
hashlib.sha256
|
|
567
|
+
).hexdigest()
|
|
568
|
+
|
|
569
|
+
if not hmac.compare_digest(expected, signature):
|
|
570
|
+
raise HTTPException(status_code=401, detail="Invalid signature")
|
|
571
|
+
|
|
572
|
+
# 解析数据
|
|
493
573
|
data = await request.json()
|
|
494
574
|
event = data.get("event")
|
|
495
575
|
user_data = data.get("data", {})
|
|
496
576
|
|
|
497
|
-
# 验证签名
|
|
498
|
-
signature = request.headers.get("X-Webhook-Signature")
|
|
499
|
-
# ... 验证逻辑
|
|
500
|
-
|
|
501
577
|
if event == "user.created":
|
|
502
578
|
adapter = MyLegacyAdapter(db, sync_config)
|
|
503
579
|
if not adapter.get_user_by_unique_field(user_data["username"]):
|
|
@@ -515,6 +591,14 @@ async def receive_auth_webhook(request: Request, db: Session = Depends(get_db)):
|
|
|
515
591
|
return {"success": True}
|
|
516
592
|
```
|
|
517
593
|
|
|
594
|
+
**Webhook 签名验证说明**
|
|
595
|
+
|
|
596
|
+
SDK 的 `register_webhook_router` 会自动处理签名验证:
|
|
597
|
+
- 从请求头 `X-Webhook-Signature` 获取签名
|
|
598
|
+
- 从环境变量读取密钥(默认 `AIGC_AUTH_WEBHOOK_SECRET`)
|
|
599
|
+
- 使用 HMAC-SHA256 算法验证签名
|
|
600
|
+
- 签名不匹配时返回 401 错误
|
|
601
|
+
|
|
518
602
|
#### 6. 执行初始化同步
|
|
519
603
|
|
|
520
604
|
```python
|
|
@@ -635,10 +719,41 @@ from huace_aigc_auth_client import (
|
|
|
635
719
|
SyncResult,
|
|
636
720
|
create_sync_config,
|
|
637
721
|
create_default_field_mappings,
|
|
722
|
+
|
|
723
|
+
# Webhook 接收
|
|
724
|
+
register_webhook_router,
|
|
725
|
+
verify_webhook_signature,
|
|
638
726
|
)
|
|
639
727
|
```
|
|
640
728
|
|
|
641
|
-
---
|
|
729
|
+
---5 (2026-01-15)
|
|
730
|
+
|
|
731
|
+
#### 新增功能
|
|
732
|
+
|
|
733
|
+
1. **Webhook 接收功能**
|
|
734
|
+
- 新增 `register_webhook_router()` 函数,快速注册 webhook 接收路由
|
|
735
|
+
- 自动处理签名验证、请求解析和错误处理
|
|
736
|
+
- 支持自定义前缀、密钥环境变量和标签
|
|
737
|
+
- 新增 `verify_webhook_signature()` 工具函数
|
|
738
|
+
|
|
739
|
+
#### 使用示例
|
|
740
|
+
|
|
741
|
+
```python
|
|
742
|
+
from fastapi import APIRouter
|
|
743
|
+
from huace_aigc_auth_client import register_webhook_router
|
|
744
|
+
|
|
745
|
+
api_router = APIRouter()
|
|
746
|
+
|
|
747
|
+
async def my_handler(data: dict) -> dict:
|
|
748
|
+
event = data.get("event")
|
|
749
|
+
# 处理逻辑...
|
|
750
|
+
return {"status": "ok"}
|
|
751
|
+
|
|
752
|
+
# 注册 webhook 路由
|
|
753
|
+
register_webhook_router(api_router, my_handler)
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### v1.1.
|
|
642
757
|
|
|
643
758
|
## API 变更日志
|
|
644
759
|
|
|
@@ -20,7 +20,7 @@ pip install huace-aigc-auth-client
|
|
|
20
20
|
AIGC_AUTH_APP_ID=your_app_id
|
|
21
21
|
AIGC_AUTH_APP_SECRET=your_app_secret
|
|
22
22
|
|
|
23
|
-
#
|
|
23
|
+
# 可选:鉴权服务地址(默认为生产环境)- 测试环境鉴权地址:https://auth-test.aigc.huacemedia.com/aigc-auth/api/v1
|
|
24
24
|
AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/aigc-auth/api/v1
|
|
25
25
|
```
|
|
26
26
|
|
|
@@ -303,21 +303,21 @@ except AigcAuthError as e:
|
|
|
303
303
|
|
|
304
304
|
```
|
|
305
305
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
306
|
-
│ aigc-auth │────▶│ SDK 同步层
|
|
307
|
-
│ (鉴权中心)
|
|
306
|
+
│ aigc-auth │────▶│ SDK 同步层 │────▶│ 旧系统 │
|
|
307
|
+
│ (鉴权中心) │ │ (字段映射) │ │ (用户表) │
|
|
308
308
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
309
309
|
│ │ │
|
|
310
|
-
│ 1. 初始化同步
|
|
310
|
+
│ 1. 初始化同步 │ │
|
|
311
311
|
│◀──────────────────────────────────────────────│
|
|
312
|
-
│ (批量同步旧用户到 auth)
|
|
312
|
+
│ (批量同步旧用户到 auth) │
|
|
313
313
|
│ │ │
|
|
314
|
-
│ 2. 增量同步
|
|
314
|
+
│ 2. 增量同步 │ │
|
|
315
315
|
│──────────────────────▶│──────────────────────▶│
|
|
316
|
-
│ (auth 新用户自动同步到旧系统)
|
|
316
|
+
│ (auth 新用户自动同步到旧系统) │
|
|
317
317
|
│ │ │
|
|
318
|
-
│ 3. Webhook 推送
|
|
318
|
+
│ 3. Webhook 推送 │ │
|
|
319
319
|
│──────────────────────────────────────────────▶│
|
|
320
|
-
│ (用户变更主动通知)
|
|
320
|
+
│ (用户变更主动通知) │
|
|
321
321
|
```
|
|
322
322
|
|
|
323
323
|
### 快速开始
|
|
@@ -332,7 +332,7 @@ AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/aigc-auth/api/v1
|
|
|
332
332
|
|
|
333
333
|
# 同步配置
|
|
334
334
|
AIGC_AUTH_SYNC_ENABLED=true
|
|
335
|
-
AIGC_AUTH_SYNC_PASSWORD
|
|
335
|
+
AIGC_AUTH_SYNC_PASSWORD=通用密码
|
|
336
336
|
AIGC_AUTH_WEBHOOK_URL=https://your-domain.com/api/v1/webhook/auth
|
|
337
337
|
AIGC_AUTH_WEBHOOK_SECRET=your_secret
|
|
338
338
|
```
|
|
@@ -382,7 +382,7 @@ field_mappings = [
|
|
|
382
382
|
sync_config = create_sync_config(
|
|
383
383
|
field_mappings=field_mappings,
|
|
384
384
|
password_mode=PasswordMode.UNIFIED,
|
|
385
|
-
unified_password="
|
|
385
|
+
unified_password="通用密码",
|
|
386
386
|
webhook_url="https://your-domain.com/api/v1/webhook/auth",
|
|
387
387
|
)
|
|
388
388
|
```
|
|
@@ -461,18 +461,94 @@ async def auth_middleware(request, call_next):
|
|
|
461
461
|
|
|
462
462
|
#### 5. 添加 Webhook 接收端点
|
|
463
463
|
|
|
464
|
+
**推荐方式:使用 SDK 提供的通用 Webhook 路由**
|
|
465
|
+
|
|
464
466
|
```python
|
|
467
|
+
from fastapi import APIRouter
|
|
468
|
+
from huace_aigc_auth_client import register_webhook_router
|
|
469
|
+
|
|
470
|
+
api_router = APIRouter()
|
|
471
|
+
|
|
472
|
+
# 定义 webhook 处理函数
|
|
473
|
+
async def handle_webhook(data: dict) -> dict:
|
|
474
|
+
"""
|
|
475
|
+
处理来自 aigc-auth 的 webhook 通知
|
|
476
|
+
|
|
477
|
+
Args:
|
|
478
|
+
data: webhook 数据,包含 event 和 data 字段
|
|
479
|
+
|
|
480
|
+
Returns:
|
|
481
|
+
dict: 处理结果
|
|
482
|
+
"""
|
|
483
|
+
from your_app.db import get_db_session
|
|
484
|
+
|
|
485
|
+
event = data.get("event")
|
|
486
|
+
user_data = data.get("data", {})
|
|
487
|
+
|
|
488
|
+
# 创建数据库会话
|
|
489
|
+
async with get_db_session() as db:
|
|
490
|
+
adapter = MyLegacyAdapter(db, sync_config)
|
|
491
|
+
|
|
492
|
+
if event == "user.created":
|
|
493
|
+
# 处理用户创建事件
|
|
494
|
+
if not adapter.get_user_by_unique_field(user_data["username"]):
|
|
495
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
496
|
+
legacy_data["password"] = sync_config.unified_password
|
|
497
|
+
adapter.create_user(legacy_data)
|
|
498
|
+
await db.commit()
|
|
499
|
+
|
|
500
|
+
elif event == "user.updated":
|
|
501
|
+
# 处理用户更新事件
|
|
502
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
503
|
+
adapter.update_user(user_data["username"], legacy_data)
|
|
504
|
+
await db.commit()
|
|
505
|
+
|
|
506
|
+
return {"status": "ok", "event": event}
|
|
507
|
+
|
|
508
|
+
# 注册 webhook 路由(自动处理签名验证)
|
|
509
|
+
register_webhook_router(
|
|
510
|
+
api_router,
|
|
511
|
+
handler=handle_webhook,
|
|
512
|
+
prefix="/webhook", # 可选,默认 "/webhook"
|
|
513
|
+
secret_env_key="aigc-auth-webhook-secret", # 可选,在 auth 后台配置
|
|
514
|
+
tags=["Webhook"] # 可选,默认 ["Webhook"]
|
|
515
|
+
)
|
|
516
|
+
|
|
517
|
+
# webhook 端点将自动创建在: /webhook/auth
|
|
518
|
+
```
|
|
519
|
+
|
|
520
|
+
**传统方式:手动实现 Webhook 端点**
|
|
521
|
+
|
|
522
|
+
```python
|
|
523
|
+
import hmac
|
|
524
|
+
import hashlib
|
|
525
|
+
import os
|
|
526
|
+
|
|
465
527
|
@app.post("/api/v1/webhook/auth")
|
|
466
528
|
async def receive_auth_webhook(request: Request, db: Session = Depends(get_db)):
|
|
467
529
|
"""接收 aigc-auth 的用户变更通知"""
|
|
530
|
+
# 获取原始请求体
|
|
531
|
+
body = await request.body()
|
|
532
|
+
|
|
533
|
+
# 验证签名
|
|
534
|
+
signature = request.headers.get("X-Webhook-Signature", "")
|
|
535
|
+
secret = os.getenv("AIGC_AUTH_WEBHOOK_SECRET", "")
|
|
536
|
+
|
|
537
|
+
if secret:
|
|
538
|
+
expected = hmac.new(
|
|
539
|
+
secret.encode('utf-8'),
|
|
540
|
+
body,
|
|
541
|
+
hashlib.sha256
|
|
542
|
+
).hexdigest()
|
|
543
|
+
|
|
544
|
+
if not hmac.compare_digest(expected, signature):
|
|
545
|
+
raise HTTPException(status_code=401, detail="Invalid signature")
|
|
546
|
+
|
|
547
|
+
# 解析数据
|
|
468
548
|
data = await request.json()
|
|
469
549
|
event = data.get("event")
|
|
470
550
|
user_data = data.get("data", {})
|
|
471
551
|
|
|
472
|
-
# 验证签名
|
|
473
|
-
signature = request.headers.get("X-Webhook-Signature")
|
|
474
|
-
# ... 验证逻辑
|
|
475
|
-
|
|
476
552
|
if event == "user.created":
|
|
477
553
|
adapter = MyLegacyAdapter(db, sync_config)
|
|
478
554
|
if not adapter.get_user_by_unique_field(user_data["username"]):
|
|
@@ -490,6 +566,14 @@ async def receive_auth_webhook(request: Request, db: Session = Depends(get_db)):
|
|
|
490
566
|
return {"success": True}
|
|
491
567
|
```
|
|
492
568
|
|
|
569
|
+
**Webhook 签名验证说明**
|
|
570
|
+
|
|
571
|
+
SDK 的 `register_webhook_router` 会自动处理签名验证:
|
|
572
|
+
- 从请求头 `X-Webhook-Signature` 获取签名
|
|
573
|
+
- 从环境变量读取密钥(默认 `AIGC_AUTH_WEBHOOK_SECRET`)
|
|
574
|
+
- 使用 HMAC-SHA256 算法验证签名
|
|
575
|
+
- 签名不匹配时返回 401 错误
|
|
576
|
+
|
|
493
577
|
#### 6. 执行初始化同步
|
|
494
578
|
|
|
495
579
|
```python
|
|
@@ -610,10 +694,41 @@ from huace_aigc_auth_client import (
|
|
|
610
694
|
SyncResult,
|
|
611
695
|
create_sync_config,
|
|
612
696
|
create_default_field_mappings,
|
|
697
|
+
|
|
698
|
+
# Webhook 接收
|
|
699
|
+
register_webhook_router,
|
|
700
|
+
verify_webhook_signature,
|
|
613
701
|
)
|
|
614
702
|
```
|
|
615
703
|
|
|
616
|
-
---
|
|
704
|
+
---5 (2026-01-15)
|
|
705
|
+
|
|
706
|
+
#### 新增功能
|
|
707
|
+
|
|
708
|
+
1. **Webhook 接收功能**
|
|
709
|
+
- 新增 `register_webhook_router()` 函数,快速注册 webhook 接收路由
|
|
710
|
+
- 自动处理签名验证、请求解析和错误处理
|
|
711
|
+
- 支持自定义前缀、密钥环境变量和标签
|
|
712
|
+
- 新增 `verify_webhook_signature()` 工具函数
|
|
713
|
+
|
|
714
|
+
#### 使用示例
|
|
715
|
+
|
|
716
|
+
```python
|
|
717
|
+
from fastapi import APIRouter
|
|
718
|
+
from huace_aigc_auth_client import register_webhook_router
|
|
719
|
+
|
|
720
|
+
api_router = APIRouter()
|
|
721
|
+
|
|
722
|
+
async def my_handler(data: dict) -> dict:
|
|
723
|
+
event = data.get("event")
|
|
724
|
+
# 处理逻辑...
|
|
725
|
+
return {"status": "ok"}
|
|
726
|
+
|
|
727
|
+
# 注册 webhook 路由
|
|
728
|
+
register_webhook_router(api_router, my_handler)
|
|
729
|
+
```
|
|
730
|
+
|
|
731
|
+
### v1.1.
|
|
617
732
|
|
|
618
733
|
## API 变更日志
|
|
619
734
|
|
|
@@ -195,14 +195,14 @@ class LegacySystemAdapter(ABC):
|
|
|
195
195
|
"""
|
|
196
196
|
raise NotImplementedError("Subclass must implement get_all_users_async method")
|
|
197
197
|
|
|
198
|
-
async def upsert_user_async(self, user_data: Dict[str, Any]) -> Dict[str, Any]:
|
|
198
|
+
async def upsert_user_async(self, user_data: Dict[str, Any], auth_data: Dict[str, Any] = None) -> Dict[str, Any]:
|
|
199
199
|
"""异步创建或更新用户(存在则更新,不存在则新增)
|
|
200
200
|
|
|
201
201
|
这是一个默认实现,子类可以选择性覆盖以优化性能。
|
|
202
202
|
|
|
203
203
|
Args:
|
|
204
204
|
user_data: 用户数据字典(必须包含 username)
|
|
205
|
-
|
|
205
|
+
auth_data: 鉴权系统用户数据字典(可选)
|
|
206
206
|
Returns:
|
|
207
207
|
Dict: 操作结果 {"created": bool, "user_id": Any}
|
|
208
208
|
"""
|
|
@@ -215,6 +215,9 @@ class LegacySystemAdapter(ABC):
|
|
|
215
215
|
|
|
216
216
|
if existing:
|
|
217
217
|
# 用户存在,执行更新
|
|
218
|
+
if not auth_data or auth_data.get("updatedFields") is None or len(auth_data.get("updatedFields")) == 0:
|
|
219
|
+
# 如果没有提供 auth_data 或 updatedFields,则不更新
|
|
220
|
+
return {"created": False, "user_id": existing.get("id")}
|
|
218
221
|
await self._update_user_async(username, user_data)
|
|
219
222
|
return {"created": False, "user_id": existing.get("id")}
|
|
220
223
|
else:
|
|
@@ -92,7 +92,7 @@ class AigcAuthClient:
|
|
|
92
92
|
client = AigcAuthClient(
|
|
93
93
|
app_id="your_app_id",
|
|
94
94
|
app_secret="your_app_secret",
|
|
95
|
-
base_url="https://aigc-auth.huacemedia.com/aigc-auth/api/v1"
|
|
95
|
+
base_url="https://aigc-auth.huacemedia.com/aigc-auth/api/v1"
|
|
96
96
|
)
|
|
97
97
|
|
|
98
98
|
# 验证 token
|
|
@@ -271,6 +271,7 @@ class AigcAuthClient:
|
|
|
271
271
|
result = response.json()
|
|
272
272
|
|
|
273
273
|
if result.get("code") != 0:
|
|
274
|
+
logger.error(f"AigcAuthClient 请求错误: {result}")
|
|
274
275
|
raise AigcAuthError(
|
|
275
276
|
result.get("code", -1),
|
|
276
277
|
result.get("message", "未知错误")
|
|
@@ -285,6 +286,7 @@ class AigcAuthClient:
|
|
|
285
286
|
return response_data
|
|
286
287
|
|
|
287
288
|
except requests.exceptions.RequestException as e:
|
|
289
|
+
logger.error(f"AigcAuthClient 请求失败: {str(e)}")
|
|
288
290
|
raise AigcAuthError(-1, f"请求失败: {str(e)}")
|
|
289
291
|
|
|
290
292
|
def verify_token(self, token: str) -> TokenVerifyResult:
|
|
@@ -599,6 +601,7 @@ class AuthMiddleware:
|
|
|
599
601
|
token = self._extract_token(authorization)
|
|
600
602
|
|
|
601
603
|
if not token:
|
|
604
|
+
logger.warning("AuthMiddleware未提供认证信息")
|
|
602
605
|
return JSONResponse(
|
|
603
606
|
status_code=401,
|
|
604
607
|
content={"code": 401, "message": "未提供认证信息", "data": None}
|
|
@@ -616,6 +619,7 @@ class AuthMiddleware:
|
|
|
616
619
|
if user_info_callback:
|
|
617
620
|
await user_info_callback(request, user_info)
|
|
618
621
|
except AigcAuthError as e:
|
|
622
|
+
logger.error(f"AuthMiddleware认证失败: {e.message}")
|
|
619
623
|
return JSONResponse(
|
|
620
624
|
status_code=401,
|
|
621
625
|
content={"code": e.code, "message": e.message, "data": None}
|
|
@@ -644,6 +648,7 @@ class AuthMiddleware:
|
|
|
644
648
|
token = self._extract_token(authorization)
|
|
645
649
|
|
|
646
650
|
if not token:
|
|
651
|
+
logger.warning("AuthMiddleware未提供认证信息")
|
|
647
652
|
return jsonify({
|
|
648
653
|
"code": 401,
|
|
649
654
|
"message": "未提供认证信息",
|
|
@@ -658,6 +663,7 @@ class AuthMiddleware:
|
|
|
658
663
|
if user_info_callback:
|
|
659
664
|
user_info_callback(request, user_info)
|
|
660
665
|
except AigcAuthError as e:
|
|
666
|
+
logger.error(f"AuthMiddleware认证失败: {e.message}")
|
|
661
667
|
return jsonify({
|
|
662
668
|
"code": e.code,
|
|
663
669
|
"message": e.message,
|
|
@@ -712,6 +718,7 @@ def create_fastapi_auth_dependency(client: AigcAuthClient):
|
|
|
712
718
|
user_info = client.get_user_info_from_header(authorization)
|
|
713
719
|
|
|
714
720
|
if user_info is None:
|
|
721
|
+
logger.warning("FastAPI依赖未登录或Token已过期")
|
|
715
722
|
raise HTTPException(status_code=401, detail="未登录或 Token 已过期")
|
|
716
723
|
|
|
717
724
|
return user_info
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
Metadata-Version: 2.4
|
|
2
2
|
Name: huace-aigc-auth-client
|
|
3
|
-
Version: 1.1.
|
|
3
|
+
Version: 1.1.7
|
|
4
4
|
Summary: 华策AIGC Auth Client - 提供 Token 验证、用户信息获取、权限检查、旧系统接入等功能
|
|
5
5
|
Author-email: Huace <support@huace.com>
|
|
6
6
|
License: MIT
|
|
@@ -45,7 +45,7 @@ pip install huace-aigc-auth-client
|
|
|
45
45
|
AIGC_AUTH_APP_ID=your_app_id
|
|
46
46
|
AIGC_AUTH_APP_SECRET=your_app_secret
|
|
47
47
|
|
|
48
|
-
#
|
|
48
|
+
# 可选:鉴权服务地址(默认为生产环境)- 测试环境鉴权地址:https://auth-test.aigc.huacemedia.com/aigc-auth/api/v1
|
|
49
49
|
AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/aigc-auth/api/v1
|
|
50
50
|
```
|
|
51
51
|
|
|
@@ -328,21 +328,21 @@ except AigcAuthError as e:
|
|
|
328
328
|
|
|
329
329
|
```
|
|
330
330
|
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
|
|
331
|
-
│ aigc-auth │────▶│ SDK 同步层
|
|
332
|
-
│ (鉴权中心)
|
|
331
|
+
│ aigc-auth │────▶│ SDK 同步层 │────▶│ 旧系统 │
|
|
332
|
+
│ (鉴权中心) │ │ (字段映射) │ │ (用户表) │
|
|
333
333
|
└─────────────────┘ └─────────────────┘ └─────────────────┘
|
|
334
334
|
│ │ │
|
|
335
|
-
│ 1. 初始化同步
|
|
335
|
+
│ 1. 初始化同步 │ │
|
|
336
336
|
│◀──────────────────────────────────────────────│
|
|
337
|
-
│ (批量同步旧用户到 auth)
|
|
337
|
+
│ (批量同步旧用户到 auth) │
|
|
338
338
|
│ │ │
|
|
339
|
-
│ 2. 增量同步
|
|
339
|
+
│ 2. 增量同步 │ │
|
|
340
340
|
│──────────────────────▶│──────────────────────▶│
|
|
341
|
-
│ (auth 新用户自动同步到旧系统)
|
|
341
|
+
│ (auth 新用户自动同步到旧系统) │
|
|
342
342
|
│ │ │
|
|
343
|
-
│ 3. Webhook 推送
|
|
343
|
+
│ 3. Webhook 推送 │ │
|
|
344
344
|
│──────────────────────────────────────────────▶│
|
|
345
|
-
│ (用户变更主动通知)
|
|
345
|
+
│ (用户变更主动通知) │
|
|
346
346
|
```
|
|
347
347
|
|
|
348
348
|
### 快速开始
|
|
@@ -357,7 +357,7 @@ AIGC_AUTH_BASE_URL=https://aigc-auth.huacemedia.com/aigc-auth/api/v1
|
|
|
357
357
|
|
|
358
358
|
# 同步配置
|
|
359
359
|
AIGC_AUTH_SYNC_ENABLED=true
|
|
360
|
-
AIGC_AUTH_SYNC_PASSWORD
|
|
360
|
+
AIGC_AUTH_SYNC_PASSWORD=通用密码
|
|
361
361
|
AIGC_AUTH_WEBHOOK_URL=https://your-domain.com/api/v1/webhook/auth
|
|
362
362
|
AIGC_AUTH_WEBHOOK_SECRET=your_secret
|
|
363
363
|
```
|
|
@@ -407,7 +407,7 @@ field_mappings = [
|
|
|
407
407
|
sync_config = create_sync_config(
|
|
408
408
|
field_mappings=field_mappings,
|
|
409
409
|
password_mode=PasswordMode.UNIFIED,
|
|
410
|
-
unified_password="
|
|
410
|
+
unified_password="通用密码",
|
|
411
411
|
webhook_url="https://your-domain.com/api/v1/webhook/auth",
|
|
412
412
|
)
|
|
413
413
|
```
|
|
@@ -486,18 +486,94 @@ async def auth_middleware(request, call_next):
|
|
|
486
486
|
|
|
487
487
|
#### 5. 添加 Webhook 接收端点
|
|
488
488
|
|
|
489
|
+
**推荐方式:使用 SDK 提供的通用 Webhook 路由**
|
|
490
|
+
|
|
489
491
|
```python
|
|
492
|
+
from fastapi import APIRouter
|
|
493
|
+
from huace_aigc_auth_client import register_webhook_router
|
|
494
|
+
|
|
495
|
+
api_router = APIRouter()
|
|
496
|
+
|
|
497
|
+
# 定义 webhook 处理函数
|
|
498
|
+
async def handle_webhook(data: dict) -> dict:
|
|
499
|
+
"""
|
|
500
|
+
处理来自 aigc-auth 的 webhook 通知
|
|
501
|
+
|
|
502
|
+
Args:
|
|
503
|
+
data: webhook 数据,包含 event 和 data 字段
|
|
504
|
+
|
|
505
|
+
Returns:
|
|
506
|
+
dict: 处理结果
|
|
507
|
+
"""
|
|
508
|
+
from your_app.db import get_db_session
|
|
509
|
+
|
|
510
|
+
event = data.get("event")
|
|
511
|
+
user_data = data.get("data", {})
|
|
512
|
+
|
|
513
|
+
# 创建数据库会话
|
|
514
|
+
async with get_db_session() as db:
|
|
515
|
+
adapter = MyLegacyAdapter(db, sync_config)
|
|
516
|
+
|
|
517
|
+
if event == "user.created":
|
|
518
|
+
# 处理用户创建事件
|
|
519
|
+
if not adapter.get_user_by_unique_field(user_data["username"]):
|
|
520
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
521
|
+
legacy_data["password"] = sync_config.unified_password
|
|
522
|
+
adapter.create_user(legacy_data)
|
|
523
|
+
await db.commit()
|
|
524
|
+
|
|
525
|
+
elif event == "user.updated":
|
|
526
|
+
# 处理用户更新事件
|
|
527
|
+
legacy_data = adapter.transform_auth_to_legacy(user_data)
|
|
528
|
+
adapter.update_user(user_data["username"], legacy_data)
|
|
529
|
+
await db.commit()
|
|
530
|
+
|
|
531
|
+
return {"status": "ok", "event": event}
|
|
532
|
+
|
|
533
|
+
# 注册 webhook 路由(自动处理签名验证)
|
|
534
|
+
register_webhook_router(
|
|
535
|
+
api_router,
|
|
536
|
+
handler=handle_webhook,
|
|
537
|
+
prefix="/webhook", # 可选,默认 "/webhook"
|
|
538
|
+
secret_env_key="aigc-auth-webhook-secret", # 可选,在 auth 后台配置
|
|
539
|
+
tags=["Webhook"] # 可选,默认 ["Webhook"]
|
|
540
|
+
)
|
|
541
|
+
|
|
542
|
+
# webhook 端点将自动创建在: /webhook/auth
|
|
543
|
+
```
|
|
544
|
+
|
|
545
|
+
**传统方式:手动实现 Webhook 端点**
|
|
546
|
+
|
|
547
|
+
```python
|
|
548
|
+
import hmac
|
|
549
|
+
import hashlib
|
|
550
|
+
import os
|
|
551
|
+
|
|
490
552
|
@app.post("/api/v1/webhook/auth")
|
|
491
553
|
async def receive_auth_webhook(request: Request, db: Session = Depends(get_db)):
|
|
492
554
|
"""接收 aigc-auth 的用户变更通知"""
|
|
555
|
+
# 获取原始请求体
|
|
556
|
+
body = await request.body()
|
|
557
|
+
|
|
558
|
+
# 验证签名
|
|
559
|
+
signature = request.headers.get("X-Webhook-Signature", "")
|
|
560
|
+
secret = os.getenv("AIGC_AUTH_WEBHOOK_SECRET", "")
|
|
561
|
+
|
|
562
|
+
if secret:
|
|
563
|
+
expected = hmac.new(
|
|
564
|
+
secret.encode('utf-8'),
|
|
565
|
+
body,
|
|
566
|
+
hashlib.sha256
|
|
567
|
+
).hexdigest()
|
|
568
|
+
|
|
569
|
+
if not hmac.compare_digest(expected, signature):
|
|
570
|
+
raise HTTPException(status_code=401, detail="Invalid signature")
|
|
571
|
+
|
|
572
|
+
# 解析数据
|
|
493
573
|
data = await request.json()
|
|
494
574
|
event = data.get("event")
|
|
495
575
|
user_data = data.get("data", {})
|
|
496
576
|
|
|
497
|
-
# 验证签名
|
|
498
|
-
signature = request.headers.get("X-Webhook-Signature")
|
|
499
|
-
# ... 验证逻辑
|
|
500
|
-
|
|
501
577
|
if event == "user.created":
|
|
502
578
|
adapter = MyLegacyAdapter(db, sync_config)
|
|
503
579
|
if not adapter.get_user_by_unique_field(user_data["username"]):
|
|
@@ -515,6 +591,14 @@ async def receive_auth_webhook(request: Request, db: Session = Depends(get_db)):
|
|
|
515
591
|
return {"success": True}
|
|
516
592
|
```
|
|
517
593
|
|
|
594
|
+
**Webhook 签名验证说明**
|
|
595
|
+
|
|
596
|
+
SDK 的 `register_webhook_router` 会自动处理签名验证:
|
|
597
|
+
- 从请求头 `X-Webhook-Signature` 获取签名
|
|
598
|
+
- 从环境变量读取密钥(默认 `AIGC_AUTH_WEBHOOK_SECRET`)
|
|
599
|
+
- 使用 HMAC-SHA256 算法验证签名
|
|
600
|
+
- 签名不匹配时返回 401 错误
|
|
601
|
+
|
|
518
602
|
#### 6. 执行初始化同步
|
|
519
603
|
|
|
520
604
|
```python
|
|
@@ -635,10 +719,41 @@ from huace_aigc_auth_client import (
|
|
|
635
719
|
SyncResult,
|
|
636
720
|
create_sync_config,
|
|
637
721
|
create_default_field_mappings,
|
|
722
|
+
|
|
723
|
+
# Webhook 接收
|
|
724
|
+
register_webhook_router,
|
|
725
|
+
verify_webhook_signature,
|
|
638
726
|
)
|
|
639
727
|
```
|
|
640
728
|
|
|
641
|
-
---
|
|
729
|
+
---5 (2026-01-15)
|
|
730
|
+
|
|
731
|
+
#### 新增功能
|
|
732
|
+
|
|
733
|
+
1. **Webhook 接收功能**
|
|
734
|
+
- 新增 `register_webhook_router()` 函数,快速注册 webhook 接收路由
|
|
735
|
+
- 自动处理签名验证、请求解析和错误处理
|
|
736
|
+
- 支持自定义前缀、密钥环境变量和标签
|
|
737
|
+
- 新增 `verify_webhook_signature()` 工具函数
|
|
738
|
+
|
|
739
|
+
#### 使用示例
|
|
740
|
+
|
|
741
|
+
```python
|
|
742
|
+
from fastapi import APIRouter
|
|
743
|
+
from huace_aigc_auth_client import register_webhook_router
|
|
744
|
+
|
|
745
|
+
api_router = APIRouter()
|
|
746
|
+
|
|
747
|
+
async def my_handler(data: dict) -> dict:
|
|
748
|
+
event = data.get("event")
|
|
749
|
+
# 处理逻辑...
|
|
750
|
+
return {"status": "ok"}
|
|
751
|
+
|
|
752
|
+
# 注册 webhook 路由
|
|
753
|
+
register_webhook_router(api_router, my_handler)
|
|
754
|
+
```
|
|
755
|
+
|
|
756
|
+
### v1.1.
|
|
642
757
|
|
|
643
758
|
## API 变更日志
|
|
644
759
|
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
{huace_aigc_auth_client-1.1.5 → huace_aigc_auth_client-1.1.7}/huace_aigc_auth_client/webhook.py
RENAMED
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|