skyplatform-iam 1.0.5__py3-none-any.whl → 1.2.0__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.
- skyplatform_iam/__init__.py +73 -69
- skyplatform_iam/config.py +46 -180
- skyplatform_iam/connect_agenterra_iam.py +147 -161
- skyplatform_iam/middleware.py +69 -145
- {skyplatform_iam-1.0.5.dist-info → skyplatform_iam-1.2.0.dist-info}/METADATA +1 -1
- skyplatform_iam-1.2.0.dist-info/RECORD +8 -0
- skyplatform_iam/api.py +0 -366
- skyplatform_iam/global_manager.py +0 -272
- skyplatform_iam-1.0.5.dist-info/RECORD +0 -10
- {skyplatform_iam-1.0.5.dist-info → skyplatform_iam-1.2.0.dist-info}/WHEEL +0 -0
|
@@ -5,6 +5,8 @@ import copy
|
|
|
5
5
|
from enum import Enum
|
|
6
6
|
from fastapi import HTTPException, status
|
|
7
7
|
|
|
8
|
+
from .config import decode_jwt_token
|
|
9
|
+
|
|
8
10
|
|
|
9
11
|
class CredentialTypeEnum(str, Enum):
|
|
10
12
|
"""凭证类型枚举,与后端API保持一致"""
|
|
@@ -17,7 +19,7 @@ class CredentialTypeEnum(str, Enum):
|
|
|
17
19
|
class ConnectAgenterraIam(object):
|
|
18
20
|
_instance = None
|
|
19
21
|
_initialized = False
|
|
20
|
-
|
|
22
|
+
|
|
21
23
|
def __new__(cls, config=None, logger_name="skyplatform_iam", log_level=logging.INFO):
|
|
22
24
|
"""
|
|
23
25
|
单例模式实现
|
|
@@ -26,11 +28,11 @@ class ConnectAgenterraIam(object):
|
|
|
26
28
|
if cls._instance is None:
|
|
27
29
|
cls._instance = super(ConnectAgenterraIam, cls).__new__(cls)
|
|
28
30
|
return cls._instance
|
|
29
|
-
|
|
31
|
+
|
|
30
32
|
def __init__(self, config=None, logger_name="skyplatform_iam", log_level=logging.INFO):
|
|
31
33
|
"""
|
|
32
34
|
初始化AgenterraIAM连接器
|
|
33
|
-
|
|
35
|
+
|
|
34
36
|
参数:
|
|
35
37
|
- config: AuthConfig配置对象,如果为None则从环境变量读取
|
|
36
38
|
- logger_name: 日志记录器名称
|
|
@@ -39,7 +41,7 @@ class ConnectAgenterraIam(object):
|
|
|
39
41
|
# 防止重复初始化
|
|
40
42
|
if self._initialized:
|
|
41
43
|
return
|
|
42
|
-
|
|
44
|
+
|
|
43
45
|
# 配置日志记录器
|
|
44
46
|
self.logger = logging.getLogger(logger_name)
|
|
45
47
|
if not self.logger.handlers:
|
|
@@ -50,16 +52,17 @@ class ConnectAgenterraIam(object):
|
|
|
50
52
|
handler.setFormatter(formatter)
|
|
51
53
|
self.logger.addHandler(handler)
|
|
52
54
|
self.logger.setLevel(log_level)
|
|
53
|
-
|
|
55
|
+
|
|
54
56
|
# 必须传入config参数,不再支持从环境变量读取
|
|
55
57
|
if config is None:
|
|
56
58
|
raise ValueError("必须传入AuthConfig配置对象,不再支持从环境变量读取配置")
|
|
57
|
-
|
|
59
|
+
|
|
58
60
|
self.agenterra_iam_host = config.agenterra_iam_host
|
|
59
61
|
self.server_name = config.server_name
|
|
60
62
|
self.access_key = config.access_key
|
|
63
|
+
self.machine_token = config.machine_token
|
|
61
64
|
self.logger.info("使用传入的AuthConfig配置")
|
|
62
|
-
|
|
65
|
+
|
|
63
66
|
# 验证必要的配置
|
|
64
67
|
if not self.agenterra_iam_host:
|
|
65
68
|
self.logger.warning("AGENTERRA_IAM_HOST 配置未设置")
|
|
@@ -67,9 +70,10 @@ class ConnectAgenterraIam(object):
|
|
|
67
70
|
self.logger.warning("AGENTERRA_SERVER_NAME 配置未设置")
|
|
68
71
|
if not self.access_key:
|
|
69
72
|
self.logger.warning("AGENTERRA_ACCESS_KEY 配置未设置")
|
|
70
|
-
|
|
71
|
-
self.logger.info(
|
|
72
|
-
|
|
73
|
+
|
|
74
|
+
self.logger.info(
|
|
75
|
+
f"初始化AgenterraIAM连接器 - Host: {self.agenterra_iam_host}, Server: {self._mask_sensitive(self.server_name)}")
|
|
76
|
+
|
|
73
77
|
self.headers = {
|
|
74
78
|
"Content-Type": "application/json",
|
|
75
79
|
"SERVER-AK": self.server_name,
|
|
@@ -77,77 +81,31 @@ class ConnectAgenterraIam(object):
|
|
|
77
81
|
}
|
|
78
82
|
self.body = {
|
|
79
83
|
"server_name": self.server_name,
|
|
80
|
-
"access_key": self.access_key
|
|
84
|
+
"access_key": self.access_key,
|
|
85
|
+
"machine_token": self.machine_token
|
|
81
86
|
}
|
|
82
|
-
|
|
87
|
+
|
|
83
88
|
# 标记为已初始化
|
|
84
89
|
self._initialized = True
|
|
85
90
|
|
|
86
|
-
@classmethod
|
|
87
|
-
def get_instance(cls):
|
|
88
|
-
"""
|
|
89
|
-
获取已初始化的ConnectAgenterraIam单例实例
|
|
90
|
-
|
|
91
|
-
如果实例尚未初始化,会抛出异常提示用户先进行配置
|
|
92
|
-
这个方法通常在用户已经通过setup_auth()进行配置后使用
|
|
93
|
-
|
|
94
|
-
返回:
|
|
95
|
-
- ConnectAgenterraIam: 已初始化的单例实例
|
|
96
|
-
|
|
97
|
-
异常:
|
|
98
|
-
- RuntimeError: 当实例未初始化时抛出
|
|
99
|
-
"""
|
|
100
|
-
if cls._instance is None or not cls._initialized:
|
|
101
|
-
raise RuntimeError(
|
|
102
|
-
"ConnectAgenterraIam实例尚未初始化。请先使用以下方式之一进行配置:\n"
|
|
103
|
-
"1. 使用setup_auth()进行一键配置\n"
|
|
104
|
-
"2. 手动创建ConnectAgenterraIam实例:ConnectAgenterraIam(config=your_config)"
|
|
105
|
-
)
|
|
106
|
-
return cls._instance
|
|
107
|
-
|
|
108
|
-
@classmethod
|
|
109
|
-
def get_instance_lazy(cls):
|
|
110
|
-
"""
|
|
111
|
-
获取已初始化的单例实例(延迟模式)
|
|
112
|
-
|
|
113
|
-
此方法支持延迟初始化,当实例未初始化时返回 None 而不是抛出异常。
|
|
114
|
-
适用于在模块导入时需要获取实例但可能尚未初始化的场景。
|
|
115
|
-
|
|
116
|
-
返回:
|
|
117
|
-
- ConnectAgenterraIam: 已初始化的单例实例,如果未初始化则返回 None
|
|
118
|
-
"""
|
|
119
|
-
if cls._instance is None or not cls._initialized:
|
|
120
|
-
return None
|
|
121
|
-
return cls._instance
|
|
122
|
-
|
|
123
|
-
@classmethod
|
|
124
|
-
def is_initialized(cls):
|
|
125
|
-
"""
|
|
126
|
-
检查单例实例是否已初始化
|
|
127
|
-
|
|
128
|
-
返回:
|
|
129
|
-
- bool: 如果实例已初始化返回 True,否则返回 False
|
|
130
|
-
"""
|
|
131
|
-
return cls._instance is not None and cls._initialized
|
|
132
|
-
|
|
133
91
|
def reload_config(self, config):
|
|
134
92
|
"""
|
|
135
93
|
重新加载配置
|
|
136
94
|
用于在运行时更新配置
|
|
137
|
-
|
|
95
|
+
|
|
138
96
|
参数:
|
|
139
97
|
- config: AuthConfig配置对象
|
|
140
98
|
"""
|
|
141
99
|
if config is None:
|
|
142
100
|
raise ValueError("必须传入AuthConfig配置对象")
|
|
143
|
-
|
|
101
|
+
|
|
144
102
|
self.logger.info("重新加载配置")
|
|
145
|
-
|
|
103
|
+
|
|
146
104
|
# 更新配置
|
|
147
105
|
self.agenterra_iam_host = config.agenterra_iam_host
|
|
148
106
|
self.server_name = config.server_name
|
|
149
107
|
self.access_key = config.access_key
|
|
150
|
-
|
|
108
|
+
|
|
151
109
|
# 验证必要的配置
|
|
152
110
|
if not self.agenterra_iam_host:
|
|
153
111
|
self.logger.warning("AGENTERRA_IAM_HOST 配置未设置")
|
|
@@ -155,7 +113,7 @@ class ConnectAgenterraIam(object):
|
|
|
155
113
|
self.logger.warning("AGENTERRA_SERVER_NAME 配置未设置")
|
|
156
114
|
if not self.access_key:
|
|
157
115
|
self.logger.warning("AGENTERRA_ACCESS_KEY 配置未设置")
|
|
158
|
-
|
|
116
|
+
|
|
159
117
|
# 更新headers和body
|
|
160
118
|
self.headers = {
|
|
161
119
|
"Content-Type": "application/json",
|
|
@@ -164,63 +122,65 @@ class ConnectAgenterraIam(object):
|
|
|
164
122
|
}
|
|
165
123
|
self.body = {
|
|
166
124
|
"server_name": self.server_name,
|
|
167
|
-
"access_key": self.access_key
|
|
125
|
+
"access_key": self.access_key,
|
|
126
|
+
"machine_token": self.machine_token,
|
|
168
127
|
}
|
|
169
|
-
|
|
170
|
-
self.logger.info(
|
|
128
|
+
|
|
129
|
+
self.logger.info(
|
|
130
|
+
f"配置重新加载完成 - Host: {self.agenterra_iam_host}, Server: {self._mask_sensitive(self.server_name)}")
|
|
171
131
|
|
|
172
132
|
def _mask_sensitive(self, value, mask_char="*", show_chars=4):
|
|
173
133
|
"""
|
|
174
134
|
脱敏处理敏感信息
|
|
175
|
-
|
|
135
|
+
|
|
176
136
|
参数:
|
|
177
137
|
- value: 要脱敏的值
|
|
178
138
|
- mask_char: 脱敏字符
|
|
179
139
|
- show_chars: 显示的字符数量
|
|
180
|
-
|
|
140
|
+
|
|
181
141
|
返回: 脱敏后的字符串
|
|
182
142
|
"""
|
|
183
143
|
if not value or not isinstance(value, str):
|
|
184
144
|
return str(value) if value else "None"
|
|
185
|
-
|
|
145
|
+
|
|
186
146
|
if len(value) <= show_chars:
|
|
187
147
|
return mask_char * len(value)
|
|
188
|
-
|
|
148
|
+
|
|
189
149
|
return value[:show_chars] + mask_char * (len(value) - show_chars)
|
|
190
150
|
|
|
191
151
|
def _sanitize_log_data(self, data):
|
|
192
152
|
"""
|
|
193
153
|
清理日志数据,脱敏敏感信息
|
|
194
|
-
|
|
154
|
+
|
|
195
155
|
参数:
|
|
196
156
|
- data: 要清理的数据(字典或其他类型)
|
|
197
|
-
|
|
157
|
+
|
|
198
158
|
返回: 清理后的数据
|
|
199
159
|
"""
|
|
200
160
|
if not isinstance(data, dict):
|
|
201
161
|
return data
|
|
202
|
-
|
|
162
|
+
|
|
203
163
|
# 需要脱敏的字段列表
|
|
204
164
|
sensitive_fields = [
|
|
205
|
-
'password', 'access_key', 'token', 'refresh_token',
|
|
165
|
+
'password', 'access_key', 'token', 'refresh_token',
|
|
206
166
|
'SERVER-SK', 'new_password', 'server_sk'
|
|
207
167
|
]
|
|
208
|
-
|
|
168
|
+
|
|
209
169
|
sanitized = copy.deepcopy(data)
|
|
210
|
-
|
|
170
|
+
|
|
211
171
|
for key, value in sanitized.items():
|
|
212
172
|
if key.lower() in [field.lower() for field in sensitive_fields]:
|
|
213
173
|
sanitized[key] = self._mask_sensitive(str(value))
|
|
214
174
|
elif isinstance(value, dict):
|
|
215
175
|
sanitized[key] = self._sanitize_log_data(value)
|
|
216
|
-
|
|
176
|
+
|
|
217
177
|
return sanitized
|
|
218
178
|
|
|
219
179
|
def _log_request(self, method_name, url, headers, body):
|
|
220
180
|
"""记录请求信息"""
|
|
221
181
|
sanitized_headers = self._sanitize_log_data(headers)
|
|
222
182
|
sanitized_body = self._sanitize_log_data(body)
|
|
223
|
-
|
|
183
|
+
|
|
224
184
|
self.logger.info(f"[{method_name}] 发送请求 - URL: {url}")
|
|
225
185
|
self.logger.info(f"[{method_name}] 请求头: {sanitized_headers}")
|
|
226
186
|
self.logger.info(f"[{method_name}] 请求体: {sanitized_body}")
|
|
@@ -236,7 +196,7 @@ class ConnectAgenterraIam(object):
|
|
|
236
196
|
self.logger.info(f"[{method_name}] 响应状态码: {response.status_code}")
|
|
237
197
|
self.logger.info(f"[{method_name}] 响应内容解析失败: {str(e)}")
|
|
238
198
|
|
|
239
|
-
def register(self, cred_type=None, cred_value=None, password=None, nickname=None, avatar_url=None,
|
|
199
|
+
def register(self, cred_type=None, cred_value=None, password=None, nickname=None, avatar_url=None,
|
|
240
200
|
username=None, phone=None):
|
|
241
201
|
"""
|
|
242
202
|
注册用户时,同步至iam
|
|
@@ -259,8 +219,9 @@ class ConnectAgenterraIam(object):
|
|
|
259
219
|
- 失败: 返回False
|
|
260
220
|
"""
|
|
261
221
|
method_name = "register"
|
|
262
|
-
self.logger.info(
|
|
263
|
-
|
|
222
|
+
self.logger.info(
|
|
223
|
+
f"[{method_name}] 开始用户注册 - cred_type: {cred_type}, cred_value: {self._mask_sensitive(str(cred_value))}")
|
|
224
|
+
|
|
264
225
|
try:
|
|
265
226
|
# 参数映射:支持旧的调用方式
|
|
266
227
|
if cred_type is None and cred_value is None:
|
|
@@ -296,10 +257,10 @@ class ConnectAgenterraIam(object):
|
|
|
296
257
|
|
|
297
258
|
uri = "/api/v2/service/register"
|
|
298
259
|
url = self.agenterra_iam_host + uri
|
|
299
|
-
|
|
260
|
+
|
|
300
261
|
# 记录请求信息
|
|
301
262
|
self._log_request(method_name, url, self.headers, body)
|
|
302
|
-
|
|
263
|
+
|
|
303
264
|
response = requests.post(
|
|
304
265
|
url=url,
|
|
305
266
|
headers=self.headers,
|
|
@@ -319,7 +280,7 @@ class ConnectAgenterraIam(object):
|
|
|
319
280
|
self.logger.warning(f"[{method_name}] 用户注册失败 - 响应: {result}")
|
|
320
281
|
else:
|
|
321
282
|
self.logger.warning(f"[{method_name}] 用户注册失败 - 状态码: {response.status_code}")
|
|
322
|
-
|
|
283
|
+
|
|
323
284
|
return False
|
|
324
285
|
except Exception as e:
|
|
325
286
|
self.logger.error(f"[{method_name}] 注册请求异常: {str(e)}")
|
|
@@ -327,7 +288,7 @@ class ConnectAgenterraIam(object):
|
|
|
327
288
|
return False
|
|
328
289
|
|
|
329
290
|
def login_with_password(self, cred_type=None, cred_value=None, password=None, ip_address=None, user_agent=None,
|
|
330
|
-
|
|
291
|
+
username=None):
|
|
331
292
|
"""
|
|
332
293
|
账号密码登陆时,同步至iam,由iam签发token
|
|
333
294
|
|
|
@@ -343,8 +304,9 @@ class ConnectAgenterraIam(object):
|
|
|
343
304
|
- password: 用户密码
|
|
344
305
|
"""
|
|
345
306
|
method_name = "login_with_password"
|
|
346
|
-
self.logger.info(
|
|
347
|
-
|
|
307
|
+
self.logger.info(
|
|
308
|
+
f"[{method_name}] 开始密码登录 - cred_type: {cred_type}, cred_value: {self._mask_sensitive(str(cred_value))}")
|
|
309
|
+
|
|
348
310
|
try:
|
|
349
311
|
# 参数映射:支持旧的调用方式
|
|
350
312
|
if cred_type is None and cred_value is None:
|
|
@@ -375,10 +337,10 @@ class ConnectAgenterraIam(object):
|
|
|
375
337
|
|
|
376
338
|
uri = "/api/v2/service/login"
|
|
377
339
|
url = self.agenterra_iam_host + uri
|
|
378
|
-
|
|
340
|
+
|
|
379
341
|
# 记录请求信息
|
|
380
342
|
self._log_request(method_name, url, self.headers, body)
|
|
381
|
-
|
|
343
|
+
|
|
382
344
|
response = requests.post(
|
|
383
345
|
url=url,
|
|
384
346
|
headers=self.headers,
|
|
@@ -391,10 +353,15 @@ class ConnectAgenterraIam(object):
|
|
|
391
353
|
|
|
392
354
|
if response.status_code == 200:
|
|
393
355
|
self.logger.info(f"[{method_name}] 密码登录成功")
|
|
356
|
+
data = response.json()["data"]
|
|
357
|
+
access_token = data["access_token"]
|
|
358
|
+
payload = decode_jwt_token(access_token)
|
|
359
|
+
self.machine_token = payload["machine_access_token"]
|
|
360
|
+
|
|
394
361
|
return response
|
|
395
362
|
else:
|
|
396
363
|
self.logger.warning(f"[{method_name}] 密码登录失败 - 状态码: {response.status_code}")
|
|
397
|
-
|
|
364
|
+
|
|
398
365
|
return False
|
|
399
366
|
except Exception as e:
|
|
400
367
|
self.logger.error(f"[{method_name}] 密码登录请求异常: {str(e)}")
|
|
@@ -402,7 +369,7 @@ class ConnectAgenterraIam(object):
|
|
|
402
369
|
return False
|
|
403
370
|
|
|
404
371
|
def login_without_password(self, cred_type=None, cred_value=None, ip_address=None, user_agent=None,
|
|
405
|
-
|
|
372
|
+
username=None):
|
|
406
373
|
"""
|
|
407
374
|
短信验证码登陆时,机机接口请求token
|
|
408
375
|
|
|
@@ -418,8 +385,9 @@ class ConnectAgenterraIam(object):
|
|
|
418
385
|
返回: response对象或False
|
|
419
386
|
"""
|
|
420
387
|
method_name = "login_without_password"
|
|
421
|
-
self.logger.info(
|
|
422
|
-
|
|
388
|
+
self.logger.info(
|
|
389
|
+
f"[{method_name}] 开始免密登录 - cred_type: {cred_type}, cred_value: {self._mask_sensitive(str(cred_value))}")
|
|
390
|
+
|
|
423
391
|
try:
|
|
424
392
|
# 参数映射:支持旧的调用方式
|
|
425
393
|
if cred_type is None and cred_value is None:
|
|
@@ -449,10 +417,10 @@ class ConnectAgenterraIam(object):
|
|
|
449
417
|
|
|
450
418
|
uri = "/api/v2/service/login_without_password"
|
|
451
419
|
url = self.agenterra_iam_host + uri
|
|
452
|
-
|
|
420
|
+
|
|
453
421
|
# 记录请求信息
|
|
454
422
|
self._log_request(method_name, url, self.headers, body)
|
|
455
|
-
|
|
423
|
+
|
|
456
424
|
response = requests.post(
|
|
457
425
|
url=url,
|
|
458
426
|
headers=self.headers,
|
|
@@ -468,7 +436,7 @@ class ConnectAgenterraIam(object):
|
|
|
468
436
|
return response
|
|
469
437
|
else:
|
|
470
438
|
self.logger.warning(f"[{method_name}] 免密登录失败 - 状态码: {response.status_code}")
|
|
471
|
-
|
|
439
|
+
|
|
472
440
|
return False
|
|
473
441
|
except Exception as e:
|
|
474
442
|
self.logger.error(f"[{method_name}] 免密登录请求异常: {str(e)}")
|
|
@@ -483,7 +451,7 @@ class ConnectAgenterraIam(object):
|
|
|
483
451
|
"""
|
|
484
452
|
method_name = "logout"
|
|
485
453
|
self.logger.info(f"[{method_name}] 开始用户登出 - token: {self._mask_sensitive(token)}")
|
|
486
|
-
|
|
454
|
+
|
|
487
455
|
try:
|
|
488
456
|
body = {
|
|
489
457
|
"server_name": self.server_name,
|
|
@@ -492,13 +460,16 @@ class ConnectAgenterraIam(object):
|
|
|
492
460
|
}
|
|
493
461
|
uri = "/api/v2/service/logout"
|
|
494
462
|
url = self.agenterra_iam_host + uri
|
|
495
|
-
|
|
463
|
+
|
|
496
464
|
# 记录请求信息
|
|
497
465
|
self._log_request(method_name, url, self.headers, body)
|
|
498
466
|
|
|
467
|
+
headers = self.headers.copy()
|
|
468
|
+
headers['MACHINE-TOKEN'] = self.machine_token
|
|
469
|
+
|
|
499
470
|
response = requests.post(
|
|
500
471
|
url=url,
|
|
501
|
-
headers=
|
|
472
|
+
headers=headers,
|
|
502
473
|
json=body,
|
|
503
474
|
verify=False
|
|
504
475
|
)
|
|
@@ -511,14 +482,14 @@ class ConnectAgenterraIam(object):
|
|
|
511
482
|
return True
|
|
512
483
|
else:
|
|
513
484
|
self.logger.warning(f"[{method_name}] 用户登出失败 - 状态码: {response.status_code}")
|
|
514
|
-
|
|
485
|
+
|
|
515
486
|
return False
|
|
516
487
|
except Exception as e:
|
|
517
488
|
self.logger.error(f"[{method_name}] 登出请求异常: {str(e)}")
|
|
518
489
|
self.logger.error(f"[{method_name}] 异常堆栈: {traceback.format_exc()}")
|
|
519
490
|
return False
|
|
520
491
|
|
|
521
|
-
def verify_token(self, token, api, method, server_ak="", server_sk=""):
|
|
492
|
+
def verify_token(self, token, api, method, server_ak="", server_sk="", machine_token=""):
|
|
522
493
|
"""
|
|
523
494
|
请求iam进行鉴权
|
|
524
495
|
server_name: 服务名称
|
|
@@ -531,12 +502,14 @@ class ConnectAgenterraIam(object):
|
|
|
531
502
|
- token无效或其他错误: 返回None
|
|
532
503
|
"""
|
|
533
504
|
method_name = "verify_token"
|
|
534
|
-
self.logger.info(
|
|
535
|
-
|
|
505
|
+
self.logger.info(
|
|
506
|
+
f"[{method_name}] 开始token验证 - api: {api}, method: {method}, token: {self._mask_sensitive(token)}")
|
|
507
|
+
|
|
536
508
|
try:
|
|
537
509
|
body = {
|
|
538
510
|
"server_name": self.server_name,
|
|
539
511
|
"access_key": self.access_key,
|
|
512
|
+
"machine_token": machine_token if machine_token else self.machine_token,
|
|
540
513
|
"token": token,
|
|
541
514
|
"api": api,
|
|
542
515
|
"method": method,
|
|
@@ -544,16 +517,16 @@ class ConnectAgenterraIam(object):
|
|
|
544
517
|
"server_sk": server_sk,
|
|
545
518
|
}
|
|
546
519
|
uri = "/api/v2/service/verify"
|
|
547
|
-
|
|
520
|
+
|
|
548
521
|
# 检查agenterra_iam_host是否为None
|
|
549
522
|
if self.agenterra_iam_host is None:
|
|
550
523
|
raise ValueError("AGENTERRA_IAM_HOST 配置未设置或为空,请确保传入正确的AuthConfig对象")
|
|
551
|
-
|
|
524
|
+
|
|
552
525
|
url = self.agenterra_iam_host + uri
|
|
553
|
-
|
|
526
|
+
|
|
554
527
|
# 记录请求信息
|
|
555
528
|
self._log_request(method_name, url, self.headers, body)
|
|
556
|
-
|
|
529
|
+
|
|
557
530
|
response = requests.post(
|
|
558
531
|
url=url,
|
|
559
532
|
headers=self.headers,
|
|
@@ -577,7 +550,8 @@ class ConnectAgenterraIam(object):
|
|
|
577
550
|
"microservice": result.get("microservice"),
|
|
578
551
|
"is_whitelist": result.get("is_whitelist", False)
|
|
579
552
|
}
|
|
580
|
-
self.logger.info(
|
|
553
|
+
self.logger.info(
|
|
554
|
+
f"[{method_name}] token验证成功,用户有权限 - user_id: {user_info.get('user_id')}")
|
|
581
555
|
return user_info
|
|
582
556
|
else:
|
|
583
557
|
# token有效但无权限,抛出403异常
|
|
@@ -587,7 +561,8 @@ class ConnectAgenterraIam(object):
|
|
|
587
561
|
detail=result.get("message", "用户无权限访问此API")
|
|
588
562
|
)
|
|
589
563
|
else:
|
|
590
|
-
self.logger.warning(
|
|
564
|
+
self.logger.warning(
|
|
565
|
+
f"[{method_name}] token验证失败 - success: {result.get('success')}, valid: {result.get('valid')}")
|
|
591
566
|
|
|
592
567
|
elif response.status_code == 403:
|
|
593
568
|
result = response.json()
|
|
@@ -623,11 +598,11 @@ class ConnectAgenterraIam(object):
|
|
|
623
598
|
"""
|
|
624
599
|
method_name = "reset_password"
|
|
625
600
|
self.logger.info(f"[{method_name}] 开始重置密码 - user_id: {user_id}")
|
|
626
|
-
|
|
601
|
+
|
|
627
602
|
# 记录旧参数格式的使用
|
|
628
603
|
if username or password:
|
|
629
604
|
self.logger.debug(f"[{method_name}] 检测到旧参数格式 - username: {username}")
|
|
630
|
-
|
|
605
|
+
|
|
631
606
|
try:
|
|
632
607
|
# 参数映射:支持旧的调用方式
|
|
633
608
|
if user_id is None and new_password is None:
|
|
@@ -641,31 +616,32 @@ class ConnectAgenterraIam(object):
|
|
|
641
616
|
body = {
|
|
642
617
|
"server_name": self.server_name,
|
|
643
618
|
"access_key": self.access_key,
|
|
619
|
+
"machine_token": self.machine_token,
|
|
644
620
|
"user_id": user_id,
|
|
645
621
|
"new_password": new_password
|
|
646
622
|
}
|
|
647
623
|
uri = "/api/v2/service/reset_password"
|
|
648
624
|
url = self.agenterra_iam_host + uri
|
|
649
|
-
|
|
625
|
+
|
|
650
626
|
# 记录请求信息
|
|
651
627
|
self._log_request(method_name, url, self.headers, body)
|
|
652
|
-
|
|
628
|
+
|
|
653
629
|
response = requests.post(
|
|
654
630
|
url=url,
|
|
655
631
|
headers=self.headers,
|
|
656
632
|
json=body,
|
|
657
633
|
verify=False
|
|
658
634
|
)
|
|
659
|
-
|
|
635
|
+
|
|
660
636
|
# 记录响应信息
|
|
661
637
|
self._log_response(method_name, response)
|
|
662
|
-
|
|
638
|
+
|
|
663
639
|
if response.status_code == 200:
|
|
664
640
|
self.logger.info(f"[{method_name}] 密码重置成功")
|
|
665
641
|
return True
|
|
666
642
|
else:
|
|
667
643
|
self.logger.warning(f"[{method_name}] 密码重置失败 - 状态码: {response.status_code}")
|
|
668
|
-
|
|
644
|
+
|
|
669
645
|
return False
|
|
670
646
|
except Exception as e:
|
|
671
647
|
self.logger.error(f"[{method_name}] 重置密码请求异常: {str(e)}")
|
|
@@ -683,19 +659,20 @@ class ConnectAgenterraIam(object):
|
|
|
683
659
|
"""
|
|
684
660
|
method_name = "refresh_token"
|
|
685
661
|
self.logger.info(f"[{method_name}] 开始刷新令牌 - refresh_token: {self._mask_sensitive(refresh_token)}")
|
|
686
|
-
|
|
662
|
+
|
|
687
663
|
try:
|
|
688
664
|
body = {
|
|
689
665
|
"server_name": self.server_name,
|
|
690
666
|
"access_key": self.access_key,
|
|
667
|
+
"machine_token": self.machine_token,
|
|
691
668
|
"refresh_token": refresh_token
|
|
692
669
|
}
|
|
693
670
|
uri = "/api/v2/service/refresh_token"
|
|
694
671
|
url = self.agenterra_iam_host + uri
|
|
695
|
-
|
|
672
|
+
|
|
696
673
|
# 记录请求信息
|
|
697
674
|
self._log_request(method_name, url, self.headers, body)
|
|
698
|
-
|
|
675
|
+
|
|
699
676
|
response = requests.post(
|
|
700
677
|
url=url,
|
|
701
678
|
headers=self.headers,
|
|
@@ -711,7 +688,7 @@ class ConnectAgenterraIam(object):
|
|
|
711
688
|
return response
|
|
712
689
|
else:
|
|
713
690
|
self.logger.warning(f"[{method_name}] 令牌刷新失败 - 状态码: {response.status_code}")
|
|
714
|
-
|
|
691
|
+
|
|
715
692
|
return False
|
|
716
693
|
except Exception as e:
|
|
717
694
|
self.logger.error(f"[{method_name}] 刷新令牌请求异常: {str(e)}")
|
|
@@ -730,20 +707,21 @@ class ConnectAgenterraIam(object):
|
|
|
730
707
|
"""
|
|
731
708
|
method_name = "assign_role_to_user"
|
|
732
709
|
self.logger.info(f"[{method_name}] 开始角色分配 - user_id: {user_id}, role_id: {role_id}")
|
|
733
|
-
|
|
710
|
+
|
|
734
711
|
try:
|
|
735
712
|
body = {
|
|
736
713
|
"server_name": self.server_name,
|
|
737
714
|
"access_key": self.access_key,
|
|
715
|
+
"machine_token": self.machine_token,
|
|
738
716
|
"user_id": user_id,
|
|
739
717
|
"role_id": role_id
|
|
740
718
|
}
|
|
741
719
|
uri = "/api/v2/service/assign_role"
|
|
742
720
|
url = self.agenterra_iam_host + uri
|
|
743
|
-
|
|
721
|
+
|
|
744
722
|
# 记录请求信息
|
|
745
723
|
self._log_request(method_name, url, self.headers, body)
|
|
746
|
-
|
|
724
|
+
|
|
747
725
|
response = requests.post(
|
|
748
726
|
url=url,
|
|
749
727
|
headers=self.headers,
|
|
@@ -759,7 +737,7 @@ class ConnectAgenterraIam(object):
|
|
|
759
737
|
return True
|
|
760
738
|
else:
|
|
761
739
|
self.logger.warning(f"[{method_name}] 角色分配失败 - 状态码: {response.status_code}")
|
|
762
|
-
|
|
740
|
+
|
|
763
741
|
return False
|
|
764
742
|
except Exception as e:
|
|
765
743
|
self.logger.error(f"[{method_name}] 角色分配请求异常: {str(e)}")
|
|
@@ -772,19 +750,20 @@ class ConnectAgenterraIam(object):
|
|
|
772
750
|
"""
|
|
773
751
|
method_name = "get_userinfo_by_token"
|
|
774
752
|
self.logger.info(f"[{method_name}] 开始获取用户信息 - token: {self._mask_sensitive(token)}")
|
|
775
|
-
|
|
753
|
+
|
|
776
754
|
try:
|
|
777
755
|
body = {
|
|
778
756
|
"server_name": self.server_name,
|
|
779
757
|
"access_key": self.access_key,
|
|
758
|
+
"machine_token": self.machine_token,
|
|
780
759
|
"token": token,
|
|
781
760
|
}
|
|
782
761
|
uri = "/api/v2/service/token"
|
|
783
762
|
url = self.agenterra_iam_host + uri
|
|
784
|
-
|
|
763
|
+
|
|
785
764
|
# 记录请求信息
|
|
786
765
|
self._log_request(method_name, url, self.headers, body)
|
|
787
|
-
|
|
766
|
+
|
|
788
767
|
response = requests.post(
|
|
789
768
|
url=url,
|
|
790
769
|
headers=self.headers,
|
|
@@ -800,7 +779,7 @@ class ConnectAgenterraIam(object):
|
|
|
800
779
|
return response
|
|
801
780
|
else:
|
|
802
781
|
self.logger.warning(f"[{method_name}] 获取用户信息失败 - 状态码: {response.status_code}")
|
|
803
|
-
|
|
782
|
+
|
|
804
783
|
return False
|
|
805
784
|
except Exception as e:
|
|
806
785
|
self.logger.error(f"[{method_name}] 获取用户信息请求异常: {str(e)}")
|
|
@@ -810,7 +789,7 @@ class ConnectAgenterraIam(object):
|
|
|
810
789
|
def add_custom_config(self, user_id, config_name, config_value=None):
|
|
811
790
|
"""
|
|
812
791
|
机机接口:添加用户自定义配置
|
|
813
|
-
|
|
792
|
+
|
|
814
793
|
为指定用户添加或更新自定义属性配置。
|
|
815
794
|
|
|
816
795
|
参数:
|
|
@@ -818,17 +797,18 @@ class ConnectAgenterraIam(object):
|
|
|
818
797
|
- config_name: 配置项名称
|
|
819
798
|
- config_value: 配置项值(可选)
|
|
820
799
|
|
|
821
|
-
返回:
|
|
800
|
+
返回:
|
|
822
801
|
- 成功: 返回响应对象
|
|
823
802
|
- 失败: 返回False
|
|
824
803
|
"""
|
|
825
804
|
method_name = "add_custom_config"
|
|
826
805
|
self.logger.info(f"[{method_name}] 开始添加用户自定义配置 - user_id: {user_id}, config_name: {config_name}")
|
|
827
|
-
|
|
806
|
+
|
|
828
807
|
try:
|
|
829
808
|
body = {
|
|
830
809
|
"server_name": self.server_name,
|
|
831
810
|
"access_key": self.access_key,
|
|
811
|
+
"machine_token": self.machine_token,
|
|
832
812
|
"user_id": user_id,
|
|
833
813
|
"config_name": config_name
|
|
834
814
|
}
|
|
@@ -839,10 +819,10 @@ class ConnectAgenterraIam(object):
|
|
|
839
819
|
|
|
840
820
|
uri = "/api/v2/service/add_custom_config"
|
|
841
821
|
url = self.agenterra_iam_host + uri
|
|
842
|
-
|
|
822
|
+
|
|
843
823
|
# 记录请求信息
|
|
844
824
|
self._log_request(method_name, url, self.headers, body)
|
|
845
|
-
|
|
825
|
+
|
|
846
826
|
response = requests.post(
|
|
847
827
|
url=url,
|
|
848
828
|
headers=self.headers,
|
|
@@ -858,7 +838,7 @@ class ConnectAgenterraIam(object):
|
|
|
858
838
|
return response
|
|
859
839
|
else:
|
|
860
840
|
self.logger.warning(f"[{method_name}] 添加用户自定义配置失败 - 状态码: {response.status_code}")
|
|
861
|
-
|
|
841
|
+
|
|
862
842
|
return False
|
|
863
843
|
except Exception as e:
|
|
864
844
|
self.logger.error(f"[{method_name}] 添加用户自定义配置请求异常: {str(e)}")
|
|
@@ -868,32 +848,33 @@ class ConnectAgenterraIam(object):
|
|
|
868
848
|
def get_custom_configs(self, user_id):
|
|
869
849
|
"""
|
|
870
850
|
机机接口:获取用户自定义配置
|
|
871
|
-
|
|
851
|
+
|
|
872
852
|
获取指定用户的所有自定义属性配置。
|
|
873
853
|
|
|
874
854
|
参数:
|
|
875
855
|
- user_id: 用户ID
|
|
876
856
|
|
|
877
|
-
返回:
|
|
857
|
+
返回:
|
|
878
858
|
- 成功: 返回响应对象
|
|
879
859
|
- 失败: 返回False
|
|
880
860
|
"""
|
|
881
861
|
method_name = "get_custom_configs"
|
|
882
862
|
self.logger.info(f"[{method_name}] 开始获取用户自定义配置 - user_id: {user_id}")
|
|
883
|
-
|
|
863
|
+
|
|
884
864
|
try:
|
|
885
865
|
body = {
|
|
886
866
|
"server_name": self.server_name,
|
|
887
867
|
"access_key": self.access_key,
|
|
868
|
+
"machine_token": self.machine_token,
|
|
888
869
|
"user_id": user_id
|
|
889
870
|
}
|
|
890
871
|
|
|
891
872
|
uri = "/api/v2/service/get_custom_configs"
|
|
892
873
|
url = self.agenterra_iam_host + uri
|
|
893
|
-
|
|
874
|
+
|
|
894
875
|
# 记录请求信息
|
|
895
876
|
self._log_request(method_name, url, self.headers, body)
|
|
896
|
-
|
|
877
|
+
|
|
897
878
|
response = requests.post(
|
|
898
879
|
url=url,
|
|
899
880
|
headers=self.headers,
|
|
@@ -909,7 +890,7 @@ class ConnectAgenterraIam(object):
|
|
|
909
890
|
return response
|
|
910
891
|
else:
|
|
911
892
|
self.logger.warning(f"[{method_name}] 获取用户自定义配置失败 - 状态码: {response.status_code}")
|
|
912
|
-
|
|
893
|
+
|
|
913
894
|
return False
|
|
914
895
|
except Exception as e:
|
|
915
896
|
self.logger.error(f"[{method_name}] 获取用户自定义配置请求异常: {str(e)}")
|
|
@@ -919,34 +900,35 @@ class ConnectAgenterraIam(object):
|
|
|
919
900
|
def delete_custom_config(self, user_id, config_name):
|
|
920
901
|
"""
|
|
921
902
|
机机接口:删除用户自定义配置
|
|
922
|
-
|
|
903
|
+
|
|
923
904
|
删除指定用户的指定自定义属性配置。
|
|
924
905
|
|
|
925
906
|
参数:
|
|
926
907
|
- user_id: 用户ID
|
|
927
908
|
- config_name: 配置项名称
|
|
928
909
|
|
|
929
|
-
返回:
|
|
910
|
+
返回:
|
|
930
911
|
- 成功: 返回响应对象
|
|
931
912
|
- 失败: 返回False
|
|
932
913
|
"""
|
|
933
914
|
method_name = "delete_custom_config"
|
|
934
915
|
self.logger.info(f"[{method_name}] 开始删除用户自定义配置 - user_id: {user_id}, config_name: {config_name}")
|
|
935
|
-
|
|
916
|
+
|
|
936
917
|
try:
|
|
937
918
|
body = {
|
|
938
919
|
"server_name": self.server_name,
|
|
939
920
|
"access_key": self.access_key,
|
|
921
|
+
"machine_token": self.machine_token,
|
|
940
922
|
"user_id": user_id,
|
|
941
923
|
"config_name": config_name
|
|
942
924
|
}
|
|
943
925
|
|
|
944
926
|
uri = "/api/v2/service/delete_custom_config"
|
|
945
927
|
url = self.agenterra_iam_host + uri
|
|
946
|
-
|
|
928
|
+
|
|
947
929
|
# 记录请求信息
|
|
948
930
|
self._log_request(method_name, url, self.headers, body)
|
|
949
|
-
|
|
931
|
+
|
|
950
932
|
response = requests.post(
|
|
951
933
|
url=url,
|
|
952
934
|
headers=self.headers,
|
|
@@ -962,7 +944,7 @@ class ConnectAgenterraIam(object):
|
|
|
962
944
|
return response
|
|
963
945
|
else:
|
|
964
946
|
self.logger.warning(f"[{method_name}] 删除用户自定义配置失败 - 状态码: {response.status_code}")
|
|
965
|
-
|
|
947
|
+
|
|
966
948
|
return False
|
|
967
949
|
except Exception as e:
|
|
968
950
|
self.logger.error(f"[{method_name}] 删除用户自定义配置请求异常: {str(e)}")
|
|
@@ -972,7 +954,7 @@ class ConnectAgenterraIam(object):
|
|
|
972
954
|
def merge_credential(self, target_user_id, cred_type, cred_value, merge_reason=None):
|
|
973
955
|
"""
|
|
974
956
|
机机接口:凭证合并
|
|
975
|
-
|
|
957
|
+
|
|
976
958
|
为第三方服务提供凭证合并功能,处理用户绑定新凭证时的账号合并场景。
|
|
977
959
|
例如用户先用账号密码注册,后续又绑定手机号时的账号合并需求。
|
|
978
960
|
|
|
@@ -982,13 +964,14 @@ class ConnectAgenterraIam(object):
|
|
|
982
964
|
- cred_value: 要绑定的凭证值
|
|
983
965
|
- merge_reason: 合并原因(可选)
|
|
984
966
|
|
|
985
|
-
返回:
|
|
967
|
+
返回:
|
|
986
968
|
- 成功: 返回响应对象
|
|
987
969
|
- 失败: 返回False
|
|
988
970
|
"""
|
|
989
971
|
method_name = "merge_credential"
|
|
990
|
-
self.logger.info(
|
|
991
|
-
|
|
972
|
+
self.logger.info(
|
|
973
|
+
f"[{method_name}] 开始凭证合并 - target_user_id: {target_user_id}, cred_type: {cred_type}, cred_value: {self._mask_sensitive(cred_value)}")
|
|
974
|
+
|
|
992
975
|
try:
|
|
993
976
|
# 验证凭证类型
|
|
994
977
|
if isinstance(cred_type, str):
|
|
@@ -997,6 +980,7 @@ class ConnectAgenterraIam(object):
|
|
|
997
980
|
body = {
|
|
998
981
|
"server_name": self.server_name,
|
|
999
982
|
"access_key": self.access_key,
|
|
983
|
+
"machine_token": self.machine_token,
|
|
1000
984
|
"target_user_id": target_user_id,
|
|
1001
985
|
"cred_type": cred_type.value,
|
|
1002
986
|
"cred_value": cred_value
|
|
@@ -1009,10 +993,10 @@ class ConnectAgenterraIam(object):
|
|
|
1009
993
|
|
|
1010
994
|
uri = "/api/v2/service/merge_credential"
|
|
1011
995
|
url = self.agenterra_iam_host + uri
|
|
1012
|
-
|
|
996
|
+
|
|
1013
997
|
# 记录请求信息
|
|
1014
998
|
self._log_request(method_name, url, self.headers, body)
|
|
1015
|
-
|
|
999
|
+
|
|
1016
1000
|
response = requests.post(
|
|
1017
1001
|
url=url,
|
|
1018
1002
|
headers=self.headers,
|
|
@@ -1028,7 +1012,7 @@ class ConnectAgenterraIam(object):
|
|
|
1028
1012
|
return response
|
|
1029
1013
|
else:
|
|
1030
1014
|
self.logger.warning(f"[{method_name}] 凭证合并失败 - 状态码: {response.status_code}")
|
|
1031
|
-
|
|
1015
|
+
|
|
1032
1016
|
return False
|
|
1033
1017
|
except Exception as e:
|
|
1034
1018
|
self.logger.error(f"[{method_name}] 凭证合并请求异常: {str(e)}")
|
|
@@ -1038,20 +1022,21 @@ class ConnectAgenterraIam(object):
|
|
|
1038
1022
|
def get_user_by_credential(self, cred_type, cred_value):
|
|
1039
1023
|
"""
|
|
1040
1024
|
机机接口:通过凭证获取用户信息
|
|
1041
|
-
|
|
1025
|
+
|
|
1042
1026
|
为第三方服务提供通过用户名或手机号等认证凭据获取用户信息的功能。
|
|
1043
1027
|
|
|
1044
1028
|
参数:
|
|
1045
1029
|
- cred_type: 凭证类型 (CredentialTypeEnum: username, email, phone, wechat_openid)
|
|
1046
1030
|
- cred_value: 凭证值
|
|
1047
1031
|
|
|
1048
|
-
返回:
|
|
1032
|
+
返回:
|
|
1049
1033
|
- 成功: 返回响应对象
|
|
1050
1034
|
- 失败: 返回False
|
|
1051
1035
|
"""
|
|
1052
1036
|
method_name = "get_user_by_credential"
|
|
1053
|
-
self.logger.info(
|
|
1054
|
-
|
|
1037
|
+
self.logger.info(
|
|
1038
|
+
f"[{method_name}] 开始获取用户信息 - cred_type: {cred_type}, cred_value: {self._mask_sensitive(cred_value)}")
|
|
1039
|
+
|
|
1055
1040
|
try:
|
|
1056
1041
|
# 验证凭证类型
|
|
1057
1042
|
if isinstance(cred_type, str):
|
|
@@ -1060,16 +1045,17 @@ class ConnectAgenterraIam(object):
|
|
|
1060
1045
|
body = {
|
|
1061
1046
|
"server_name": self.server_name,
|
|
1062
1047
|
"access_key": self.access_key,
|
|
1048
|
+
"machine_token": self.machine_token,
|
|
1063
1049
|
"cred_type": cred_type.value,
|
|
1064
1050
|
"cred_value": cred_value
|
|
1065
1051
|
}
|
|
1066
1052
|
|
|
1067
1053
|
uri = "/api/v2/service/get_user_by_credential"
|
|
1068
1054
|
url = self.agenterra_iam_host + uri
|
|
1069
|
-
|
|
1055
|
+
|
|
1070
1056
|
# 记录请求信息
|
|
1071
1057
|
self._log_request(method_name, url, self.headers, body)
|
|
1072
|
-
|
|
1058
|
+
|
|
1073
1059
|
response = requests.post(
|
|
1074
1060
|
url=url,
|
|
1075
1061
|
headers=self.headers,
|
|
@@ -1085,7 +1071,7 @@ class ConnectAgenterraIam(object):
|
|
|
1085
1071
|
return response
|
|
1086
1072
|
else:
|
|
1087
1073
|
self.logger.warning(f"[{method_name}] 获取用户信息失败 - 状态码: {response.status_code}")
|
|
1088
|
-
|
|
1074
|
+
|
|
1089
1075
|
return False
|
|
1090
1076
|
except Exception as e:
|
|
1091
1077
|
self.logger.error(f"[{method_name}] 获取用户信息请求异常: {str(e)}")
|