huace-aigc-auth-client 1.1.0__tar.gz

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