huace-aigc-auth-client 1.1.6__tar.gz → 1.1.8__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.6/huace_aigc_auth_client.egg-info → huace_aigc_auth_client-1.1.8}/PKG-INFO +132 -17
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/README.md +131 -16
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/__init__.py +1 -1
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/legacy_adapter.py +19 -2
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/sdk.py +8 -1
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8/huace_aigc_auth_client.egg-info}/PKG-INFO +132 -17
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/pyproject.toml +1 -1
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/LICENSE +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/MANIFEST.in +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/QUICK_START.txt +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/webhook.py +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client.egg-info/SOURCES.txt +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client.egg-info/dependency_links.txt +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client.egg-info/requires.txt +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client.egg-info/top_level.txt +0 -0
- {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/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.8
|
|
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
|
+
# 可选:鉴权服务地址(默认为生产环境)- 测试环境鉴权地址:http://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
|
+
# 可选:鉴权服务地址(默认为生产环境)- 测试环境鉴权地址:http://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
|
|
|
@@ -147,6 +147,7 @@ class LegacySystemAdapter(ABC):
|
|
|
147
147
|
Returns:
|
|
148
148
|
Optional[LegacyUserData]: 用户数据,不存在返回 None
|
|
149
149
|
"""
|
|
150
|
+
logger.info(f"Fetching user by username asynchronously: {username}")
|
|
150
151
|
raise NotImplementedError("Subclass must implement get_user_by_username_async method")
|
|
151
152
|
|
|
152
153
|
@abstractmethod
|
|
@@ -159,6 +160,7 @@ class LegacySystemAdapter(ABC):
|
|
|
159
160
|
Returns:
|
|
160
161
|
Optional[Any]: 创建的用户 ID 或其他标识
|
|
161
162
|
"""
|
|
163
|
+
logger.info(f"Creating user with data: {user_data}")
|
|
162
164
|
raise NotImplementedError("Subclass must implement _create_user_async method")
|
|
163
165
|
|
|
164
166
|
@abstractmethod
|
|
@@ -172,6 +174,7 @@ class LegacySystemAdapter(ABC):
|
|
|
172
174
|
Returns:
|
|
173
175
|
bool: 更新成功返回 True
|
|
174
176
|
"""
|
|
177
|
+
logger.info(f"Updating user: {username} with data: {user_data}")
|
|
175
178
|
raise NotImplementedError("Subclass must implement _update_user_async method")
|
|
176
179
|
|
|
177
180
|
@abstractmethod
|
|
@@ -184,6 +187,7 @@ class LegacySystemAdapter(ABC):
|
|
|
184
187
|
Returns:
|
|
185
188
|
bool: 删除成功返回 True
|
|
186
189
|
"""
|
|
190
|
+
logger.info(f"Deleting user: {username}")
|
|
187
191
|
raise NotImplementedError("Subclass must implement _delete_user_async method")
|
|
188
192
|
|
|
189
193
|
@abstractmethod
|
|
@@ -193,6 +197,7 @@ class LegacySystemAdapter(ABC):
|
|
|
193
197
|
Returns:
|
|
194
198
|
List[LegacyUserData]: 所有用户数据列表
|
|
195
199
|
"""
|
|
200
|
+
logger.info("Fetching all users from legacy system asynchronously")
|
|
196
201
|
raise NotImplementedError("Subclass must implement get_all_users_async method")
|
|
197
202
|
|
|
198
203
|
async def upsert_user_async(self, user_data: Dict[str, Any], auth_data: Dict[str, Any] = None) -> Dict[str, Any]:
|
|
@@ -208,6 +213,7 @@ class LegacySystemAdapter(ABC):
|
|
|
208
213
|
"""
|
|
209
214
|
username = user_data.get("username")
|
|
210
215
|
if not username:
|
|
216
|
+
logger.error("username is required for upsert operation")
|
|
211
217
|
raise ValueError("username is required for upsert operation")
|
|
212
218
|
|
|
213
219
|
# 检查用户是否存在
|
|
@@ -216,6 +222,7 @@ class LegacySystemAdapter(ABC):
|
|
|
216
222
|
if existing:
|
|
217
223
|
# 用户存在,执行更新
|
|
218
224
|
if not auth_data or auth_data.get("updatedFields") is None or len(auth_data.get("updatedFields")) == 0:
|
|
225
|
+
logger.info(f"No updatedFields provided for user: {username}, skipping update")
|
|
219
226
|
# 如果没有提供 auth_data 或 updatedFields,则不更新
|
|
220
227
|
return {"created": False, "user_id": existing.get("id")}
|
|
221
228
|
await self._update_user_async(username, user_data)
|
|
@@ -234,8 +241,10 @@ class LegacySystemAdapter(ABC):
|
|
|
234
241
|
Dict: 同步结果统计
|
|
235
242
|
"""
|
|
236
243
|
if not self.auth_client:
|
|
244
|
+
logger.error("auth_client is required for batch_sync_to_auth")
|
|
237
245
|
raise ValueError("auth_client is required for batch_sync_to_auth. Please provide it in constructor.")
|
|
238
246
|
|
|
247
|
+
logger.info("Starting batch sync from legacy system to aigc-auth")
|
|
239
248
|
users = await self.get_all_users_async()
|
|
240
249
|
|
|
241
250
|
results = {
|
|
@@ -264,6 +273,7 @@ class LegacySystemAdapter(ABC):
|
|
|
264
273
|
auth_data["password"] = password
|
|
265
274
|
|
|
266
275
|
result = self.auth_client.sync_user_to_auth(auth_data)
|
|
276
|
+
logger.info(f"Sync result for user {user.get('username')}: {result}")
|
|
267
277
|
|
|
268
278
|
if result.get("success"):
|
|
269
279
|
if result.get("created"):
|
|
@@ -277,6 +287,7 @@ class LegacySystemAdapter(ABC):
|
|
|
277
287
|
"error": result.get("message")
|
|
278
288
|
})
|
|
279
289
|
except Exception as e:
|
|
290
|
+
logger.error(f"Error syncing user {user.get('username')}: {e}")
|
|
280
291
|
results["failed"] += 1
|
|
281
292
|
results["errors"].append({
|
|
282
293
|
"user": user.get("username"),
|
|
@@ -311,6 +322,7 @@ class LegacySystemAdapter(ABC):
|
|
|
311
322
|
legacy_data["password"] = password
|
|
312
323
|
|
|
313
324
|
# 创建或更新用户
|
|
325
|
+
logger.info(f"Handling {event} event for user: {legacy_data}")
|
|
314
326
|
result = await self.upsert_user_async(legacy_data)
|
|
315
327
|
|
|
316
328
|
return {
|
|
@@ -321,18 +333,23 @@ class LegacySystemAdapter(ABC):
|
|
|
321
333
|
}
|
|
322
334
|
|
|
323
335
|
elif event == "user.deleted":
|
|
336
|
+
logger.info("Handling user.deleted event")
|
|
324
337
|
# 禁用用户而不是删除
|
|
325
338
|
username = data.get("username")
|
|
326
339
|
if not username:
|
|
340
|
+
logger.error("username is required for user.deleted event")
|
|
327
341
|
logger.error("username is required for user.deleted event")
|
|
328
342
|
return {"success": False, "message": "username is required for user.deleted event"}
|
|
343
|
+
logger.info(f"Disabling user: {username}")
|
|
329
344
|
await self._delete_user_async(username)
|
|
330
345
|
|
|
331
346
|
return {"success": True, "message": "User disabled"}
|
|
332
347
|
|
|
333
348
|
elif event == "user.init_sync_auth":
|
|
349
|
+
logger.info("Handling user.init_sync_auth event")
|
|
334
350
|
# 初始化同步:批量同步旧系统用户到 aigc-auth
|
|
335
351
|
if not self.auth_client:
|
|
352
|
+
logger.error("auth_client is required for init_sync_auth event")
|
|
336
353
|
return {"success": False, "message": "auth_client is required for init_sync_auth event. Please provide it in constructor."}
|
|
337
354
|
|
|
338
355
|
results = await self.batch_sync_to_auth()
|
|
@@ -362,7 +379,7 @@ class LegacySystemAdapter(ABC):
|
|
|
362
379
|
|
|
363
380
|
if auth_value is not None:
|
|
364
381
|
result[mapping.legacy_field] = auth_value
|
|
365
|
-
|
|
382
|
+
logger.info(f"Transformed auth user({auth_user}) to legacy format: {result}")
|
|
366
383
|
return result
|
|
367
384
|
|
|
368
385
|
def transform_legacy_to_auth(self, legacy_user: LegacyUserData) -> Dict[str, Any]:
|
|
@@ -382,7 +399,7 @@ class LegacySystemAdapter(ABC):
|
|
|
382
399
|
|
|
383
400
|
if legacy_value is not None:
|
|
384
401
|
result[mapping.auth_field] = legacy_value
|
|
385
|
-
|
|
402
|
+
logger.info(f"Transformed legacy user({legacy_user}) to auth format: {result}")
|
|
386
403
|
return result
|
|
387
404
|
|
|
388
405
|
def get_password_for_sync(self, legacy_user: Optional[LegacyUserData] = None) -> tuple:
|
|
@@ -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.8
|
|
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
|
+
# 可选:鉴权服务地址(默认为生产环境)- 测试环境鉴权地址:http://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.6 → huace_aigc_auth_client-1.1.8}/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
|