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.
Files changed (16) hide show
  1. {huace_aigc_auth_client-1.1.6/huace_aigc_auth_client.egg-info → huace_aigc_auth_client-1.1.8}/PKG-INFO +132 -17
  2. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/README.md +131 -16
  3. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/__init__.py +1 -1
  4. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/legacy_adapter.py +19 -2
  5. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/sdk.py +8 -1
  6. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8/huace_aigc_auth_client.egg-info}/PKG-INFO +132 -17
  7. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/pyproject.toml +1 -1
  8. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/LICENSE +0 -0
  9. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/MANIFEST.in +0 -0
  10. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/QUICK_START.txt +0 -0
  11. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client/webhook.py +0 -0
  12. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client.egg-info/SOURCES.txt +0 -0
  13. {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
  14. {huace_aigc_auth_client-1.1.6 → huace_aigc_auth_client-1.1.8}/huace_aigc_auth_client.egg-info/requires.txt +0 -0
  15. {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
  16. {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.6
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=Abc@123456
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="Abc@123456",
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=Abc@123456
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="Abc@123456",
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
 
@@ -98,4 +98,4 @@ __all__ = [
98
98
  "register_webhook_router",
99
99
  "verify_webhook_signature",
100
100
  ]
101
- __version__ = "1.1.6"
101
+ __version__ = "1.1.8"
@@ -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.6
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=Abc@123456
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="Abc@123456",
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
 
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "huace-aigc-auth-client"
7
- version = "1.1.6"
7
+ version = "1.1.8"
8
8
  description = "华策AIGC Auth Client - 提供 Token 验证、用户信息获取、权限检查、旧系统接入等功能"
9
9
  readme = "README.md"
10
10
  requires-python = ">=3.7"