huace-aigc-auth-client 1.1.30__py3-none-any.whl → 1.1.32__py3-none-any.whl

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.
@@ -54,7 +54,21 @@ from .sdk import (
54
54
  create_fastapi_auth_dependency
55
55
  )
56
56
 
57
- from .user_context import get_current_user
57
+ from .user_context import (
58
+ get_current_user, add_to_request_context, clear_request_context, set_request_context, get_request_context, get_client_ip, get_user_agent, get_request_id, get_trace_id, get_request_token, get_request_app_id, get_request_app_secret
59
+ )
60
+
61
+ from .api_stats_collector import (
62
+ init_api_stats_collector,
63
+ get_api_stats_collector,
64
+ collect_api_stat,
65
+ stop_api_stats_collector
66
+ )
67
+
68
+ from .auth_request import (
69
+ auth_request,
70
+ async_auth_httpx_request
71
+ )
58
72
 
59
73
  from .legacy_adapter import (
60
74
  LegacySystemAdapter,
@@ -130,6 +144,12 @@ def setLogger(log):
130
144
  except Exception as e:
131
145
  print(f"Failed to set logger for api_stats_collector module: {e}")
132
146
 
147
+ try:
148
+ from .auth_request import setLogger as auth_request_setLogger
149
+ auth_request_setLogger(log)
150
+ except Exception as e:
151
+ print(f"Failed to set logger for auth_request module: {e}")
152
+
133
153
  if _fastapi_available:
134
154
  try:
135
155
  from .webhook import setLogger as webhook_setLogger
@@ -177,5 +197,24 @@ __all__ = [
177
197
  "setLogger",
178
198
  # 用户上下文
179
199
  "get_current_user",
200
+ "add_to_request_context",
201
+ "clear_request_context",
202
+ "set_request_context",
203
+ "get_request_context",
204
+ "get_client_ip",
205
+ "get_user_agent",
206
+ "get_request_id",
207
+ "get_trace_id",
208
+ "get_request_token",
209
+ "get_request_app_id",
210
+ "get_request_app_secret",
211
+ # API 统计收集器
212
+ "init_api_stats_collector",
213
+ "get_api_stats_collector",
214
+ "collect_api_stat",
215
+ "stop_api_stats_collector",
216
+ # 认证请求封装
217
+ "auth_request",
218
+ "async_auth_httpx_request",
180
219
  ]
181
- __version__ = "1.1.30"
220
+ __version__ = "1.1.32"
@@ -1,6 +1,6 @@
1
1
  """
2
2
  认证请求封装模块
3
- 提供对 requests.request 的封装,自动添加认证信息和统计上报
3
+ 提供对 requests.request 和 httpx 的封装,自动添加认证信息和统计上报
4
4
  """
5
5
  import time
6
6
  import logging
@@ -8,11 +8,26 @@ from typing import Optional, Dict, Any, Union
8
8
  import requests
9
9
  from requests import Response
10
10
 
11
+ try:
12
+ import httpx
13
+ HTTPX_AVAILABLE = True
14
+ except ImportError:
15
+ HTTPX_AVAILABLE = False
16
+ httpx = None
17
+
11
18
  from .user_context import get_request_context
12
19
  from .api_stats_collector import get_api_stats_collector
13
20
 
14
21
  logger = logging.getLogger(__name__)
15
-
22
+ def setLogger(log):
23
+ """
24
+ 统一设置所有模块的 logger
25
+
26
+ Args:
27
+ log: logging.Logger 实例
28
+ """
29
+ global logger
30
+ logger = log
16
31
 
17
32
  def auth_request(
18
33
  method: str,
@@ -232,6 +247,324 @@ def _report_stats(
232
247
  logger.debug(f"统计上报失败: {e}")
233
248
 
234
249
 
250
+ # ============ HTTPX 异步请求封装 ============
251
+
252
+ if HTTPX_AVAILABLE:
253
+
254
+ async def async_auth_httpx_request(
255
+ method: str,
256
+ url: str,
257
+ params: Optional[Dict[str, Any]] = None,
258
+ data: Optional[Union[Dict[str, Any], str, bytes]] = None,
259
+ json: Optional[Dict[str, Any]] = None,
260
+ headers: Optional[Dict[str, str]] = None,
261
+ cookies: Optional[Dict[str, str]] = None,
262
+ files: Optional[Dict[str, Any]] = None,
263
+ auth: Optional[tuple] = None,
264
+ timeout: Optional[Union[float, httpx.Timeout]] = None,
265
+ follow_redirects: bool = True,
266
+ **kwargs
267
+ ) -> httpx.Response:
268
+ """
269
+ 异步认证请求封装函数(httpx)
270
+
271
+ 基本参数与 httpx.request 一致,会自动从 request_context 中获取认证信息并添加到请求头
272
+
273
+ Args:
274
+ method: HTTP 方法 (GET, POST, PUT, DELETE 等)
275
+ url: 请求 URL
276
+ params: URL 查询参数
277
+ data: 请求体数据 (form-data 或 raw)
278
+ json: JSON 请求体数据
279
+ headers: 请求头(会自动添加认证相关的头)
280
+ cookies: Cookies
281
+ files: 文件上传
282
+ auth: HTTP 认证元组
283
+ timeout: 超时时间(秒)
284
+ follow_redirects: 是否允许重定向
285
+ **kwargs: 其他 httpx.request 支持的参数
286
+
287
+ Returns:
288
+ httpx.Response: 响应对象
289
+
290
+ 自动添加的请求头(如果在 request_context 中存在):
291
+ - X-App-ID: 应用ID
292
+ - X-App-Secret: 应用密钥
293
+ - Authorization: Bearer token
294
+ - x-real-ip: 客户端真实IP
295
+ - user-agent: User Agent
296
+ - X-Trace-ID: 追踪ID
297
+ """
298
+ # 初始化 headers
299
+ if headers is None:
300
+ headers = {}
301
+ else:
302
+ headers = headers.copy() # 避免修改原始 headers
303
+
304
+ # 从 request_context 获取认证信息
305
+ request_context = get_request_context()
306
+
307
+ if request_context:
308
+ # 添加应用ID
309
+ app_id = request_context.get('app_id')
310
+ if app_id is not None:
311
+ headers['X-App-ID'] = str(app_id)
312
+
313
+ # 添加应用密钥
314
+ app_secret = request_context.get('app_secret')
315
+ if app_secret:
316
+ headers['X-App-Secret'] = app_secret
317
+
318
+ # 添加认证令牌
319
+ token = request_context.get('token')
320
+ if token:
321
+ headers['Authorization'] = f'Bearer {token}'
322
+
323
+ # 添加客户端IP
324
+ ip_address = request_context.get('ip_address')
325
+ if ip_address:
326
+ headers['x-real-ip'] = ip_address
327
+
328
+ # 添加 User Agent
329
+ user_agent = request_context.get('user_agent')
330
+ if user_agent:
331
+ headers['user-agent'] = user_agent
332
+
333
+ # 添加追踪ID
334
+ trace_id = request_context.get('trace_id')
335
+ if trace_id:
336
+ headers['X-Trace-ID'] = trace_id
337
+
338
+ # 记录开始时间
339
+ start_time = time.time()
340
+ response = None
341
+ error_message = None
342
+
343
+ try:
344
+ # 执行异步请求
345
+ logger.info(f"发起异步认证请求: {method} {url} with headers={headers} params={params} json={json} data={data}")
346
+
347
+ async with httpx.AsyncClient(timeout=timeout) as client:
348
+ response = await client.request(
349
+ method=method,
350
+ url=url,
351
+ params=params,
352
+ data=data,
353
+ json=json,
354
+ headers=headers,
355
+ cookies=cookies,
356
+ files=files,
357
+ auth=auth,
358
+ follow_redirects=follow_redirects,
359
+ **kwargs
360
+ )
361
+
362
+ logger.info(f"异步认证请求响应: {method} {url} 状态码: {response.status_code}")
363
+ return response
364
+
365
+ except Exception as e:
366
+ error_message = str(e)
367
+ logger.error(f"异步认证请求失败: {method} {url} 错误: {error_message}")
368
+ raise
369
+
370
+ finally:
371
+ # 计算响应时间
372
+ response_time = time.time() - start_time
373
+
374
+ # 上报统计信息
375
+ _report_stats(
376
+ url=url,
377
+ method=method,
378
+ response=response,
379
+ response_time=response_time,
380
+ error_message=error_message,
381
+ request_context=request_context,
382
+ headers=headers,
383
+ params=params,
384
+ json_data=json,
385
+ form_data=data
386
+ )
387
+
388
+
389
+ class AsyncAuthClient:
390
+ """
391
+ 异步认证客户端(httpx.AsyncClient 包装)
392
+
393
+ 提供可复用的异步 HTTP 客户端,自动处理认证信息和统计上报
394
+ """
395
+
396
+ def __init__(
397
+ self,
398
+ base_url: Optional[str] = None,
399
+ timeout: Optional[Union[float, httpx.Timeout]] = None,
400
+ follow_redirects: bool = True,
401
+ **kwargs
402
+ ):
403
+ """
404
+ 初始化异步认证客户端
405
+
406
+ Args:
407
+ base_url: 基础 URL
408
+ timeout: 超时配置
409
+ follow_redirects: 是否允许重定向
410
+ **kwargs: 其他 httpx.AsyncClient 支持的参数
411
+ """
412
+ self.base_url = base_url
413
+ self.timeout = timeout
414
+ self.follow_redirects = follow_redirects
415
+ self.client_kwargs = kwargs
416
+ self._client: Optional[httpx.AsyncClient] = None
417
+
418
+ async def __aenter__(self):
419
+ """进入异步上下文"""
420
+ self._client = httpx.AsyncClient(
421
+ base_url=self.base_url,
422
+ timeout=self.timeout,
423
+ follow_redirects=self.follow_redirects,
424
+ **self.client_kwargs
425
+ )
426
+ return self
427
+
428
+ async def __aexit__(self, exc_type, exc_val, exc_tb):
429
+ """退出异步上下文"""
430
+ if self._client:
431
+ await self._client.aclose()
432
+ self._client = None
433
+
434
+ def _prepare_headers(self, headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
435
+ """准备请求头(添加认证信息)"""
436
+ # 初始化 headers
437
+ if headers is None:
438
+ headers = {}
439
+ else:
440
+ headers = headers.copy()
441
+
442
+ # 从 request_context 获取认证信息
443
+ request_context = get_request_context()
444
+
445
+ if request_context:
446
+ # 添加应用ID
447
+ app_id = request_context.get('app_id')
448
+ if app_id is not None:
449
+ headers['X-App-ID'] = str(app_id)
450
+
451
+ # 添加应用密钥
452
+ app_secret = request_context.get('app_secret')
453
+ if app_secret:
454
+ headers['X-App-Secret'] = app_secret
455
+
456
+ # 添加认证令牌
457
+ token = request_context.get('token')
458
+ if token:
459
+ headers['Authorization'] = f'Bearer {token}'
460
+
461
+ # 添加客户端IP
462
+ ip_address = request_context.get('ip_address')
463
+ if ip_address:
464
+ headers['x-real-ip'] = ip_address
465
+
466
+ # 添加 User Agent
467
+ user_agent = request_context.get('user_agent')
468
+ if user_agent:
469
+ headers['user-agent'] = user_agent
470
+
471
+ # 添加追踪ID
472
+ trace_id = request_context.get('trace_id')
473
+ if trace_id:
474
+ headers['X-Trace-ID'] = trace_id
475
+
476
+ return headers
477
+
478
+ async def _request(
479
+ self,
480
+ method: str,
481
+ url: str,
482
+ **kwargs
483
+ ) -> httpx.Response:
484
+ """执行请求(内部方法)"""
485
+ if self._client is None:
486
+ raise RuntimeError("Client not initialized. Use 'async with AsyncAuthClient()' context manager.")
487
+
488
+ # 准备 headers
489
+ headers = kwargs.pop('headers', None)
490
+ headers = self._prepare_headers(headers)
491
+
492
+ # 提取参数用于统计
493
+ params = kwargs.get('params')
494
+ json_data = kwargs.get('json')
495
+ form_data = kwargs.get('data')
496
+
497
+ # 记录开始时间
498
+ start_time = time.time()
499
+ response = None
500
+ error_message = None
501
+ request_context = get_request_context()
502
+
503
+ try:
504
+ # 执行请求
505
+ logger.info(f"AsyncAuthClient 发起请求: {method} {url} with headers={headers}")
506
+ response = await self._client.request(
507
+ method=method,
508
+ url=url,
509
+ headers=headers,
510
+ **kwargs
511
+ )
512
+ logger.info(f"AsyncAuthClient 请求响应: {method} {url} 状态码: {response.status_code}")
513
+ return response
514
+
515
+ except Exception as e:
516
+ error_message = str(e)
517
+ logger.error(f"AsyncAuthClient 请求失败: {method} {url} 错误: {error_message}")
518
+ raise
519
+
520
+ finally:
521
+ # 计算响应时间
522
+ response_time = time.time() - start_time
523
+
524
+ # 上报统计信息
525
+ full_url = str(self._client.build_request(method, url).url) if self._client else url
526
+ _report_stats(
527
+ url=full_url,
528
+ method=method,
529
+ response=response,
530
+ response_time=response_time,
531
+ error_message=error_message,
532
+ request_context=request_context,
533
+ headers=headers,
534
+ params=params,
535
+ json_data=json_data,
536
+ form_data=form_data
537
+ )
538
+
539
+ async def get(self, url: str, **kwargs) -> httpx.Response:
540
+ """GET 请求"""
541
+ return await self._request('GET', url, **kwargs)
542
+
543
+ async def post(self, url: str, **kwargs) -> httpx.Response:
544
+ """POST 请求"""
545
+ return await self._request('POST', url, **kwargs)
546
+
547
+ async def put(self, url: str, **kwargs) -> httpx.Response:
548
+ """PUT 请求"""
549
+ return await self._request('PUT', url, **kwargs)
550
+
551
+ async def delete(self, url: str, **kwargs) -> httpx.Response:
552
+ """DELETE 请求"""
553
+ return await self._request('DELETE', url, **kwargs)
554
+
555
+ async def patch(self, url: str, **kwargs) -> httpx.Response:
556
+ """PATCH 请求"""
557
+ return await self._request('PATCH', url, **kwargs)
558
+
559
+ async def head(self, url: str, **kwargs) -> httpx.Response:
560
+ """HEAD 请求"""
561
+ return await self._request('HEAD', url, **kwargs)
562
+
563
+ async def options(self, url: str, **kwargs) -> httpx.Response:
564
+ """OPTIONS 请求"""
565
+ return await self._request('OPTIONS', url, **kwargs)
566
+
567
+
235
568
  # ============ 使用示例 ============
236
569
  """
237
570
  使用示例:
@@ -313,4 +646,44 @@ def _report_stats(
313
646
 
314
647
  # 发起请求(会自动上报统计)
315
648
  response = auth_request('GET', 'https://api.example.com/data')
649
+
650
+
651
+ 5. 使用 httpx 异步请求(需要安装 httpx):
652
+
653
+ from huace_aigc_auth_client.auth_request import async_auth_request, AsyncAuthClient
654
+ from huace_aigc_auth_client.user_context import set_request_context
655
+ import asyncio
656
+
657
+ # 设置请求上下文
658
+ set_request_context(
659
+ app_id='your-app-id',
660
+ app_secret='your-app-secret',
661
+ token='user-access-token'
662
+ )
663
+
664
+ # 方式1:使用 async_auth_request 函数
665
+ async def example1():
666
+ response = await async_auth_request('GET', 'https://api.example.com/data')
667
+ print(response.json())
668
+
669
+ # 方式2:使用 AsyncAuthClient(推荐用于多个请求)
670
+ async def example2():
671
+ async with AsyncAuthClient(timeout=10.0) as client:
672
+ # POST 请求带 JSON
673
+ response = await client.post(
674
+ 'https://api.example.com/users',
675
+ json={'name': 'John', 'email': 'john@example.com'}
676
+ )
677
+ print(response.json())
678
+
679
+ # GET 请求带参数
680
+ response = await client.get(
681
+ 'https://api.example.com/users',
682
+ params={'page': 1, 'size': 10}
683
+ )
684
+ print(response.json())
685
+
686
+ # 运行
687
+ asyncio.run(example1())
688
+ asyncio.run(example2())
316
689
  """
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: huace-aigc-auth-client
3
- Version: 1.1.30
3
+ Version: 1.1.32
4
4
  Summary: 华策AIGC Auth Client - 提供 Token 验证、用户信息获取、权限检查、旧系统接入等功能
5
5
  Author-email: Huace <support@huace.com>
6
6
  License: MIT
@@ -1,13 +1,13 @@
1
- huace_aigc_auth_client/__init__.py,sha256=9wZM_9CM2SukN3pw2JpiXe-oVqXh0FD3h0y4S8ueckQ,4857
1
+ huace_aigc_auth_client/__init__.py,sha256=t5GBEVaTo-vcjRWWbI-SG51-fR1AFzZK9Cuz3wQC5a8,6020
2
2
  huace_aigc_auth_client/api_stats_collector.py,sha256=ADpjpHXMqn80YI4UltWHbzAO_szykU9ZCvwXgBRWFIM,11046
3
- huace_aigc_auth_client/auth_request.py,sha256=f7KgmyamoEk1HWP-47nCxUBnOgRbQjYnnNZ7yRzb4j0,9285
3
+ huace_aigc_auth_client/auth_request.py,sha256=lNIVytSpmbr2oYHEMuXX032cLo323IPhr7eK_KaCqVs,22564
4
4
  huace_aigc_auth_client/legacy_adapter.py,sha256=TVCBAKejE2z2HQFsEwDW8LMiaIkXNfz3Mxv6_E-UJFY,24102
5
5
  huace_aigc_auth_client/sdk.py,sha256=rproo913OAi37wz_rMYgxzP3F1YyY3nc5e35JS5WvoY,37751
6
6
  huace_aigc_auth_client/user_context.py,sha256=IqdX6Xd2jJwvij6Hc2qWAFWj5pn3wHqk0RBsaXKLP8g,6795
7
7
  huace_aigc_auth_client/webhook.py,sha256=XQZYEbMoqIdqZWCGSTcedeDKJpDbUVSq5g08g-6Qucg,4124
8
8
  huace_aigc_auth_client/webhook_flask.py,sha256=Iosu4dBtRhQZM_ytn-bn82MpVsyOiV28FBnt7Tfh31U,7225
9
- huace_aigc_auth_client-1.1.30.dist-info/licenses/LICENSE,sha256=z7dgC7KljhBLNvKjN15391nMj3aLt0gbud8-Yf1F8EQ,1063
10
- huace_aigc_auth_client-1.1.30.dist-info/METADATA,sha256=3rtqM-PxSFyXEc0l_UW2gy6R5rN-J81VpKfuMgVNfYI,23629
11
- huace_aigc_auth_client-1.1.30.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
12
- huace_aigc_auth_client-1.1.30.dist-info/top_level.txt,sha256=kbv0nQ6PQ0JVneWPH7O2AbtlJnP7AjvFJ6JjM6ZEBxo,23
13
- huace_aigc_auth_client-1.1.30.dist-info/RECORD,,
9
+ huace_aigc_auth_client-1.1.32.dist-info/licenses/LICENSE,sha256=z7dgC7KljhBLNvKjN15391nMj3aLt0gbud8-Yf1F8EQ,1063
10
+ huace_aigc_auth_client-1.1.32.dist-info/METADATA,sha256=YdHV3D86QX4XloiBoP3ydX5Wmph2Wuscwx6mPUTUUBQ,23629
11
+ huace_aigc_auth_client-1.1.32.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
12
+ huace_aigc_auth_client-1.1.32.dist-info/top_level.txt,sha256=kbv0nQ6PQ0JVneWPH7O2AbtlJnP7AjvFJ6JjM6ZEBxo,23
13
+ huace_aigc_auth_client-1.1.32.dist-info/RECORD,,