huace-aigc-auth-client 1.1.20__py3-none-any.whl → 1.1.28__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.
- huace_aigc_auth_client/__init__.py +1 -1
- huace_aigc_auth_client/api_stats_collector.py +66 -12
- huace_aigc_auth_client/sdk.py +157 -56
- {huace_aigc_auth_client-1.1.20.dist-info → huace_aigc_auth_client-1.1.28.dist-info}/METADATA +1 -1
- huace_aigc_auth_client-1.1.28.dist-info/RECORD +12 -0
- huace_aigc_auth_client-1.1.20.dist-info/RECORD +0 -12
- {huace_aigc_auth_client-1.1.20.dist-info → huace_aigc_auth_client-1.1.28.dist-info}/WHEEL +0 -0
- {huace_aigc_auth_client-1.1.20.dist-info → huace_aigc_auth_client-1.1.28.dist-info}/licenses/LICENSE +0 -0
- {huace_aigc_auth_client-1.1.20.dist-info → huace_aigc_auth_client-1.1.28.dist-info}/top_level.txt +0 -0
|
@@ -16,9 +16,9 @@ class ApiStatsCollector:
|
|
|
16
16
|
def __init__(
|
|
17
17
|
self,
|
|
18
18
|
api_url: str,
|
|
19
|
+
app_id: str,
|
|
19
20
|
app_secret: str,
|
|
20
|
-
|
|
21
|
-
batch_size: int = 10,
|
|
21
|
+
batch_size: int = 50,
|
|
22
22
|
flush_interval: float = 5.0,
|
|
23
23
|
enabled: bool = True
|
|
24
24
|
):
|
|
@@ -27,15 +27,15 @@ class ApiStatsCollector:
|
|
|
27
27
|
|
|
28
28
|
Args:
|
|
29
29
|
api_url: 统计接口 URL(如:http://auth.example.com/api/sdk/stats/report/batch)
|
|
30
|
+
app_id: 应用 ID
|
|
30
31
|
app_secret: 应用密钥
|
|
31
|
-
token: 用户访问令牌
|
|
32
32
|
batch_size: 批量提交大小
|
|
33
33
|
flush_interval: 刷新间隔(秒)
|
|
34
34
|
enabled: 是否启用
|
|
35
35
|
"""
|
|
36
36
|
self.api_url = api_url.rstrip('/')
|
|
37
|
+
self.app_id = app_id
|
|
37
38
|
self.app_secret = app_secret
|
|
38
|
-
self.token = token
|
|
39
39
|
self.batch_size = batch_size
|
|
40
40
|
self.flush_interval = flush_interval
|
|
41
41
|
self.enabled = enabled
|
|
@@ -66,6 +66,7 @@ class ApiStatsCollector:
|
|
|
66
66
|
api_method: str,
|
|
67
67
|
status_code: int,
|
|
68
68
|
response_time: float,
|
|
69
|
+
token: str,
|
|
69
70
|
error_message: Optional[str] = None,
|
|
70
71
|
request_params: Optional[Dict[str, Any]] = None
|
|
71
72
|
):
|
|
@@ -77,21 +78,26 @@ class ApiStatsCollector:
|
|
|
77
78
|
api_method: 请求方法
|
|
78
79
|
status_code: 状态码
|
|
79
80
|
response_time: 响应时间(秒)
|
|
81
|
+
token: 用户访问令牌
|
|
80
82
|
error_message: 错误信息
|
|
81
83
|
request_params: 请求参数(包含 headers, query_params, view_params, request_body, form_params)
|
|
82
84
|
"""
|
|
83
85
|
if not self.enabled:
|
|
84
86
|
return
|
|
85
87
|
|
|
88
|
+
# 过滤重定向请求(3xx 状态码),这些通常是框架自动处理的,不应统计
|
|
89
|
+
if 300 <= status_code < 400:
|
|
90
|
+
return
|
|
91
|
+
|
|
86
92
|
try:
|
|
87
93
|
stat_data = {
|
|
88
94
|
'api_path': api_path,
|
|
89
95
|
'api_method': api_method,
|
|
90
96
|
'status_code': status_code,
|
|
91
97
|
'response_time': response_time,
|
|
98
|
+
'token': token,
|
|
92
99
|
'error_message': error_message,
|
|
93
|
-
'request_params': request_params
|
|
94
|
-
'timestamp': datetime.utcnow().isoformat()
|
|
100
|
+
'request_params': request_params
|
|
95
101
|
}
|
|
96
102
|
self.queue.put_nowait(stat_data)
|
|
97
103
|
except queue.Full:
|
|
@@ -132,18 +138,50 @@ class ApiStatsCollector:
|
|
|
132
138
|
self._flush_buffer(buffer)
|
|
133
139
|
|
|
134
140
|
def _flush_buffer(self, buffer: List[Dict[str, Any]]):
|
|
135
|
-
"""
|
|
141
|
+
"""刷新缓冲区:按token分组批量提交统计数据"""
|
|
136
142
|
if not buffer:
|
|
137
143
|
return
|
|
138
144
|
|
|
145
|
+
try:
|
|
146
|
+
# 按token分组
|
|
147
|
+
token_groups: Dict[str, List[Dict[str, Any]]] = {}
|
|
148
|
+
for stat in buffer:
|
|
149
|
+
token = stat.get('token')
|
|
150
|
+
if not token:
|
|
151
|
+
continue
|
|
152
|
+
|
|
153
|
+
if token not in token_groups:
|
|
154
|
+
token_groups[token] = []
|
|
155
|
+
|
|
156
|
+
# 移除token字段后添加到分组
|
|
157
|
+
stat_copy = stat.copy()
|
|
158
|
+
stat_copy.pop('token', None)
|
|
159
|
+
token_groups[token].append(stat_copy)
|
|
160
|
+
|
|
161
|
+
# 对每个token分组分别提交
|
|
162
|
+
for token, stats in token_groups.items():
|
|
163
|
+
self._submit_stats(token, stats)
|
|
164
|
+
|
|
165
|
+
except Exception:
|
|
166
|
+
pass # 静默失败,不影响主流程
|
|
167
|
+
|
|
168
|
+
def _submit_stats(self, token: str, stats: List[Dict[str, Any]]):
|
|
169
|
+
"""
|
|
170
|
+
提交统计数据到服务端
|
|
171
|
+
|
|
172
|
+
Args:
|
|
173
|
+
token: 用户访问令牌
|
|
174
|
+
stats: 统计数据列表(已移除token字段)
|
|
175
|
+
"""
|
|
139
176
|
try:
|
|
140
177
|
headers = {
|
|
178
|
+
'X-App-Id': self.app_id,
|
|
141
179
|
'X-App-Secret': self.app_secret,
|
|
142
|
-
'Authorization': f'Bearer {
|
|
180
|
+
'Authorization': f'Bearer {token}',
|
|
143
181
|
'Content-Type': 'application/json'
|
|
144
182
|
}
|
|
145
183
|
|
|
146
|
-
payload = {'stats':
|
|
184
|
+
payload = {'stats': stats}
|
|
147
185
|
|
|
148
186
|
response = requests.post(
|
|
149
187
|
f'{self.api_url}/stats/report/batch',
|
|
@@ -167,8 +205,8 @@ _global_collector: Optional[ApiStatsCollector] = None
|
|
|
167
205
|
|
|
168
206
|
def init_api_stats_collector(
|
|
169
207
|
api_url: str,
|
|
208
|
+
app_id: str,
|
|
170
209
|
app_secret: str,
|
|
171
|
-
token: str,
|
|
172
210
|
batch_size: int = 10,
|
|
173
211
|
flush_interval: float = 5.0,
|
|
174
212
|
enabled: bool = True
|
|
@@ -178,8 +216,8 @@ def init_api_stats_collector(
|
|
|
178
216
|
|
|
179
217
|
Args:
|
|
180
218
|
api_url: 统计接口 URL
|
|
219
|
+
app_id: 应用 ID
|
|
181
220
|
app_secret: 应用密钥
|
|
182
|
-
token: 用户访问令牌
|
|
183
221
|
batch_size: 批量提交大小
|
|
184
222
|
flush_interval: 刷新间隔(秒)
|
|
185
223
|
enabled: 是否启用
|
|
@@ -190,8 +228,8 @@ def init_api_stats_collector(
|
|
|
190
228
|
global _global_collector
|
|
191
229
|
_global_collector = ApiStatsCollector(
|
|
192
230
|
api_url=api_url,
|
|
231
|
+
app_id=app_id,
|
|
193
232
|
app_secret=app_secret,
|
|
194
|
-
token=token,
|
|
195
233
|
batch_size=batch_size,
|
|
196
234
|
flush_interval=flush_interval,
|
|
197
235
|
enabled=enabled
|
|
@@ -217,6 +255,7 @@ def collect_api_stat(
|
|
|
217
255
|
api_method: str,
|
|
218
256
|
status_code: int,
|
|
219
257
|
response_time: float,
|
|
258
|
+
token: str,
|
|
220
259
|
error_message: Optional[str] = None,
|
|
221
260
|
request_params: Optional[Dict[str, Any]] = None
|
|
222
261
|
):
|
|
@@ -224,7 +263,21 @@ def collect_api_stat(
|
|
|
224
263
|
快捷方法:收集接口统计数据
|
|
225
264
|
|
|
226
265
|
使用全局收集器实例
|
|
266
|
+
注意:会自动过滤 3xx 重定向状态码的请求
|
|
267
|
+
|
|
268
|
+
Args:
|
|
269
|
+
api_path: 接口路径
|
|
270
|
+
api_method: 请求方法
|
|
271
|
+
status_code: 状态码
|
|
272
|
+
response_time: 响应时间(秒)
|
|
273
|
+
token: 用户访问令牌
|
|
274
|
+
error_message: 错误信息
|
|
275
|
+
request_params: 请求参数
|
|
227
276
|
"""
|
|
277
|
+
# 过滤重定向请求(3xx 状态码),这些通常是框架自动处理的,不应统计
|
|
278
|
+
if 300 <= status_code < 400:
|
|
279
|
+
return
|
|
280
|
+
|
|
228
281
|
collector = get_api_stats_collector()
|
|
229
282
|
if collector:
|
|
230
283
|
collector.collect(
|
|
@@ -232,6 +285,7 @@ def collect_api_stat(
|
|
|
232
285
|
api_method=api_method,
|
|
233
286
|
status_code=status_code,
|
|
234
287
|
response_time=response_time,
|
|
288
|
+
token=token,
|
|
235
289
|
error_message=error_message,
|
|
236
290
|
request_params=request_params
|
|
237
291
|
)
|
huace_aigc_auth_client/sdk.py
CHANGED
|
@@ -570,23 +570,28 @@ class AuthMiddleware:
|
|
|
570
570
|
self.exclude_paths = exclude_paths or []
|
|
571
571
|
self.exclude_prefixes = exclude_prefixes or []
|
|
572
572
|
self.enable_stats = enable_stats
|
|
573
|
-
self.stats_collector = None
|
|
574
573
|
|
|
575
|
-
#
|
|
574
|
+
# 如果启用统计,初始化全局统计收集器
|
|
576
575
|
if self.enable_stats:
|
|
577
576
|
self.stats_api_url = stats_api_url or f"{self.client.base_url}/sdk"
|
|
577
|
+
self._init_global_stats_collector()
|
|
578
578
|
|
|
579
|
-
def
|
|
580
|
-
"""
|
|
581
|
-
if not self.enable_stats
|
|
579
|
+
def _init_global_stats_collector(self):
|
|
580
|
+
"""初始化全局统计收集器(只初始化一次)"""
|
|
581
|
+
if not self.enable_stats:
|
|
582
582
|
return
|
|
583
583
|
|
|
584
584
|
try:
|
|
585
|
-
from .api_stats_collector import init_api_stats_collector
|
|
586
|
-
|
|
585
|
+
from .api_stats_collector import init_api_stats_collector, get_api_stats_collector
|
|
586
|
+
|
|
587
|
+
# 检查是否已经初始化
|
|
588
|
+
if get_api_stats_collector() is not None:
|
|
589
|
+
return
|
|
590
|
+
|
|
591
|
+
init_api_stats_collector(
|
|
587
592
|
api_url=self.stats_api_url,
|
|
593
|
+
app_id=self.client.app_id,
|
|
588
594
|
app_secret=self.client.app_secret,
|
|
589
|
-
token=token,
|
|
590
595
|
batch_size=10,
|
|
591
596
|
flush_interval=5.0,
|
|
592
597
|
enabled=True
|
|
@@ -614,21 +619,31 @@ class AuthMiddleware:
|
|
|
614
619
|
"form_params": None
|
|
615
620
|
}
|
|
616
621
|
|
|
617
|
-
#
|
|
622
|
+
# 获取 content-type
|
|
623
|
+
content_type = request.headers.get('Content-Type', '').lower()
|
|
624
|
+
|
|
625
|
+
# 获取请求体(使用白名单方式,只处理已知安全的内容类型)
|
|
618
626
|
if request.is_json:
|
|
619
627
|
try:
|
|
620
628
|
params["request_body"] = request.get_json(silent=True)
|
|
621
629
|
except Exception:
|
|
622
630
|
pass
|
|
623
|
-
elif
|
|
631
|
+
elif 'application/x-www-form-urlencoded' in content_type:
|
|
632
|
+
# 表单数据
|
|
633
|
+
if request.form:
|
|
634
|
+
params["form_params"] = request.form.to_dict(flat=False)
|
|
635
|
+
elif 'multipart/form-data' in content_type:
|
|
636
|
+
# 文件上传请求,不读取 request.data,避免损坏文件流
|
|
637
|
+
# 只收集表单字段(非文件字段)
|
|
638
|
+
if request.form:
|
|
639
|
+
params["form_params"] = request.form.to_dict(flat=False)
|
|
640
|
+
elif content_type.startswith('text/') and request.data and len(request.data) < 10240:
|
|
641
|
+
# 只读取文本类型的请求体,且限制大小避免内存问题
|
|
624
642
|
try:
|
|
625
643
|
params["request_body"] = request.data.decode('utf-8')
|
|
626
644
|
except Exception:
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
# 获取表单数据
|
|
630
|
-
if request.form:
|
|
631
|
-
params["form_params"] = request.form.to_dict(flat=False)
|
|
645
|
+
pass
|
|
646
|
+
# 其他类型(如 application/octet-stream 等二进制流)直接跳过,不读取
|
|
632
647
|
|
|
633
648
|
return params
|
|
634
649
|
except Exception as e:
|
|
@@ -655,28 +670,32 @@ class AuthMiddleware:
|
|
|
655
670
|
"form_params": None
|
|
656
671
|
}
|
|
657
672
|
|
|
658
|
-
#
|
|
659
|
-
content_type = request.headers.get("content-type", "")
|
|
673
|
+
# 获取请求体(使用白名单方式,只处理已知安全的内容类型)
|
|
674
|
+
content_type = request.headers.get("content-type", "").lower()
|
|
675
|
+
# 读取请求体(需要特殊处理以避免消耗流)
|
|
676
|
+
body = b""
|
|
677
|
+
if request.method in ["POST", "PUT", "PATCH"]:
|
|
678
|
+
try:
|
|
679
|
+
body = await request.body()
|
|
680
|
+
except:
|
|
681
|
+
pass
|
|
682
|
+
params["request_body"] = body.decode('utf-8', errors='ignore')
|
|
660
683
|
|
|
661
684
|
if "application/json" in content_type:
|
|
662
685
|
try:
|
|
663
686
|
params["request_body"] = await request.json()
|
|
664
687
|
except Exception:
|
|
665
688
|
pass
|
|
666
|
-
elif "application/x-www-form-urlencoded" in content_type
|
|
689
|
+
elif "application/x-www-form-urlencoded" in content_type:
|
|
667
690
|
try:
|
|
668
691
|
form = await request.form()
|
|
669
692
|
params["form_params"] = {k: v for k, v in form.items()}
|
|
670
693
|
except Exception:
|
|
671
694
|
pass
|
|
672
|
-
|
|
673
|
-
#
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
if body:
|
|
677
|
-
params["request_body"] = body.decode('utf-8')
|
|
678
|
-
except Exception:
|
|
679
|
-
pass
|
|
695
|
+
elif "multipart/form-data" in content_type:
|
|
696
|
+
# 文件上传请求,不读取 body,避免损坏文件流
|
|
697
|
+
params["form_params"] = {"skipped_multipart": True}
|
|
698
|
+
# 其他类型(如 application/octet-stream 等二进制流)直接跳过,不读取
|
|
680
699
|
|
|
681
700
|
return params
|
|
682
701
|
except Exception as e:
|
|
@@ -689,22 +708,27 @@ class AuthMiddleware:
|
|
|
689
708
|
api_method: str,
|
|
690
709
|
status_code: int,
|
|
691
710
|
response_time: float,
|
|
711
|
+
token: str,
|
|
692
712
|
error_message: Optional[str] = None,
|
|
693
713
|
request_params: Optional[Dict[str, Any]] = None
|
|
694
714
|
):
|
|
695
715
|
"""收集接口统计"""
|
|
696
|
-
if not self.enable_stats
|
|
716
|
+
if not self.enable_stats:
|
|
697
717
|
return
|
|
698
718
|
|
|
699
719
|
try:
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
|
|
707
|
-
|
|
720
|
+
from .api_stats_collector import get_api_stats_collector
|
|
721
|
+
collector = get_api_stats_collector()
|
|
722
|
+
if collector:
|
|
723
|
+
collector.collect(
|
|
724
|
+
api_path=api_path,
|
|
725
|
+
api_method=api_method,
|
|
726
|
+
status_code=status_code,
|
|
727
|
+
response_time=response_time,
|
|
728
|
+
token=token,
|
|
729
|
+
error_message=error_message,
|
|
730
|
+
request_params=request_params
|
|
731
|
+
)
|
|
708
732
|
except Exception:
|
|
709
733
|
pass # 静默失败
|
|
710
734
|
|
|
@@ -725,9 +749,83 @@ class AuthMiddleware:
|
|
|
725
749
|
return None
|
|
726
750
|
return authorization[7:]
|
|
727
751
|
|
|
752
|
+
def get_fastapi_middleware_class(self, user_info_callback: Callable = None):
|
|
753
|
+
"""
|
|
754
|
+
获取 FastAPI 中间件类(推荐使用,避免请求体读取问题)
|
|
755
|
+
|
|
756
|
+
使用方法:
|
|
757
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
758
|
+
app.add_middleware(auth_middleware.get_fastapi_middleware_class())
|
|
759
|
+
|
|
760
|
+
Returns:
|
|
761
|
+
继承于 BaseHTTPMiddleware 的中间件类
|
|
762
|
+
"""
|
|
763
|
+
from fastapi.responses import JSONResponse
|
|
764
|
+
from starlette.middleware.base import BaseHTTPMiddleware
|
|
765
|
+
|
|
766
|
+
auth_middleware_instance = self
|
|
767
|
+
|
|
768
|
+
class AuthHTTPMiddleware(BaseHTTPMiddleware):
|
|
769
|
+
async def dispatch(self, request, call_next):
|
|
770
|
+
path = request.url.path
|
|
771
|
+
start_time = time.time()
|
|
772
|
+
|
|
773
|
+
# 收集请求参数
|
|
774
|
+
request_params = await auth_middleware_instance._collect_fastapi_request_params(request) if auth_middleware_instance.enable_stats else None
|
|
775
|
+
|
|
776
|
+
# 检查是否跳过
|
|
777
|
+
if auth_middleware_instance._should_skip(path):
|
|
778
|
+
return await call_next(request)
|
|
779
|
+
|
|
780
|
+
# 获取 Authorization header
|
|
781
|
+
authorization = request.headers.get("Authorization")
|
|
782
|
+
token = auth_middleware_instance._extract_token(authorization)
|
|
783
|
+
|
|
784
|
+
if not token:
|
|
785
|
+
logger.warning("AuthMiddleware未提供认证信息")
|
|
786
|
+
response_time = time.time() - start_time
|
|
787
|
+
auth_middleware_instance._collect_stats(path, request.method, 401, response_time, "", "未提供认证信息", request_params)
|
|
788
|
+
return JSONResponse(
|
|
789
|
+
status_code=401,
|
|
790
|
+
content={"code": 401, "message": "未提供认证信息", "data": None}
|
|
791
|
+
)
|
|
792
|
+
|
|
793
|
+
# 验证 token
|
|
794
|
+
try:
|
|
795
|
+
user_info = auth_middleware_instance.client.get_user_info(token)
|
|
796
|
+
# 将用户信息存储到 request.state
|
|
797
|
+
request.state.user_info = user_info
|
|
798
|
+
# 设置上下文
|
|
799
|
+
set_current_user(dataclasses.asdict(user_info))
|
|
800
|
+
if user_info_callback:
|
|
801
|
+
await user_info_callback(request, user_info)
|
|
802
|
+
except AigcAuthError as e:
|
|
803
|
+
logger.error(f"AuthMiddleware认证失败: {e.message}")
|
|
804
|
+
response_time = time.time() - start_time
|
|
805
|
+
auth_middleware_instance._collect_stats(path, request.method, 401, response_time, token, e.message, request_params)
|
|
806
|
+
return JSONResponse(
|
|
807
|
+
status_code=401,
|
|
808
|
+
content={"code": e.code, "message": e.message, "data": None}
|
|
809
|
+
)
|
|
810
|
+
|
|
811
|
+
# 处理请求
|
|
812
|
+
try:
|
|
813
|
+
response = await call_next(request)
|
|
814
|
+
response_time = time.time() - start_time
|
|
815
|
+
auth_middleware_instance._collect_stats(path, request.method, response.status_code, response_time, token, None, request_params)
|
|
816
|
+
return response
|
|
817
|
+
except Exception as e:
|
|
818
|
+
response_time = time.time() - start_time
|
|
819
|
+
auth_middleware_instance._collect_stats(path, request.method, 500, response_time, token, str(e), request_params)
|
|
820
|
+
raise
|
|
821
|
+
finally:
|
|
822
|
+
clear_current_user()
|
|
823
|
+
|
|
824
|
+
return AuthHTTPMiddleware
|
|
825
|
+
|
|
728
826
|
async def fastapi_middleware(self, request, call_next, user_info_callback: Callable = None):
|
|
729
827
|
"""
|
|
730
|
-
FastAPI
|
|
828
|
+
FastAPI 中间件(旧方法,推荐使用 get_fastapi_middleware_class)
|
|
731
829
|
|
|
732
830
|
使用方法:
|
|
733
831
|
@app.middleware("http")
|
|
@@ -735,12 +833,14 @@ class AuthMiddleware:
|
|
|
735
833
|
return await auth_middleware.fastapi_middleware(request, call_next)
|
|
736
834
|
"""
|
|
737
835
|
from fastapi.responses import JSONResponse
|
|
836
|
+
|
|
837
|
+
# 处理代理头部,确保重定向(如果有)使用正确的协议
|
|
838
|
+
forwarded_proto = request.headers.get("x-forwarded-proto")
|
|
839
|
+
if forwarded_proto:
|
|
840
|
+
request.scope["scheme"] = forwarded_proto
|
|
738
841
|
|
|
739
842
|
path = request.url.path
|
|
740
843
|
start_time = time.time()
|
|
741
|
-
|
|
742
|
-
# 收集请求参数
|
|
743
|
-
request_params = await self._collect_fastapi_request_params(request) if self.enable_stats else None
|
|
744
844
|
|
|
745
845
|
# 检查是否跳过
|
|
746
846
|
if self._should_skip(path):
|
|
@@ -753,7 +853,9 @@ class AuthMiddleware:
|
|
|
753
853
|
if not token:
|
|
754
854
|
logger.warning("AuthMiddleware未提供认证信息")
|
|
755
855
|
response_time = time.time() - start_time
|
|
756
|
-
|
|
856
|
+
# 收集请求参数
|
|
857
|
+
request_params = await self._collect_fastapi_request_params(request) if self.enable_stats else None
|
|
858
|
+
self._collect_stats(path, request.method, 401, response_time, "", "未提供认证信息", request_params)
|
|
757
859
|
return JSONResponse(
|
|
758
860
|
status_code=401,
|
|
759
861
|
content={"code": 401, "message": "未提供认证信息", "data": None}
|
|
@@ -762,24 +864,18 @@ class AuthMiddleware:
|
|
|
762
864
|
# 验证 token
|
|
763
865
|
try:
|
|
764
866
|
user_info = self.client.get_user_info(token)
|
|
765
|
-
# 初始化统计收集器(第一次有token时)
|
|
766
|
-
if self.enable_stats and self.stats_collector is None:
|
|
767
|
-
self._init_stats_collector(token)
|
|
768
867
|
# 将用户信息存储到 request.state
|
|
769
868
|
request.state.user_info = user_info
|
|
770
869
|
# 设置上下文
|
|
771
870
|
set_current_user(dataclasses.asdict(user_info))
|
|
772
|
-
|
|
773
|
-
# 处理代理头部,确保重定向(如果有)使用正确的协议
|
|
774
|
-
forwarded_proto = request.headers.get("x-forwarded-proto")
|
|
775
|
-
if forwarded_proto:
|
|
776
|
-
request.scope["scheme"] = forwarded_proto
|
|
777
871
|
if user_info_callback:
|
|
778
872
|
await user_info_callback(request, user_info)
|
|
779
873
|
except AigcAuthError as e:
|
|
780
874
|
logger.error(f"AuthMiddleware认证失败: {e.message}")
|
|
781
875
|
response_time = time.time() - start_time
|
|
782
|
-
|
|
876
|
+
# 收集请求参数
|
|
877
|
+
request_params = await self._collect_fastapi_request_params(request) if self.enable_stats else None
|
|
878
|
+
self._collect_stats(path, request.method, 401, response_time, token, e.message, request_params)
|
|
783
879
|
return JSONResponse(
|
|
784
880
|
status_code=401,
|
|
785
881
|
content={"code": e.code, "message": e.message, "data": None}
|
|
@@ -789,11 +885,15 @@ class AuthMiddleware:
|
|
|
789
885
|
try:
|
|
790
886
|
response = await call_next(request)
|
|
791
887
|
response_time = time.time() - start_time
|
|
792
|
-
|
|
888
|
+
# 收集请求参数
|
|
889
|
+
request_params = await self._collect_fastapi_request_params(request) if self.enable_stats else None
|
|
890
|
+
self._collect_stats(path, request.method, response.status_code, response_time, token, None, request_params)
|
|
793
891
|
return response
|
|
794
892
|
except Exception as e:
|
|
893
|
+
# 收集请求参数
|
|
894
|
+
request_params = await self._collect_fastapi_request_params(request) if self.enable_stats else None
|
|
795
895
|
response_time = time.time() - start_time
|
|
796
|
-
self._collect_stats(path, request.method, 500, response_time, str(e), request_params)
|
|
896
|
+
self._collect_stats(path, request.method, 500, response_time, token, str(e), request_params)
|
|
797
897
|
raise
|
|
798
898
|
finally:
|
|
799
899
|
clear_current_user()
|
|
@@ -827,7 +927,7 @@ class AuthMiddleware:
|
|
|
827
927
|
if not token:
|
|
828
928
|
logger.warning("AuthMiddleware未提供认证信息")
|
|
829
929
|
response_time = time.time() - g.start_time
|
|
830
|
-
self._collect_stats(path, request.method, 401, response_time, "未提供认证信息", g.request_params)
|
|
930
|
+
self._collect_stats(path, request.method, 401, response_time, "", "未提供认证信息", g.request_params)
|
|
831
931
|
return jsonify({
|
|
832
932
|
"code": 401,
|
|
833
933
|
"message": "未提供认证信息",
|
|
@@ -837,9 +937,6 @@ class AuthMiddleware:
|
|
|
837
937
|
# 验证 token
|
|
838
938
|
try:
|
|
839
939
|
user_info = self.client.get_user_info(token)
|
|
840
|
-
# 初始化统计收集器(第一次有token时)
|
|
841
|
-
if self.enable_stats and self.stats_collector is None:
|
|
842
|
-
self._init_stats_collector(token)
|
|
843
940
|
# 将用户信息存储到 flask.g
|
|
844
941
|
g.user_info = user_info
|
|
845
942
|
# 设置上下文
|
|
@@ -849,7 +946,7 @@ class AuthMiddleware:
|
|
|
849
946
|
except AigcAuthError as e:
|
|
850
947
|
logger.error(f"AuthMiddleware认证失败: {e.message}")
|
|
851
948
|
response_time = time.time() - g.start_time
|
|
852
|
-
self._collect_stats(path, request.method, 401, response_time, e.message, g.request_params)
|
|
949
|
+
self._collect_stats(path, request.method, 401, response_time, token, e.message, g.request_params)
|
|
853
950
|
return jsonify({
|
|
854
951
|
"code": e.code,
|
|
855
952
|
"message": e.message,
|
|
@@ -875,11 +972,15 @@ class AuthMiddleware:
|
|
|
875
972
|
if hasattr(g, 'start_time'):
|
|
876
973
|
response_time = time.time() - g.start_time
|
|
877
974
|
request_params = getattr(g, 'request_params', None)
|
|
975
|
+
# 从 request 的 Authorization header 获取 token
|
|
976
|
+
authorization = request.headers.get("Authorization")
|
|
977
|
+
token = self._extract_token(authorization) or ""
|
|
878
978
|
self._collect_stats(
|
|
879
979
|
request.path,
|
|
880
980
|
request.method,
|
|
881
981
|
response.status_code,
|
|
882
982
|
response_time,
|
|
983
|
+
token,
|
|
883
984
|
None,
|
|
884
985
|
request_params
|
|
885
986
|
)
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
huace_aigc_auth_client/__init__.py,sha256=nCpT58WU83NkEpdyMiq35t4Zd261cdp45N_07NRoisY,4630
|
|
2
|
+
huace_aigc_auth_client/api_stats_collector.py,sha256=UCUu2CHWsJyiAM58-XLQtfxWK0fjZ8TTdw90gv_Gx04,10347
|
|
3
|
+
huace_aigc_auth_client/legacy_adapter.py,sha256=TVCBAKejE2z2HQFsEwDW8LMiaIkXNfz3Mxv6_E-UJFY,24102
|
|
4
|
+
huace_aigc_auth_client/sdk.py,sha256=49UrQnS96a_m-FM9KVSqmE8x4J-R4qpYsE4KgzasvFE,36742
|
|
5
|
+
huace_aigc_auth_client/user_context.py,sha256=KzevYLsLv1hv8rlvRw83FT-HugeoBJSJ1Pi56iLWyTE,5592
|
|
6
|
+
huace_aigc_auth_client/webhook.py,sha256=XQZYEbMoqIdqZWCGSTcedeDKJpDbUVSq5g08g-6Qucg,4124
|
|
7
|
+
huace_aigc_auth_client/webhook_flask.py,sha256=Iosu4dBtRhQZM_ytn-bn82MpVsyOiV28FBnt7Tfh31U,7225
|
|
8
|
+
huace_aigc_auth_client-1.1.28.dist-info/licenses/LICENSE,sha256=z7dgC7KljhBLNvKjN15391nMj3aLt0gbud8-Yf1F8EQ,1063
|
|
9
|
+
huace_aigc_auth_client-1.1.28.dist-info/METADATA,sha256=9TkNkzidAbMP7nb2drl1FfSOAumh6ngs7ueiik40mnE,23629
|
|
10
|
+
huace_aigc_auth_client-1.1.28.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
+
huace_aigc_auth_client-1.1.28.dist-info/top_level.txt,sha256=kbv0nQ6PQ0JVneWPH7O2AbtlJnP7AjvFJ6JjM6ZEBxo,23
|
|
12
|
+
huace_aigc_auth_client-1.1.28.dist-info/RECORD,,
|
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
huace_aigc_auth_client/__init__.py,sha256=e-Y0M75DKW4t-hhipxgH_UDhoVSdH1uKFmJKyacyRJo,4630
|
|
2
|
-
huace_aigc_auth_client/api_stats_collector.py,sha256=VL_z-3WUWhEkAKDhGnKX0H-nNUn3x2IO_1FASsFA-Ss,8511
|
|
3
|
-
huace_aigc_auth_client/legacy_adapter.py,sha256=TVCBAKejE2z2HQFsEwDW8LMiaIkXNfz3Mxv6_E-UJFY,24102
|
|
4
|
-
huace_aigc_auth_client/sdk.py,sha256=0E0EmfLVxpOI5rOiVdAGcFzajdNZnDgjwrmOX7aYzGc,31303
|
|
5
|
-
huace_aigc_auth_client/user_context.py,sha256=KzevYLsLv1hv8rlvRw83FT-HugeoBJSJ1Pi56iLWyTE,5592
|
|
6
|
-
huace_aigc_auth_client/webhook.py,sha256=XQZYEbMoqIdqZWCGSTcedeDKJpDbUVSq5g08g-6Qucg,4124
|
|
7
|
-
huace_aigc_auth_client/webhook_flask.py,sha256=Iosu4dBtRhQZM_ytn-bn82MpVsyOiV28FBnt7Tfh31U,7225
|
|
8
|
-
huace_aigc_auth_client-1.1.20.dist-info/licenses/LICENSE,sha256=z7dgC7KljhBLNvKjN15391nMj3aLt0gbud8-Yf1F8EQ,1063
|
|
9
|
-
huace_aigc_auth_client-1.1.20.dist-info/METADATA,sha256=NkVUBXJLpANzcTh_VpBm2Lm1UquzxgjCK_2l-Xj6Kfo,23629
|
|
10
|
-
huace_aigc_auth_client-1.1.20.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
|
|
11
|
-
huace_aigc_auth_client-1.1.20.dist-info/top_level.txt,sha256=kbv0nQ6PQ0JVneWPH7O2AbtlJnP7AjvFJ6JjM6ZEBxo,23
|
|
12
|
-
huace_aigc_auth_client-1.1.20.dist-info/RECORD,,
|
|
File without changes
|
{huace_aigc_auth_client-1.1.20.dist-info → huace_aigc_auth_client-1.1.28.dist-info}/licenses/LICENSE
RENAMED
|
File without changes
|
{huace_aigc_auth_client-1.1.20.dist-info → huace_aigc_auth_client-1.1.28.dist-info}/top_level.txt
RENAMED
|
File without changes
|