skyplatform-iam 1.0.5__py3-none-any.whl → 1.1.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 +18 -173
- skyplatform_iam/connect_agenterra_iam.py +88 -127
- skyplatform_iam/middleware.py +31 -138
- {skyplatform_iam-1.0.5.dist-info → skyplatform_iam-1.1.0.dist-info}/METADATA +1 -1
- skyplatform_iam-1.1.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.1.0.dist-info}/WHEEL +0 -0
skyplatform_iam/__init__.py
CHANGED
|
@@ -4,28 +4,8 @@ SkyPlatform IAM SDK
|
|
|
4
4
|
"""
|
|
5
5
|
|
|
6
6
|
from .config import AuthConfig
|
|
7
|
-
from .middleware import
|
|
8
|
-
AuthMiddleware,
|
|
9
|
-
AuthService,
|
|
10
|
-
setup_auth_middleware,
|
|
11
|
-
get_current_user,
|
|
12
|
-
get_optional_user,
|
|
13
|
-
create_auth_middleware
|
|
14
|
-
)
|
|
7
|
+
from .middleware import AuthMiddleware, AuthService, setup_auth_middleware, get_current_user, get_optional_user
|
|
15
8
|
from .connect_agenterra_iam import ConnectAgenterraIam
|
|
16
|
-
from .global_manager import GlobalIAMManager, get_global_manager
|
|
17
|
-
from .api import (
|
|
18
|
-
init_skyplatform_iam,
|
|
19
|
-
get_iam_client,
|
|
20
|
-
create_lazy_iam_client,
|
|
21
|
-
LazyIAMClient,
|
|
22
|
-
get_current_user_info,
|
|
23
|
-
verify_permission,
|
|
24
|
-
get_config,
|
|
25
|
-
get_sdk_status,
|
|
26
|
-
reset_sdk,
|
|
27
|
-
setup_auth # 向后兼容的别名
|
|
28
|
-
)
|
|
29
9
|
from .exceptions import (
|
|
30
10
|
SkyPlatformAuthException,
|
|
31
11
|
AuthenticationError,
|
|
@@ -37,39 +17,28 @@ from .exceptions import (
|
|
|
37
17
|
NetworkError
|
|
38
18
|
)
|
|
39
19
|
|
|
40
|
-
__version__ = "
|
|
20
|
+
__version__ = "1.0.0"
|
|
41
21
|
__author__ = "x9"
|
|
42
22
|
__description__ = "SkyPlatform IAM认证SDK,提供FastAPI中间件和IAM服务连接功能"
|
|
43
23
|
|
|
24
|
+
# 全局IAM客户端实例
|
|
25
|
+
_global_iam_client = None
|
|
26
|
+
|
|
44
27
|
# 导出主要类和函数
|
|
45
28
|
__all__ = [
|
|
46
29
|
# 配置
|
|
47
30
|
"AuthConfig",
|
|
48
31
|
|
|
49
|
-
# 新的统一API(推荐使用)
|
|
50
|
-
"init_skyplatform_iam",
|
|
51
|
-
"get_iam_client",
|
|
52
|
-
"create_lazy_iam_client",
|
|
53
|
-
"LazyIAMClient",
|
|
54
|
-
"get_current_user_info",
|
|
55
|
-
"verify_permission",
|
|
56
|
-
"get_config",
|
|
57
|
-
"get_sdk_status",
|
|
58
|
-
"reset_sdk",
|
|
59
|
-
|
|
60
|
-
# 全局管理器
|
|
61
|
-
"GlobalIAMManager",
|
|
62
|
-
"get_global_manager",
|
|
63
|
-
|
|
64
32
|
# 中间件
|
|
65
33
|
"AuthMiddleware",
|
|
66
34
|
"AuthService",
|
|
67
|
-
"
|
|
35
|
+
"setup_auth_middleware",
|
|
68
36
|
"get_current_user",
|
|
69
37
|
"get_optional_user",
|
|
70
38
|
|
|
71
39
|
# 客户端
|
|
72
40
|
"ConnectAgenterraIam",
|
|
41
|
+
"get_iam_client",
|
|
73
42
|
|
|
74
43
|
# 异常
|
|
75
44
|
"SkyPlatformAuthException",
|
|
@@ -81,10 +50,6 @@ __all__ = [
|
|
|
81
50
|
"IAMServiceError",
|
|
82
51
|
"NetworkError",
|
|
83
52
|
|
|
84
|
-
# 向后兼容(已废弃)
|
|
85
|
-
"setup_auth_middleware",
|
|
86
|
-
"setup_auth",
|
|
87
|
-
|
|
88
53
|
# 版本信息
|
|
89
54
|
"__version__",
|
|
90
55
|
"__author__",
|
|
@@ -92,10 +57,9 @@ __all__ = [
|
|
|
92
57
|
]
|
|
93
58
|
|
|
94
59
|
|
|
95
|
-
|
|
96
|
-
def create_auth_middleware_legacy(config: AuthConfig = None, **kwargs) -> AuthMiddleware:
|
|
60
|
+
def create_auth_middleware(config: AuthConfig = None, **kwargs) -> AuthMiddleware:
|
|
97
61
|
"""
|
|
98
|
-
|
|
62
|
+
创建认证中间件的便捷函数
|
|
99
63
|
|
|
100
64
|
Args:
|
|
101
65
|
config: 认证配置,如果为None则从环境变量创建
|
|
@@ -104,25 +68,19 @@ def create_auth_middleware_legacy(config: AuthConfig = None, **kwargs) -> AuthMi
|
|
|
104
68
|
Returns:
|
|
105
69
|
AuthMiddleware: 认证中间件实例
|
|
106
70
|
|
|
107
|
-
|
|
108
|
-
|
|
71
|
+
Note:
|
|
72
|
+
此函数用于创建中间件实例,用于请求拦截和鉴权。
|
|
73
|
+
客户端应用需要自己实现具体的业务接口。
|
|
109
74
|
"""
|
|
110
|
-
import warnings
|
|
111
|
-
warnings.warn(
|
|
112
|
-
"create_auth_middleware_legacy()已废弃,请使用init_skyplatform_iam() + create_auth_middleware()替代",
|
|
113
|
-
DeprecationWarning,
|
|
114
|
-
stacklevel=2
|
|
115
|
-
)
|
|
116
|
-
|
|
117
75
|
if config is None:
|
|
118
76
|
config = AuthConfig.from_env()
|
|
119
77
|
|
|
120
|
-
return AuthMiddleware(config=config,
|
|
78
|
+
return AuthMiddleware(config=config, **kwargs)
|
|
121
79
|
|
|
122
80
|
|
|
123
|
-
def
|
|
81
|
+
def init_skyplatform_iam(app, config: AuthConfig = None):
|
|
124
82
|
"""
|
|
125
|
-
|
|
83
|
+
一键设置认证中间件的便捷函数
|
|
126
84
|
|
|
127
85
|
Args:
|
|
128
86
|
app: FastAPI应用实例
|
|
@@ -131,16 +89,11 @@ def setup_auth_legacy(app, config: AuthConfig = None):
|
|
|
131
89
|
Returns:
|
|
132
90
|
AuthMiddleware: 认证中间件实例
|
|
133
91
|
|
|
134
|
-
|
|
135
|
-
|
|
92
|
+
Note:
|
|
93
|
+
此函数只设置认证中间件,不包含预制路由。
|
|
94
|
+
客户端应用需要根据业务需求自己实现认证相关的API接口。
|
|
95
|
+
建议传入完整的AuthConfig对象以避免环境变量配置问题。
|
|
136
96
|
"""
|
|
137
|
-
import warnings
|
|
138
|
-
warnings.warn(
|
|
139
|
-
"setup_auth_legacy()已废弃,请使用init_skyplatform_iam()替代",
|
|
140
|
-
DeprecationWarning,
|
|
141
|
-
stacklevel=2
|
|
142
|
-
)
|
|
143
|
-
|
|
144
97
|
if config is None:
|
|
145
98
|
config = AuthConfig.from_env()
|
|
146
99
|
|
|
@@ -151,7 +104,58 @@ def setup_auth_legacy(app, config: AuthConfig = None):
|
|
|
151
104
|
setup_auth_middleware(config)
|
|
152
105
|
|
|
153
106
|
# 添加中间件
|
|
154
|
-
middleware = AuthMiddleware(app=app, config=config
|
|
155
|
-
app.add_middleware(AuthMiddleware, config=config
|
|
107
|
+
middleware = AuthMiddleware(app=app, config=config)
|
|
108
|
+
app.add_middleware(AuthMiddleware, config=config)
|
|
156
109
|
|
|
157
|
-
return middleware
|
|
110
|
+
return middleware
|
|
111
|
+
|
|
112
|
+
|
|
113
|
+
def get_iam_client(config: AuthConfig = None) -> ConnectAgenterraIam:
|
|
114
|
+
"""
|
|
115
|
+
获取全局IAM客户端实例
|
|
116
|
+
|
|
117
|
+
Args:
|
|
118
|
+
config: 认证配置,如果为None则从环境变量创建
|
|
119
|
+
|
|
120
|
+
Returns:
|
|
121
|
+
ConnectAgenterraIam: IAM客户端实例
|
|
122
|
+
|
|
123
|
+
Note:
|
|
124
|
+
此函数使用单例模式,确保整个应用中只有一个IAM客户端实例。
|
|
125
|
+
第一次调用时会创建实例,后续调用会返回同一个实例。
|
|
126
|
+
如果需要更新配置,可以传入新的config参数。
|
|
127
|
+
|
|
128
|
+
Example:
|
|
129
|
+
# 使用默认配置(从环境变量)
|
|
130
|
+
iam_client = get_iam_client()
|
|
131
|
+
|
|
132
|
+
# 使用自定义配置
|
|
133
|
+
config = AuthConfig(
|
|
134
|
+
agenterra_iam_host="https://iam.example.com",
|
|
135
|
+
server_name="my_server",
|
|
136
|
+
access_key="my_access_key"
|
|
137
|
+
)
|
|
138
|
+
iam_client = get_iam_client(config)
|
|
139
|
+
|
|
140
|
+
# 调用IAM服务方法
|
|
141
|
+
result = iam_client.register(
|
|
142
|
+
cred_type="username",
|
|
143
|
+
cred_value="test_user",
|
|
144
|
+
password="password123"
|
|
145
|
+
)
|
|
146
|
+
"""
|
|
147
|
+
global _global_iam_client
|
|
148
|
+
|
|
149
|
+
# 如果传入了新的配置,或者实例不存在,则创建/更新实例
|
|
150
|
+
if config is not None:
|
|
151
|
+
if _global_iam_client is None:
|
|
152
|
+
_global_iam_client = ConnectAgenterraIam(config=config)
|
|
153
|
+
else:
|
|
154
|
+
# 重新加载配置
|
|
155
|
+
_global_iam_client.reload_config(config)
|
|
156
|
+
elif _global_iam_client is None:
|
|
157
|
+
# 使用默认配置创建实例
|
|
158
|
+
default_config = AuthConfig.from_env()
|
|
159
|
+
_global_iam_client = ConnectAgenterraIam(config=default_config)
|
|
160
|
+
|
|
161
|
+
return _global_iam_client
|
skyplatform_iam/config.py
CHANGED
|
@@ -3,21 +3,18 @@ SkyPlatform IAM SDK 配置模块
|
|
|
3
3
|
"""
|
|
4
4
|
import os
|
|
5
5
|
import fnmatch
|
|
6
|
-
import
|
|
7
|
-
from
|
|
8
|
-
from pydantic import BaseModel, Field, validator
|
|
6
|
+
from typing import Optional, List
|
|
7
|
+
from pydantic import BaseModel, Field
|
|
9
8
|
from dotenv import load_dotenv
|
|
10
9
|
|
|
11
10
|
# 加载环境变量
|
|
12
11
|
load_dotenv()
|
|
13
12
|
|
|
14
|
-
logger = logging.getLogger(__name__)
|
|
15
|
-
|
|
16
13
|
|
|
17
14
|
class AuthConfig(BaseModel):
|
|
18
15
|
"""
|
|
19
16
|
认证配置类
|
|
20
|
-
|
|
17
|
+
支持环境变量和代码配置
|
|
21
18
|
"""
|
|
22
19
|
# IAM服务配置
|
|
23
20
|
agenterra_iam_host: str
|
|
@@ -33,184 +30,32 @@ class AuthConfig(BaseModel):
|
|
|
33
30
|
|
|
34
31
|
# 白名单路径配置(实例变量)
|
|
35
32
|
whitelist_paths: List[str] = Field(default_factory=list)
|
|
36
|
-
|
|
37
|
-
# 连接配置
|
|
38
|
-
timeout: int = 30
|
|
39
|
-
max_retries: int = 3
|
|
40
|
-
|
|
41
|
-
# 缓存配置
|
|
42
|
-
enable_cache: bool = True
|
|
43
|
-
cache_ttl: int = 300 # 5分钟
|
|
44
33
|
|
|
45
34
|
class Config:
|
|
46
|
-
env_prefix = "
|
|
47
|
-
validate_assignment = True
|
|
48
|
-
|
|
49
|
-
@validator('agenterra_iam_host')
|
|
50
|
-
def validate_iam_host(cls, v):
|
|
51
|
-
"""验证IAM主机地址"""
|
|
52
|
-
if not v:
|
|
53
|
-
raise ValueError("agenterra_iam_host不能为空")
|
|
54
|
-
if not (v.startswith('http://') or v.startswith('https://')):
|
|
55
|
-
raise ValueError("agenterra_iam_host必须以http://或https://开头")
|
|
56
|
-
return v.rstrip('/') # 移除末尾的斜杠
|
|
57
|
-
|
|
58
|
-
@validator('server_name')
|
|
59
|
-
def validate_server_name(cls, v):
|
|
60
|
-
"""验证服务名称"""
|
|
61
|
-
if not v or not v.strip():
|
|
62
|
-
raise ValueError("server_name不能为空")
|
|
63
|
-
return v.strip()
|
|
64
|
-
|
|
65
|
-
@validator('access_key')
|
|
66
|
-
def validate_access_key(cls, v):
|
|
67
|
-
"""验证访问密钥"""
|
|
68
|
-
if not v or not v.strip():
|
|
69
|
-
raise ValueError("access_key不能为空")
|
|
70
|
-
if len(v.strip()) < 8:
|
|
71
|
-
raise ValueError("access_key长度不能少于8个字符")
|
|
72
|
-
return v.strip()
|
|
73
|
-
|
|
74
|
-
@validator('timeout')
|
|
75
|
-
def validate_timeout(cls, v):
|
|
76
|
-
"""验证超时时间"""
|
|
77
|
-
if v <= 0:
|
|
78
|
-
raise ValueError("timeout必须大于0")
|
|
79
|
-
return v
|
|
80
|
-
|
|
81
|
-
@validator('max_retries')
|
|
82
|
-
def validate_max_retries(cls, v):
|
|
83
|
-
"""验证最大重试次数"""
|
|
84
|
-
if v < 0:
|
|
85
|
-
raise ValueError("max_retries不能小于0")
|
|
86
|
-
return v
|
|
87
|
-
|
|
88
|
-
@validator('cache_ttl')
|
|
89
|
-
def validate_cache_ttl(cls, v):
|
|
90
|
-
"""验证缓存TTL"""
|
|
91
|
-
if v <= 0:
|
|
92
|
-
raise ValueError("cache_ttl必须大于0")
|
|
93
|
-
return v
|
|
35
|
+
env_prefix = "AGENTERRA_"
|
|
94
36
|
|
|
95
37
|
@classmethod
|
|
96
|
-
def from_env(cls
|
|
38
|
+
def from_env(cls) -> "AuthConfig":
|
|
97
39
|
"""
|
|
98
40
|
从环境变量创建配置
|
|
99
|
-
|
|
100
|
-
Args:
|
|
101
|
-
prefix: 环境变量前缀,默认为SKYPLATFORM_
|
|
102
|
-
|
|
103
|
-
Returns:
|
|
104
|
-
AuthConfig: 配置实例
|
|
105
|
-
|
|
106
|
-
Raises:
|
|
107
|
-
ValueError: 配置验证失败
|
|
108
41
|
"""
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
if not value:
|
|
116
|
-
# 回退到旧前缀
|
|
117
|
-
value = os.environ.get(f"AGENTERRA_{key}", default)
|
|
118
|
-
return value
|
|
119
|
-
|
|
120
|
-
# 解析白名单路径
|
|
121
|
-
whitelist_paths_str = get_env_value('WHITELIST_PATHS', '')
|
|
122
|
-
whitelist_paths = []
|
|
123
|
-
if whitelist_paths_str:
|
|
124
|
-
whitelist_paths = [path.strip() for path in whitelist_paths_str.split(',') if path.strip()]
|
|
125
|
-
|
|
126
|
-
config = cls(
|
|
127
|
-
agenterra_iam_host=get_env_value('IAM_HOST'),
|
|
128
|
-
server_name=get_env_value('SERVER_NAME'),
|
|
129
|
-
access_key=get_env_value('ACCESS_KEY'),
|
|
130
|
-
enable_debug=get_env_value('ENABLE_DEBUG', 'false').lower() == 'true',
|
|
131
|
-
whitelist_paths=whitelist_paths,
|
|
132
|
-
timeout=int(get_env_value('TIMEOUT', '30')),
|
|
133
|
-
max_retries=int(get_env_value('MAX_RETRIES', '3')),
|
|
134
|
-
enable_cache=get_env_value('ENABLE_CACHE', 'true').lower() == 'true',
|
|
135
|
-
cache_ttl=int(get_env_value('CACHE_TTL', '300'))
|
|
42
|
+
return cls(
|
|
43
|
+
agenterra_iam_host=os.environ.get('AGENTERRA_IAM_HOST', ''),
|
|
44
|
+
server_name=os.environ.get('AGENTERRA_SERVER_NAME', ''),
|
|
45
|
+
access_key=os.environ.get('AGENTERRA_ACCESS_KEY', ''),
|
|
46
|
+
enable_debug=os.environ.get('AGENTERRA_ENABLE_DEBUG', 'false').lower() == 'true',
|
|
47
|
+
whitelist_paths=[] # 初始化空的白名单路径列表
|
|
136
48
|
)
|
|
137
|
-
|
|
138
|
-
logger.info(f"配置加载完成: server_name={config.server_name}, "
|
|
139
|
-
f"iam_host={config.agenterra_iam_host}, "
|
|
140
|
-
f"whitelist_paths_count={len(config.whitelist_paths)}")
|
|
141
|
-
|
|
142
|
-
return config
|
|
143
|
-
|
|
144
|
-
def validate_config(self) -> None:
|
|
145
|
-
"""
|
|
146
|
-
验证配置完整性
|
|
147
|
-
|
|
148
|
-
Raises:
|
|
149
|
-
ValueError: 配置验证失败
|
|
150
|
-
"""
|
|
151
|
-
logger.debug("开始验证配置完整性")
|
|
152
|
-
|
|
153
|
-
# Pydantic会自动调用validator,这里只需要检查业务逻辑
|
|
154
|
-
if not self.agenterra_iam_host:
|
|
155
|
-
raise ValueError("agenterra_iam_host不能为空")
|
|
156
|
-
if not self.server_name:
|
|
157
|
-
raise ValueError("server_name不能为空")
|
|
158
|
-
if not self.access_key:
|
|
159
|
-
raise ValueError("access_key不能为空")
|
|
160
|
-
|
|
161
|
-
logger.info("配置验证通过")
|
|
162
49
|
|
|
163
|
-
def
|
|
164
|
-
"""
|
|
165
|
-
合并配置,other的非空值会覆盖当前配置
|
|
166
|
-
|
|
167
|
-
Args:
|
|
168
|
-
other: 要合并的配置
|
|
169
|
-
|
|
170
|
-
Returns:
|
|
171
|
-
AuthConfig: 合并后的新配置实例
|
|
50
|
+
def validate_config(self) -> bool:
|
|
172
51
|
"""
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
# 获取当前配置的字典表示
|
|
176
|
-
current_dict = self.dict()
|
|
177
|
-
other_dict = other.dict()
|
|
178
|
-
|
|
179
|
-
# 合并配置
|
|
180
|
-
merged_dict = current_dict.copy()
|
|
181
|
-
for key, value in other_dict.items():
|
|
182
|
-
if key == 'whitelist_paths':
|
|
183
|
-
# 白名单路径需要合并而不是覆盖
|
|
184
|
-
merged_paths = list(set(current_dict[key] + value))
|
|
185
|
-
merged_dict[key] = merged_paths
|
|
186
|
-
elif value: # 只有非空值才覆盖
|
|
187
|
-
merged_dict[key] = value
|
|
188
|
-
|
|
189
|
-
logger.debug(f"配置合并完成,合并后的配置: {merged_dict}")
|
|
190
|
-
return AuthConfig(**merged_dict)
|
|
191
|
-
|
|
192
|
-
def to_dict(self) -> Dict[str, Any]:
|
|
193
|
-
"""
|
|
194
|
-
转换为字典格式
|
|
195
|
-
|
|
196
|
-
Returns:
|
|
197
|
-
Dict: 配置字典
|
|
198
|
-
"""
|
|
199
|
-
return self.dict()
|
|
200
|
-
|
|
201
|
-
def copy_with_updates(self, **updates) -> "AuthConfig":
|
|
202
|
-
"""
|
|
203
|
-
创建配置副本并更新指定字段
|
|
204
|
-
|
|
205
|
-
Args:
|
|
206
|
-
**updates: 要更新的字段
|
|
207
|
-
|
|
208
|
-
Returns:
|
|
209
|
-
AuthConfig: 更新后的配置副本
|
|
52
|
+
验证配置是否完整
|
|
210
53
|
"""
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
54
|
+
required_fields = ['agenterra_iam_host', 'server_name', 'access_key']
|
|
55
|
+
for field in required_fields:
|
|
56
|
+
if not getattr(self, field):
|
|
57
|
+
raise ValueError(f"配置项 {field} 不能为空")
|
|
58
|
+
return True
|
|
214
59
|
|
|
215
60
|
def _normalize_path(self, path: str) -> str:
|
|
216
61
|
"""
|