ctyun-cli 0.1.0a1__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.
- ctyun_cli/__init__.py +22 -0
- ctyun_cli/auth/__init__.py +5 -0
- ctyun_cli/auth/eop_signature.py +235 -0
- ctyun_cli/auth/signature.py +225 -0
- ctyun_cli/billing/__init__.py +8 -0
- ctyun_cli/billing/client.py +1204 -0
- ctyun_cli/billing/commands.py +701 -0
- ctyun_cli/cli/__init__.py +5 -0
- ctyun_cli/cli/main.py +1483 -0
- ctyun_cli/client.py +391 -0
- ctyun_cli/config/__init__.py +5 -0
- ctyun_cli/config/settings.py +159 -0
- ctyun_cli/ecs/__init__.py +6 -0
- ctyun_cli/ecs/client.py +475 -0
- ctyun_cli/ecs/commands.py +587 -0
- ctyun_cli/security/__init__.py +6 -0
- ctyun_cli/security/client.py +1188 -0
- ctyun_cli/security/commands.py +245 -0
- ctyun_cli/utils/__init__.py +11 -0
- ctyun_cli/utils/cache.py +176 -0
- ctyun_cli/utils/helpers.py +322 -0
- ctyun_cli-0.1.0a1.dist-info/METADATA +31 -0
- ctyun_cli-0.1.0a1.dist-info/RECORD +26 -0
- ctyun_cli-0.1.0a1.dist-info/WHEEL +5 -0
- ctyun_cli-0.1.0a1.dist-info/entry_points.txt +2 -0
- ctyun_cli-0.1.0a1.dist-info/top_level.txt +1 -0
ctyun_cli/__init__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""
|
|
2
|
+
天翼云CLI工具
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
__version__ = "1.0.0"
|
|
6
|
+
__author__ = "Your Name"
|
|
7
|
+
__email__ = "your.email@example.com"
|
|
8
|
+
|
|
9
|
+
from .client import CTYUNClient, CTYUNAPIError
|
|
10
|
+
from .config.settings import ConfigManager, config
|
|
11
|
+
|
|
12
|
+
__all__ = [
|
|
13
|
+
'CTYUNClient',
|
|
14
|
+
'CTYUNAPIError',
|
|
15
|
+
'ConfigManager',
|
|
16
|
+
'config'
|
|
17
|
+
]
|
|
18
|
+
|
|
19
|
+
def main():
|
|
20
|
+
"""CLI主入口函数"""
|
|
21
|
+
from .cli.main import cli
|
|
22
|
+
cli()
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
"""
|
|
2
|
+
天翼云EOP签名认证模块
|
|
3
|
+
实现基于EOP规范的AK/SK签名认证机制
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import hashlib
|
|
7
|
+
import hmac
|
|
8
|
+
import base64
|
|
9
|
+
import uuid
|
|
10
|
+
from datetime import datetime
|
|
11
|
+
from urllib.parse import quote
|
|
12
|
+
from typing import Dict, Any, Optional
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
class CTYUNEOPAuth:
|
|
16
|
+
"""天翼云EOP签名认证类"""
|
|
17
|
+
|
|
18
|
+
def __init__(self, access_key: str, secret_key: str):
|
|
19
|
+
"""
|
|
20
|
+
初始化认证器
|
|
21
|
+
|
|
22
|
+
Args:
|
|
23
|
+
access_key: 访问密钥(AK)
|
|
24
|
+
secret_key: 密钥(SK)
|
|
25
|
+
"""
|
|
26
|
+
self.access_key = access_key
|
|
27
|
+
self.secret_key = secret_key
|
|
28
|
+
|
|
29
|
+
def sign_request(self, method: str, url: str, query_params: Optional[Dict[str, Any]] = None,
|
|
30
|
+
body: Optional[str] = None, extra_headers: Optional[Dict[str, str]] = None) -> Dict[str, str]:
|
|
31
|
+
"""
|
|
32
|
+
对请求进行签名,返回完整的请求头
|
|
33
|
+
|
|
34
|
+
Args:
|
|
35
|
+
method: HTTP方法
|
|
36
|
+
url: 请求URL
|
|
37
|
+
query_params: 查询参数
|
|
38
|
+
body: 请求体
|
|
39
|
+
extra_headers: 额外的请求头
|
|
40
|
+
|
|
41
|
+
Returns:
|
|
42
|
+
包含签名的请求头字典
|
|
43
|
+
"""
|
|
44
|
+
# 生成必需的请求头
|
|
45
|
+
request_id = str(uuid.uuid4())
|
|
46
|
+
eop_date = self._get_eop_date()
|
|
47
|
+
|
|
48
|
+
# 构建基础请求头
|
|
49
|
+
headers = {
|
|
50
|
+
'Content-Type': 'application/json',
|
|
51
|
+
'ctyun-eop-request-id': request_id,
|
|
52
|
+
'Eop-date': eop_date
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
# 添加额外的请求头
|
|
56
|
+
if extra_headers:
|
|
57
|
+
headers.update(extra_headers)
|
|
58
|
+
|
|
59
|
+
# 步骤一:构造待签名字符串 signature
|
|
60
|
+
signature_string = self._build_signature_string(
|
|
61
|
+
headers, query_params, body
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
# 步骤二:构造动态密钥 kdate
|
|
65
|
+
kdate = self._build_kdate(eop_date)
|
|
66
|
+
|
|
67
|
+
# 步骤三:构造 signature
|
|
68
|
+
signature = self._build_signature(signature_string, kdate)
|
|
69
|
+
|
|
70
|
+
# 步骤四:构造 Eop-Authorization
|
|
71
|
+
eop_authorization = self._build_eop_authorization(signature, headers)
|
|
72
|
+
|
|
73
|
+
# 添加认证头
|
|
74
|
+
headers['Eop-Authorization'] = eop_authorization
|
|
75
|
+
|
|
76
|
+
return headers
|
|
77
|
+
|
|
78
|
+
def _get_eop_date(self) -> str:
|
|
79
|
+
"""
|
|
80
|
+
获取EOP格式的日期时间
|
|
81
|
+
格式:yyyyMMdd'T'HHmmss'Z'
|
|
82
|
+
注意:实际传时间为北京东八区UTC+8时间,TZ仅为格式,非UTC时间
|
|
83
|
+
|
|
84
|
+
Returns:
|
|
85
|
+
EOP格式的日期时间字符串
|
|
86
|
+
"""
|
|
87
|
+
# 获取当前北京时间(UTC+8)
|
|
88
|
+
now = datetime.now()
|
|
89
|
+
return now.strftime('%Y%m%dT%H%M%SZ')
|
|
90
|
+
|
|
91
|
+
def _build_signature_string(self, headers: Dict[str, str],
|
|
92
|
+
query_params: Optional[Dict[str, Any]] = None,
|
|
93
|
+
body: Optional[str] = None) -> str:
|
|
94
|
+
"""
|
|
95
|
+
构造待签名字符串
|
|
96
|
+
sigture = 需要进行签名的Header排序后的组合列表 + "\n" + encode的query + "\n" + toHex(sha256(原封的body))
|
|
97
|
+
|
|
98
|
+
Args:
|
|
99
|
+
headers: 请求头字典
|
|
100
|
+
query_params: 查询参数
|
|
101
|
+
body: 请求体
|
|
102
|
+
|
|
103
|
+
Returns:
|
|
104
|
+
待签名字符串
|
|
105
|
+
"""
|
|
106
|
+
# 1. 构造需要签名的Header排序后的组合列表
|
|
107
|
+
# EOP强制要求 ctyun-eop-request-id、eop-date 必须进行签名
|
|
108
|
+
signed_header_names = ['ctyun-eop-request-id', 'eop-date']
|
|
109
|
+
|
|
110
|
+
# 按字母顺序排序
|
|
111
|
+
signed_header_names.sort()
|
|
112
|
+
|
|
113
|
+
# 构造 header_name:header_value\n 格式
|
|
114
|
+
header_list = []
|
|
115
|
+
for header_name in signed_header_names:
|
|
116
|
+
# 注意:查找header时不区分大小写,但构造签名字符串时必须用小写
|
|
117
|
+
header_value = None
|
|
118
|
+
for k, v in headers.items():
|
|
119
|
+
if k.lower() == header_name.lower():
|
|
120
|
+
header_value = v
|
|
121
|
+
break
|
|
122
|
+
|
|
123
|
+
if header_value:
|
|
124
|
+
header_list.append(f"{header_name.lower()}:{header_value}\n")
|
|
125
|
+
|
|
126
|
+
header_string = ''.join(header_list)
|
|
127
|
+
|
|
128
|
+
# 2. 构造编码后的query字符串
|
|
129
|
+
query_string = ''
|
|
130
|
+
if query_params:
|
|
131
|
+
# 对参数按key排序
|
|
132
|
+
sorted_params = sorted(query_params.items())
|
|
133
|
+
encoded_params = []
|
|
134
|
+
for key, value in sorted_params:
|
|
135
|
+
# 值需要进行URL编码
|
|
136
|
+
encoded_value = quote(str(value), safe='')
|
|
137
|
+
encoded_params.append(f"{key}={encoded_value}")
|
|
138
|
+
query_string = '&'.join(encoded_params)
|
|
139
|
+
|
|
140
|
+
# 3. 对body进行SHA256摘要并转十六进制
|
|
141
|
+
if body is None or body == '':
|
|
142
|
+
body = ''
|
|
143
|
+
body_hash = hashlib.sha256(body.encode('utf-8')).hexdigest()
|
|
144
|
+
|
|
145
|
+
# 拼接最终的待签名字符串
|
|
146
|
+
# 格式:header_string + "\n" + query_string + "\n" + body_hash
|
|
147
|
+
signature_string = f"{header_string}\n{query_string}\n{body_hash}"
|
|
148
|
+
|
|
149
|
+
return signature_string
|
|
150
|
+
|
|
151
|
+
def _build_kdate(self, eop_date: str) -> bytes:
|
|
152
|
+
"""
|
|
153
|
+
构造动态密钥 kdate
|
|
154
|
+
|
|
155
|
+
步骤:
|
|
156
|
+
1. ktime = hmacSHA256(eop_date, sk)
|
|
157
|
+
2. kAk = hmacSHA256(ak, ktime)
|
|
158
|
+
3. kdate = hmacSHA256(eop_date的年月日值, kAk)
|
|
159
|
+
|
|
160
|
+
Args:
|
|
161
|
+
eop_date: EOP格式的日期时间
|
|
162
|
+
|
|
163
|
+
Returns:
|
|
164
|
+
动态密钥 kdate
|
|
165
|
+
"""
|
|
166
|
+
# 1. 使用eop_date作为数据,sk作为密钥,算出ktime
|
|
167
|
+
ktime = hmac.new(
|
|
168
|
+
self.secret_key.encode('utf-8'),
|
|
169
|
+
eop_date.encode('utf-8'),
|
|
170
|
+
hashlib.sha256
|
|
171
|
+
).digest()
|
|
172
|
+
|
|
173
|
+
# 2. 使用ak作为数据,ktime作为密钥,算出kAk
|
|
174
|
+
kAk = hmac.new(
|
|
175
|
+
ktime,
|
|
176
|
+
self.access_key.encode('utf-8'),
|
|
177
|
+
hashlib.sha256
|
|
178
|
+
).digest()
|
|
179
|
+
|
|
180
|
+
# 3. 使用eop_date的年月日值作为数据,kAk作为密钥,算出kdate
|
|
181
|
+
# eop_date格式:20221107T093029Z,提取年月日:20221107
|
|
182
|
+
date_part = eop_date.split('T')[0]
|
|
183
|
+
kdate = hmac.new(
|
|
184
|
+
kAk,
|
|
185
|
+
date_part.encode('utf-8'),
|
|
186
|
+
hashlib.sha256
|
|
187
|
+
).digest()
|
|
188
|
+
|
|
189
|
+
return kdate
|
|
190
|
+
|
|
191
|
+
def _build_signature(self, signature_string: str, kdate: bytes) -> str:
|
|
192
|
+
"""
|
|
193
|
+
构造 signature
|
|
194
|
+
使用kdate作为密钥、signature_string作为数据,进行HMAC-SHA256,然后Base64编码
|
|
195
|
+
|
|
196
|
+
Args:
|
|
197
|
+
signature_string: 待签名字符串
|
|
198
|
+
kdate: 动态密钥
|
|
199
|
+
|
|
200
|
+
Returns:
|
|
201
|
+
Base64编码的签名
|
|
202
|
+
"""
|
|
203
|
+
signature_bytes = hmac.new(
|
|
204
|
+
kdate,
|
|
205
|
+
signature_string.encode('utf-8'),
|
|
206
|
+
hashlib.sha256
|
|
207
|
+
).digest()
|
|
208
|
+
|
|
209
|
+
# Base64编码
|
|
210
|
+
signature = base64.b64encode(signature_bytes).decode('utf-8')
|
|
211
|
+
|
|
212
|
+
return signature
|
|
213
|
+
|
|
214
|
+
def _build_eop_authorization(self, signature: str, headers: Dict[str, str]) -> str:
|
|
215
|
+
"""
|
|
216
|
+
构造 Eop-Authorization 请求头
|
|
217
|
+
格式:ak Headers=header1;header2 Signature=xxx
|
|
218
|
+
|
|
219
|
+
Args:
|
|
220
|
+
signature: 签名
|
|
221
|
+
headers: 请求头字典
|
|
222
|
+
|
|
223
|
+
Returns:
|
|
224
|
+
Eop-Authorization 字符串
|
|
225
|
+
"""
|
|
226
|
+
# 构造 Headers 部分(需要签名的header,按字母排序,用分号分隔)
|
|
227
|
+
signed_header_names = ['ctyun-eop-request-id', 'eop-date']
|
|
228
|
+
signed_header_names.sort()
|
|
229
|
+
headers_part = ';'.join(signed_header_names)
|
|
230
|
+
|
|
231
|
+
# 构造完整的 Eop-Authorization
|
|
232
|
+
# 格式:ak Headers=xxx Signature=xxx
|
|
233
|
+
eop_authorization = f"{self.access_key} Headers={headers_part} Signature={signature}"
|
|
234
|
+
|
|
235
|
+
return eop_authorization
|
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
"""
|
|
2
|
+
天翼云API签名认证模块
|
|
3
|
+
实现AK/SK签名认证机制
|
|
4
|
+
"""
|
|
5
|
+
|
|
6
|
+
import hashlib
|
|
7
|
+
import hmac
|
|
8
|
+
import time
|
|
9
|
+
import uuid
|
|
10
|
+
from urllib.parse import quote
|
|
11
|
+
from typing import Dict, Any
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
class CTYUNAuth:
|
|
15
|
+
"""天翼云API签名认证类"""
|
|
16
|
+
|
|
17
|
+
def __init__(self, access_key: str, secret_key: str):
|
|
18
|
+
"""
|
|
19
|
+
初始化认证器
|
|
20
|
+
|
|
21
|
+
Args:
|
|
22
|
+
access_key: 访问密钥
|
|
23
|
+
secret_key: 密钥
|
|
24
|
+
"""
|
|
25
|
+
self.access_key = access_key
|
|
26
|
+
self.secret_key = secret_key
|
|
27
|
+
|
|
28
|
+
def _create_string_to_sign(self, method: str, uri: str, params: Dict[str, Any],
|
|
29
|
+
headers: Dict[str, str], timestamp: str) -> str:
|
|
30
|
+
"""
|
|
31
|
+
创建待签名字符串
|
|
32
|
+
|
|
33
|
+
Args:
|
|
34
|
+
method: HTTP方法
|
|
35
|
+
uri: 请求URI
|
|
36
|
+
params: 查询参数
|
|
37
|
+
headers: 请求头
|
|
38
|
+
timestamp: 时间戳
|
|
39
|
+
|
|
40
|
+
Returns:
|
|
41
|
+
待签名字符串
|
|
42
|
+
"""
|
|
43
|
+
# 规范化URI
|
|
44
|
+
canonical_uri = quote(uri, safe='/')
|
|
45
|
+
|
|
46
|
+
# 规范化查询字符串
|
|
47
|
+
canonical_query = self._canonicalize_query(params)
|
|
48
|
+
|
|
49
|
+
# 规范化请求头
|
|
50
|
+
canonical_headers, signed_headers = self._canonicalize_headers(headers)
|
|
51
|
+
|
|
52
|
+
# 创建哈希载荷(如果有body)
|
|
53
|
+
payload_hash = hashlib.sha256(''.encode()).hexdigest()
|
|
54
|
+
|
|
55
|
+
# 构建待签名字符串
|
|
56
|
+
string_to_sign = f"{method.upper()}\n{canonical_uri}\n{canonical_query}\n"
|
|
57
|
+
string_to_sign += f"{canonical_headers}\n{signed_headers}\n{payload_hash}"
|
|
58
|
+
|
|
59
|
+
return string_to_sign
|
|
60
|
+
|
|
61
|
+
def _canonicalize_query(self, params: Dict[str, Any]) -> str:
|
|
62
|
+
"""
|
|
63
|
+
规范化查询参数
|
|
64
|
+
|
|
65
|
+
Args:
|
|
66
|
+
params: 查询参数字典
|
|
67
|
+
|
|
68
|
+
Returns:
|
|
69
|
+
规范化的查询字符串
|
|
70
|
+
"""
|
|
71
|
+
if not params:
|
|
72
|
+
return ""
|
|
73
|
+
|
|
74
|
+
# 对参数名进行编码和排序
|
|
75
|
+
encoded_params = []
|
|
76
|
+
for key in sorted(params.keys()):
|
|
77
|
+
encoded_key = quote(str(key), safe='')
|
|
78
|
+
encoded_value = quote(str(params[key]), safe='')
|
|
79
|
+
encoded_params.append(f"{encoded_key}={encoded_value}")
|
|
80
|
+
|
|
81
|
+
return "&".join(encoded_params)
|
|
82
|
+
|
|
83
|
+
def _canonicalize_headers(self, headers: Dict[str, str]) -> tuple:
|
|
84
|
+
"""
|
|
85
|
+
规范化请求头
|
|
86
|
+
|
|
87
|
+
Args:
|
|
88
|
+
headers: 请求头字典
|
|
89
|
+
|
|
90
|
+
Returns:
|
|
91
|
+
(规范化请求头字符串, 已签名头列表)
|
|
92
|
+
"""
|
|
93
|
+
# 过滤和规范化请求头
|
|
94
|
+
canonical_headers = {}
|
|
95
|
+
signed_headers = []
|
|
96
|
+
|
|
97
|
+
# 天翼云API要求包含的头
|
|
98
|
+
required_headers = ['host', 'x-ctyun-date', 'x-ctyun-nonce']
|
|
99
|
+
|
|
100
|
+
for key, value in headers.items():
|
|
101
|
+
lower_key = key.lower().strip()
|
|
102
|
+
if lower_key in required_headers or lower_key.startswith('x-ctyun-'):
|
|
103
|
+
canonical_headers[lower_key] = value.strip()
|
|
104
|
+
signed_headers.append(lower_key)
|
|
105
|
+
|
|
106
|
+
# 排序已签名头
|
|
107
|
+
signed_headers.sort()
|
|
108
|
+
|
|
109
|
+
# 构建规范化请求头字符串
|
|
110
|
+
header_lines = []
|
|
111
|
+
for header in signed_headers:
|
|
112
|
+
header_lines.append(f"{header}:{canonical_headers[header]}")
|
|
113
|
+
|
|
114
|
+
canonical_headers_str = "\n".join(header_lines) + "\n"
|
|
115
|
+
signed_headers_str = ";".join(signed_headers)
|
|
116
|
+
|
|
117
|
+
return canonical_headers_str, signed_headers_str
|
|
118
|
+
|
|
119
|
+
def sign_request(self, method: str, uri: str, params: Dict[str, Any] = None,
|
|
120
|
+
headers: Dict[str, str] = None, body: str = None) -> Dict[str, str]:
|
|
121
|
+
"""
|
|
122
|
+
为请求添加签名
|
|
123
|
+
|
|
124
|
+
Args:
|
|
125
|
+
method: HTTP方法
|
|
126
|
+
uri: 请求URI
|
|
127
|
+
params: 查询参数
|
|
128
|
+
headers: 请求头
|
|
129
|
+
body: 请求体
|
|
130
|
+
|
|
131
|
+
Returns:
|
|
132
|
+
包含签名信息的请求头
|
|
133
|
+
"""
|
|
134
|
+
if params is None:
|
|
135
|
+
params = {}
|
|
136
|
+
if headers is None:
|
|
137
|
+
headers = {}
|
|
138
|
+
if body is None:
|
|
139
|
+
body = ""
|
|
140
|
+
|
|
141
|
+
# 生成时间戳和随机数
|
|
142
|
+
timestamp = time.strftime("%Y%m%dT%H%M%SZ", time.gmtime())
|
|
143
|
+
nonce = str(uuid.uuid4()).replace('-', '')
|
|
144
|
+
|
|
145
|
+
# 添加必要的请求头
|
|
146
|
+
headers['X-CTYUN-Date'] = timestamp
|
|
147
|
+
headers['X-CTYUN-Nonce'] = nonce
|
|
148
|
+
|
|
149
|
+
# 创建待签名字符串
|
|
150
|
+
string_to_sign = self._create_string_to_sign(method, uri, params, headers, timestamp)
|
|
151
|
+
|
|
152
|
+
# 计算签名
|
|
153
|
+
signature = self._calculate_signature(string_to_sign, timestamp)
|
|
154
|
+
|
|
155
|
+
# 添加认证头
|
|
156
|
+
auth_headers = {
|
|
157
|
+
'X-CTYUN-Signature': signature,
|
|
158
|
+
'X-CTYUN-SignedHeaders': self._get_signed_headers(headers),
|
|
159
|
+
'X-CTYUN-Date': timestamp,
|
|
160
|
+
'X-CTYUN-Nonce': nonce,
|
|
161
|
+
'X-CTYUN-Algorithm': 'CTYUN-HMAC-SHA256'
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
return auth_headers
|
|
165
|
+
|
|
166
|
+
def _calculate_signature(self, string_to_sign: str, timestamp: str) -> str:
|
|
167
|
+
"""
|
|
168
|
+
计算签名
|
|
169
|
+
|
|
170
|
+
Args:
|
|
171
|
+
string_to_sign: 待签名字符串
|
|
172
|
+
timestamp: 时间戳
|
|
173
|
+
|
|
174
|
+
Returns:
|
|
175
|
+
签名值
|
|
176
|
+
"""
|
|
177
|
+
# 创建签名密钥
|
|
178
|
+
date_key = hmac.new(
|
|
179
|
+
f'CTYUN{self.secret_key}'.encode(),
|
|
180
|
+
timestamp[:8].encode(),
|
|
181
|
+
hashlib.sha256
|
|
182
|
+
).digest()
|
|
183
|
+
|
|
184
|
+
signature_key = hmac.new(
|
|
185
|
+
date_key,
|
|
186
|
+
'ctyun_request'.encode(),
|
|
187
|
+
hashlib.sha256
|
|
188
|
+
).digest()
|
|
189
|
+
|
|
190
|
+
# 计算最终签名
|
|
191
|
+
signature = hmac.new(
|
|
192
|
+
signature_key,
|
|
193
|
+
string_to_sign.encode(),
|
|
194
|
+
hashlib.sha256
|
|
195
|
+
).hexdigest()
|
|
196
|
+
|
|
197
|
+
return signature
|
|
198
|
+
|
|
199
|
+
def _get_signed_headers(self, headers: Dict[str, str]) -> str:
|
|
200
|
+
"""
|
|
201
|
+
获取已签名头列表
|
|
202
|
+
|
|
203
|
+
Args:
|
|
204
|
+
headers: 请求头字典
|
|
205
|
+
|
|
206
|
+
Returns:
|
|
207
|
+
已签名头列表字符串
|
|
208
|
+
"""
|
|
209
|
+
signed_headers = []
|
|
210
|
+
for key in headers:
|
|
211
|
+
lower_key = key.lower()
|
|
212
|
+
if lower_key in ['host', 'x-ctyun-date', 'x-ctyun-nonce'] or lower_key.startswith('x-ctyun-'):
|
|
213
|
+
signed_headers.append(lower_key)
|
|
214
|
+
|
|
215
|
+
signed_headers.sort()
|
|
216
|
+
return ";".join(signed_headers)
|
|
217
|
+
|
|
218
|
+
def get_bearer_token(self) -> str:
|
|
219
|
+
"""
|
|
220
|
+
获取Bearer Token(简化认证方式)
|
|
221
|
+
|
|
222
|
+
Returns:
|
|
223
|
+
Bearer Token字符串
|
|
224
|
+
"""
|
|
225
|
+
return f"Bearer {self.access_key}"
|