skyplatform-iam 1.2.0__py3-none-any.whl → 1.2.1__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.
@@ -17,7 +17,7 @@ from .exceptions import (
17
17
  NetworkError
18
18
  )
19
19
 
20
- __version__ = "1.2.0"
20
+ __version__ = "1.2.1"
21
21
  __author__ = "x9"
22
22
  __description__ = "SkyPlatform IAM认证SDK,提供FastAPI中间件和IAM服务连接功能"
23
23
 
@@ -100,6 +100,9 @@ def init_skyplatform_iam(app, config: AuthConfig = None):
100
100
  # 验证配置的完整性
101
101
  config.validate_config()
102
102
 
103
+ # 配置SDK日志级别
104
+ _configure_sdk_logging(config.enable_sdk_logging)
105
+
103
106
  # 初始化全局认证服务
104
107
  setup_auth_middleware(config)
105
108
 
@@ -110,6 +113,36 @@ def init_skyplatform_iam(app, config: AuthConfig = None):
110
113
  return middleware
111
114
 
112
115
 
116
+ def _configure_sdk_logging(enable_sdk_logging: bool):
117
+ """
118
+ 配置SDK日志级别
119
+
120
+ Args:
121
+ enable_sdk_logging: 是否启用SDK日志
122
+ """
123
+ import logging
124
+
125
+ # SDK相关的logger名称列表
126
+ sdk_loggers = [
127
+ 'skyplatform_iam.config',
128
+ 'skyplatform_iam.middleware',
129
+ 'skyplatform_iam.connect_agenterra_iam',
130
+ 'skyplatform_iam.exceptions'
131
+ ]
132
+
133
+ if enable_sdk_logging:
134
+ # 启用SDK日志,设置为INFO级别
135
+ log_level = logging.INFO
136
+ else:
137
+ # 禁用SDK日志,设置为WARNING级别,只显示警告和错误
138
+ log_level = logging.WARNING
139
+
140
+ # 配置所有SDK相关的logger
141
+ for logger_name in sdk_loggers:
142
+ logger = logging.getLogger(logger_name)
143
+ logger.setLevel(log_level)
144
+
145
+
113
146
  def get_iam_client(config: AuthConfig = None) -> ConnectAgenterraIam:
114
147
  """
115
148
  获取全局IAM客户端实例
skyplatform_iam/config.py CHANGED
@@ -32,6 +32,9 @@ class AuthConfig(BaseModel):
32
32
 
33
33
  # 错误处理配置
34
34
  enable_debug: bool = False
35
+
36
+ # SDK日志控制配置
37
+ enable_sdk_logging: bool = True
35
38
 
36
39
  # 白名单路径配置(实例变量)
37
40
  whitelist_paths: List[str] = Field(default_factory=list)
@@ -49,6 +52,7 @@ class AuthConfig(BaseModel):
49
52
  server_name=os.environ.get('AGENTERRA_SERVER_NAME', ''),
50
53
  access_key=os.environ.get('AGENTERRA_ACCESS_KEY', ''),
51
54
  enable_debug=os.environ.get('AGENTERRA_ENABLE_DEBUG', 'false').lower() == 'true',
55
+ enable_sdk_logging=os.environ.get('AGENTERRA_ENABLE_SDK_LOGGING', 'true').lower() == 'true',
52
56
  machine_token=os.environ.get('MACHINE_TOKEN', ''),
53
57
  whitelist_paths=[] # 初始化空的白名单路径列表
54
58
  )
@@ -2,11 +2,16 @@ import requests
2
2
  import logging
3
3
  import traceback
4
4
  import copy
5
+ import urllib3
5
6
  from enum import Enum
6
7
  from fastapi import HTTPException, status
7
8
 
8
9
  from .config import decode_jwt_token
9
10
 
11
+ # 禁用 urllib3 的 InsecureRequestWarning 警告
12
+ # 这样可以避免在使用自定义 HTTPS 地址(可能没有有效证书)时出现警告信息
13
+ urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
14
+
10
15
 
11
16
  class CredentialTypeEnum(str, Enum):
12
17
  """凭证类型枚举,与后端API保持一致"""
@@ -42,6 +47,21 @@ class ConnectAgenterraIam(object):
42
47
  if self._initialized:
43
48
  return
44
49
 
50
+ # 必须传入config参数,不再支持从环境变量读取
51
+ if config is None:
52
+ raise ValueError("必须传入AuthConfig配置对象,不再支持从环境变量读取配置")
53
+
54
+ # 保存配置对象,用于日志控制
55
+ self.config = config
56
+
57
+ # 根据配置设置日志级别
58
+ if hasattr(config, 'enable_sdk_logging') and not config.enable_sdk_logging:
59
+ # 禁用SDK日志时,设置为WARNING级别,只显示警告和错误
60
+ effective_log_level = logging.WARNING
61
+ else:
62
+ # 启用SDK日志时,使用传入的日志级别
63
+ effective_log_level = log_level
64
+
45
65
  # 配置日志记录器
46
66
  self.logger = logging.getLogger(logger_name)
47
67
  if not self.logger.handlers:
@@ -51,17 +71,15 @@ class ConnectAgenterraIam(object):
51
71
  )
52
72
  handler.setFormatter(formatter)
53
73
  self.logger.addHandler(handler)
54
- self.logger.setLevel(log_level)
55
-
56
- # 必须传入config参数,不再支持从环境变量读取
57
- if config is None:
58
- raise ValueError("必须传入AuthConfig配置对象,不再支持从环境变量读取配置")
74
+ self.logger.setLevel(effective_log_level)
59
75
 
60
76
  self.agenterra_iam_host = config.agenterra_iam_host
61
77
  self.server_name = config.server_name
62
78
  self.access_key = config.access_key
63
79
  self.machine_token = config.machine_token
64
- self.logger.info("使用传入的AuthConfig配置")
80
+
81
+ if hasattr(config, 'enable_sdk_logging') and config.enable_sdk_logging:
82
+ self.logger.info("使用传入的AuthConfig配置")
65
83
 
66
84
  # 验证必要的配置
67
85
  if not self.agenterra_iam_host:
@@ -71,8 +89,9 @@ class ConnectAgenterraIam(object):
71
89
  if not self.access_key:
72
90
  self.logger.warning("AGENTERRA_ACCESS_KEY 配置未设置")
73
91
 
74
- self.logger.info(
75
- f"初始化AgenterraIAM连接器 - Host: {self.agenterra_iam_host}, Server: {self._mask_sensitive(self.server_name)}")
92
+ if hasattr(config, 'enable_sdk_logging') and config.enable_sdk_logging:
93
+ self.logger.info(
94
+ f"初始化AgenterraIAM连接器 - Host: {self.agenterra_iam_host}, Server: {self._mask_sensitive(self.server_name)}")
76
95
 
77
96
  self.headers = {
78
97
  "Content-Type": "application/json",
@@ -178,23 +197,27 @@ class ConnectAgenterraIam(object):
178
197
 
179
198
  def _log_request(self, method_name, url, headers, body):
180
199
  """记录请求信息"""
181
- sanitized_headers = self._sanitize_log_data(headers)
182
- sanitized_body = self._sanitize_log_data(body)
200
+ # 只有在启用SDK日志时才输出详细的请求信息
201
+ if hasattr(self, 'config') and hasattr(self.config, 'enable_sdk_logging') and self.config.enable_sdk_logging:
202
+ sanitized_headers = self._sanitize_log_data(headers)
203
+ sanitized_body = self._sanitize_log_data(body)
183
204
 
184
- self.logger.info(f"[{method_name}] 发送请求 - URL: {url}")
185
- self.logger.info(f"[{method_name}] 请求头: {sanitized_headers}")
186
- self.logger.info(f"[{method_name}] 请求体: {sanitized_body}")
205
+ self.logger.info(f"[{method_name}] 发送请求 - URL: {url}")
206
+ self.logger.info(f"[{method_name}] 请求头: {sanitized_headers}")
207
+ self.logger.info(f"[{method_name}] 请求体: {sanitized_body}")
187
208
 
188
209
  def _log_response(self, method_name, response):
189
210
  """记录响应信息"""
190
- try:
191
- response_data = response.json() if response.content else {}
192
- sanitized_response = self._sanitize_log_data(response_data)
193
- self.logger.info(f"[{method_name}] 响应状态码: {response.status_code}")
194
- self.logger.info(f"[{method_name}] 响应内容: {sanitized_response}")
195
- except Exception as e:
196
- self.logger.info(f"[{method_name}] 响应状态码: {response.status_code}")
197
- self.logger.info(f"[{method_name}] 响应内容解析失败: {str(e)}")
211
+ # 只有在启用SDK日志时才输出详细的响应信息
212
+ if hasattr(self, 'config') and hasattr(self.config, 'enable_sdk_logging') and self.config.enable_sdk_logging:
213
+ try:
214
+ response_data = response.json() if response.content else {}
215
+ sanitized_response = self._sanitize_log_data(response_data)
216
+ self.logger.info(f"[{method_name}] 响应状态码: {response.status_code}")
217
+ self.logger.info(f"[{method_name}] 响应内容: {sanitized_response}")
218
+ except Exception as e:
219
+ self.logger.info(f"[{method_name}] 响应状态码: {response.status_code}")
220
+ self.logger.info(f"[{method_name}] 响应内容解析失败: {str(e)}")
198
221
 
199
222
  def register(self, cred_type=None, cred_value=None, password=None, nickname=None, avatar_url=None,
200
223
  username=None, phone=None):
@@ -76,7 +76,8 @@ class AuthMiddleware(BaseHTTPMiddleware):
76
76
 
77
77
  # 首先检查路径是否在本地白名单中
78
78
  if self.is_path_whitelisted(api_path):
79
- logger.info(f"路径 {api_path} 在本地白名单中,跳过认证直接允许访问")
79
+ if self.config.enable_sdk_logging:
80
+ logger.info(f"路径 {api_path} 在本地白名单中,跳过认证直接允许访问")
80
81
  # 设置白名单标识
81
82
  request.state.user = None
82
83
  request.state.authenticated = False
@@ -106,9 +107,14 @@ class AuthMiddleware(BaseHTTPMiddleware):
106
107
  request.state.is_whitelist = True
107
108
  else:
108
109
  if machine_token:
109
- payload = jwt.decode(machine_token, algorithms=["HS256"], options={"verify_signature": False})
110
- user_id = payload.get("sub", None)
111
- request.state.user_id = user_id
110
+ try:
111
+ payload = jwt.decode(machine_token, algorithms=["HS256"], options={"verify_signature": False})
112
+ user_id = payload.get("sub", None)
113
+ request.state.user_id = user_id
114
+ except Exception as jwt_error:
115
+ if self.config.enable_sdk_logging:
116
+ logger.error(f"JWT解码失败: {str(jwt_error)}")
117
+ # JWT解码失败时不设置user_id,但继续处理
112
118
 
113
119
  # 正常认证接口,设置用户信息
114
120
  request.state.user = user_info
@@ -138,9 +144,10 @@ class AuthMiddleware(BaseHTTPMiddleware):
138
144
  detail=e.detail
139
145
  )
140
146
  except Exception as e:
141
- logger.error(f"认证中间件处理异常: {str(e)}")
142
- if self.config.enable_debug:
143
- logger.exception("详细异常信息:")
147
+ if self.config.enable_sdk_logging:
148
+ logger.error(f"认证中间件处理异常: {str(e)}")
149
+ if self.config.enable_debug:
150
+ logger.exception("详细异常信息:")
144
151
 
145
152
  return self._create_error_response(
146
153
  status_code=500,
@@ -155,13 +162,11 @@ class AuthMiddleware(BaseHTTPMiddleware):
155
162
  # 从Authorization头提取
156
163
  auth_header = request.headers.get(self.config.token_header)
157
164
  if auth_header and auth_header.startswith(self.config.token_prefix):
158
- print("has auth_header: ", auth_header)
159
165
  return auth_header[len(self.config.token_prefix):].strip()
160
166
 
161
167
  # 从查询参数提取(备选方案)
162
168
  token = request.query_params.get("token")
163
169
  if token:
164
- print("has token: ", token)
165
170
  return token
166
171
 
167
172
  return None
@@ -173,7 +178,6 @@ class AuthMiddleware(BaseHTTPMiddleware):
173
178
  # 从Authorization头提取
174
179
  machine_token = request.headers.get("MACHINE-TOKEN")
175
180
  if machine_token:
176
- print("has MACHINE-TOKEN': ", machine_token)
177
181
  return machine_token
178
182
 
179
183
  return None
@@ -208,9 +212,10 @@ class AuthMiddleware(BaseHTTPMiddleware):
208
212
  # 重新抛出HTTP异常
209
213
  raise
210
214
  except Exception as e:
211
- logger.error(f"Token验证异常: {str(e)}")
212
- if self.config.enable_debug:
213
- logger.exception("详细异常信息:")
215
+ if self.config.enable_sdk_logging:
216
+ logger.error(f"Token验证异常: {str(e)}")
217
+ if self.config.enable_debug:
218
+ logger.exception("详细异常信息:")
214
219
  return None
215
220
 
216
221
  def _create_error_response(
@@ -265,7 +270,8 @@ class AuthService:
265
270
 
266
271
  # 首先检查路径是否在白名单中
267
272
  if self.is_path_whitelisted(api_path):
268
- logger.info(f"路径 {api_path} 在白名单中,跳过IAM鉴权")
273
+ if self.auth_config.enable_sdk_logging:
274
+ logger.info(f"路径 {api_path} 在白名单中,跳过IAM鉴权")
269
275
  return True
270
276
 
271
277
  credentials: HTTPAuthorizationCredentials = await self.security(request)
@@ -274,7 +280,6 @@ class AuthService:
274
280
  server_ak = request.headers.get("SERVER-AK", "")
275
281
  server_sk = request.headers.get("SERVER-SK", "")
276
282
  machine_token = request.headers.get("MACHINE-TOKEN", "")
277
- print("248 machine_token:", machine_token)
278
283
 
279
284
  token = ""
280
285
  if credentials is not None:
@@ -301,7 +306,8 @@ class AuthService:
301
306
  # 直接解析JWT token获取payload
302
307
  payload = self.decode_jwt_token(token)
303
308
  if not payload:
304
- logger.error("JWT token解析失败")
309
+ if self.auth_config.enable_sdk_logging:
310
+ logger.error("JWT token解析失败")
305
311
  return None
306
312
 
307
313
  # 从payload中提取用户信息
@@ -357,20 +363,23 @@ class AuthService:
357
363
  cred_types = [cred.get("type") for cred in all_credentials]
358
364
  cred_type_count = {cred_type: cred_types.count(cred_type) for cred_type in set(cred_types)}
359
365
 
360
- logger.info(
361
- f"用户认证成功: user_id={iam_user_id}, username={username}, 凭证数量={total_credentials}, 凭证类型分布={cred_type_count}")
362
- logger.debug(f"JWT payload: {payload}")
366
+ if self.auth_config.enable_sdk_logging:
367
+ logger.info(
368
+ f"用户认证成功: user_id={iam_user_id}, username={username}, 凭证数量={total_credentials}, 凭证类型分布={cred_type_count}")
369
+ logger.debug(f"JWT payload: {payload}")
363
370
 
364
371
  # 将用户信息添加到请求状态中
365
372
  request.state.user = user_info
366
373
  return user_info
367
374
 
368
375
  except HTTPException as e:
369
- logger.error(f"获取当前用户信息失败: {str(e)}")
376
+ if self.auth_config.enable_sdk_logging:
377
+ logger.error(f"获取当前用户信息失败: {str(e)}")
370
378
  # 重新抛出HTTP异常(403权限不足)
371
379
  return None
372
380
  except Exception as e:
373
- logger.error(f"获取当前用户信息失败: {str(e)}")
381
+ if self.auth_config.enable_sdk_logging:
382
+ logger.error(f"获取当前用户信息失败: {str(e)}")
374
383
  return None
375
384
 
376
385
  async def require_auth(self, request: Request) -> Dict:
@@ -402,13 +411,16 @@ class AuthService:
402
411
  try:
403
412
  # 不验证签名,只解析payload(因为token已经通过verify_token验证过)
404
413
  decoded_payload = jwt.decode(token, options={"verify_signature": False})
405
- logger.debug(f"JWT token解析成功: {decoded_payload}")
414
+ if self.auth_config.enable_sdk_logging:
415
+ logger.debug(f"JWT token解析成功: {decoded_payload}")
406
416
  return decoded_payload
407
417
  except jwt.InvalidTokenError as e:
408
- logger.error(f"JWT token解析失败: {str(e)}")
418
+ if self.auth_config.enable_sdk_logging:
419
+ logger.error(f"JWT token解析失败: {str(e)}")
409
420
  return None
410
421
  except Exception as e:
411
- logger.error(f"JWT token解析异常: {str(e)}")
422
+ if self.auth_config.enable_sdk_logging:
423
+ logger.error(f"JWT token解析异常: {str(e)}")
412
424
  return None
413
425
 
414
426
 
@@ -425,7 +437,8 @@ def setup_auth_middleware(auth_config: AuthConfig) -> None:
425
437
  """
426
438
  global auth_service
427
439
  auth_service = AuthService(auth_config)
428
- logger.info(f"认证中间件已配置,白名单路径数量: {len(auth_config.get_whitelist_paths())}")
440
+ if auth_config.enable_sdk_logging:
441
+ logger.info(f"认证中间件已配置,白名单路径数量: {len(auth_config.get_whitelist_paths())}")
429
442
 
430
443
 
431
444
  # 便捷的依赖函数
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: skyplatform-iam
3
- Version: 1.2.0
3
+ Version: 1.2.1
4
4
  Summary: SkyPlatform IAM认证SDK,提供FastAPI中间件和认证路由
5
5
  Project-URL: Homepage, https://github.com/xinmayoujiang12621/agenterra_iam
6
6
  Project-URL: Documentation, https://skyplatform-iam.readthedocs.io/
@@ -0,0 +1,8 @@
1
+ skyplatform_iam/__init__.py,sha256=6ffSGMRItbBPnxgQMaoeB1oGLfXuMK3HHrspuiqyO8s,5591
2
+ skyplatform_iam/config.py,sha256=x3GBikMkC8-0og0Vhs6h5_nTcBXeEd8euDgVDd7IsK4,4607
3
+ skyplatform_iam/connect_agenterra_iam.py,sha256=t03IdWCwBP1oOF1WBTSZETB4MUKQ7zTmfvc6zXD83fg,42050
4
+ skyplatform_iam/exceptions.py,sha256=Rt55QIzVK1F_kn6yzKQKKakD6PZDFdPLCGaCphKKms8,2166
5
+ skyplatform_iam/middleware.py,sha256=jXX8_UciUhOkbK418anqtJoclNhvTQeFnguwPjv5K9E,17863
6
+ skyplatform_iam-1.2.1.dist-info/METADATA,sha256=HLkBft7Qp6w9NFpsHtkVJWFXLcHNZDJ_7_AaXYprZ6E,12658
7
+ skyplatform_iam-1.2.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
+ skyplatform_iam-1.2.1.dist-info/RECORD,,
@@ -1,8 +0,0 @@
1
- skyplatform_iam/__init__.py,sha256=N4acauQXv5CUHNgaeYc3wCTi9zlwt9xvZW5szZ-ahkc,4664
2
- skyplatform_iam/config.py,sha256=4EOzjevFtQ25tZPK7wpU58W6hD-B_XVQF7VCNQzdVOM,4429
3
- skyplatform_iam/connect_agenterra_iam.py,sha256=ixnk45JQoILfwVVKdPllLO-xUqGb8moOh0G6sAIvrVU,40712
4
- skyplatform_iam/exceptions.py,sha256=Rt55QIzVK1F_kn6yzKQKKakD6PZDFdPLCGaCphKKms8,2166
5
- skyplatform_iam/middleware.py,sha256=e_YNRWXmDVKeKwpAcFYptTV4WZboAF-ICC5p9rvLSE0,17069
6
- skyplatform_iam-1.2.0.dist-info/METADATA,sha256=T7kVHT53D8WXPJTomoWc6nDNIS3ZM2SYGVDX_r26JGY,12658
7
- skyplatform_iam-1.2.0.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
8
- skyplatform_iam-1.2.0.dist-info/RECORD,,