认证授权
获取访问凭证(推荐)
1.接口说明
接口路径:/api/user/v3/tokens
请求方式:POST
请求数据类型:application/json
接口描述:区域资源用户认证,认证成功后返回各区域ID、名称以及区域接口访问凭证token
备注:
1、每次访问为用户可用的计算区域分别颁发一个token,此token为访问其他服务接口的凭证,在后续接口请求中均需要携带。每个区域的token配合获取授权区域接口返回的URL地址,携带token调用作业、文件、容器等接口。
2、若用户有某个区域的访问权限,但账户状态为停用状态时,则返回区域信息,但token为null,无法调用后续接口,需充值后才能正常调用接口。
3、clusterId为0,clusterName为ac的区域信息为平台自身token,仅支持调用平台层面接口,如认证授权和用户资源及资源。
2.请求消息
参数说明: Headers:
| 名称 | 类型 | 必填 | 描述 | 示例 |
|---|---|---|---|---|
| user | string | 是 | 用户名 | test |
| accessKey | string | 是 | AK | 934e4dd887264b63a797ccb27f86048f |
| signature | string | 是 | 签名 | b86b8b86c98ce... |
| timestamp | string | 是 | 时间戳 | 1764597591 |
3.签名算法
1. 获取授权码
在个人中心,点击【访问控制】,生成授权码下载并保存。 accessKey(AK)与 secretKey(SK)对应下载文件中的 Accesskey、Secretkey 列。
2. 签名生成流程:
- 构造请求参数:
- 请求参数包括 accessKey(AK)、timestamp(当前秒级时间戳)、user(平台用户名)。
- 构造JSON字符串如下,作为待签名的消息。
json
{"accessKey":"85f96a42b13f4d2c8b760d2775bbcca8","timestamp":"1764597591","user":"bob"}- 生成签名:
- 使用 HMAC-SHA256 算法对 JSON 字符串进行签名。
- 使用 secretKey(SK)密钥,计算消息的签名。
- 结果是一个 16 进制字符串,即签名。
3. 签名算法示例:
Java代码示例
java
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.nio.charset.StandardCharsets;
public class AkSkSignatureUtil {
private static final String ALGORITHM = "HmacSHA256";
/**
* 构造待签名 JSON 字符串并生成签名
*
* @param accessKey AK
* @param timestamp 时间戳(秒,字符串)
* @param user 用户名
* @param secretKey SK
* @return 签名(小写十六进制)
*/
public static String sign(String accessKey, String timestamp, String user, String secretKey) {
// 按字典序拼接 JSON:accessKey, timestamp, user
StringBuilder jsonBuilder = new StringBuilder();
jsonBuilder.append("{\"accessKey\":\"")
.append(escapeJson(accessKey))
.append("\",\"timestamp\":\"")
.append(escapeJson(timestamp))
.append("\",\"user\":\"")
.append(escapeJson(user))
.append("\"}");
String dataToSign = jsonBuilder.toString();
return hmacSha256(secretKey, dataToSign);
}
private static String escapeJson(String input) {
if (input == null) return "";
return input.replace("\\", "\\\\").replace("\"", "\\\"");
}
private static String hmacSha256(String secret, String message) {
try {
Mac mac = Mac.getInstance(ALGORITHM);
SecretKeySpec spec = new SecretKeySpec(secret.getBytes(StandardCharsets.UTF_8), ALGORITHM);
mac.init(spec);
byte[] hash = mac.doFinal(message.getBytes(StandardCharsets.UTF_8));
return bytesToHex(hash);
} catch (Exception e) {
throw new RuntimeException("Failed to generate HMAC-SHA256 signature", e);
}
}
private static String bytesToHex(byte[] bytes) {
StringBuilder sb = new StringBuilder();
for (byte b : bytes) {
String hex = Integer.toHexString(b & 0xFF);
if (hex.length() == 1) {
sb.append('0');
}
sb.append(hex);
}
return sb.toString().toLowerCase();
}
// ========================
// 示例使用
// ========================
public static void main(String[] args) {
String accessKey = "your_access_key_here"; // 替换为真实的 AK
String timestamp = "1764597591"; // 当前时间戳
String user = "bob"; // 用户名
String secretKey = "your_secret_key_here"; // 替换为真实的 SK
String signature = sign(accessKey, timestamp, user, secretKey);
System.out.println("Generated Signature: " + signature);
}
}Python代码示例
python
import hmac
import hashlib
def escape_json(s: str) -> str:
if s is None:
return ""
return s.replace("\\", "\\\\").replace('"', '\\"')
def sign(access_key: str, timestamp: str, user: str, secret_key: str) -> str:
"""
构造待签名 JSON 字符串并生成 HMAC-SHA256 签名
Args:
access_key: AK
timestamp: 时间戳(秒,字符串)
user: 用户名
secret_key: SK
Returns:
签名(小写十六进制字符串)
"""
# 按字典序拼接 JSON:accessKey, timestamp, user
escaped_ak = escape_json(access_key)
escaped_ts = escape_json(timestamp)
escaped_user = escape_json(user)
data_to_sign = f'{{"accessKey":"{escaped_ak}","timestamp":"{escaped_ts}","user":"{escaped_user}"}}'
# 计算 HMAC-SHA256 签名
signature = hmac.new(
key=secret_key.encode('utf-8'),
msg=data_to_sign.encode('utf-8'),
digestmod=hashlib.sha256
).hexdigest()
return signature.lower()
# ========================
# 示例使用
# ========================
if __name__ == "__main__":
access_key = "your_access_key_here" # 替换为真实的 AK
timestamp = "1764597591" # 时间戳(秒)
user = "bob" # 用户名
secret_key = "your_secret_key_here" # 替换为真实的 SK
signature = sign(access_key, timestamp, user, secret_key)
print("Generated Signature:", signature)4.请求示例
CURL请求示例
shell
curl --location --request POST 'https://scnet-demo.accloud.cn/api/user/v3/tokens' \
--header 'accessKey: 934e4dd887264b63a797ccb27f86048f' \
--header 'signature: b2cfe85a136af1e3ff18898e' \
--header 'user: test' \
--header 'timestamp: 1764597591'Java请求示例
java
import okhttp3.*;
public class GetUserTokenDemo {
public static final String URL = "https://scnet-demo.accloud.cn/api/user/v3/tokens";
public static final String USER = "test";
public static final String ACCESS_KEY = "934e4dd887264b63a797ccb27f86048f";
public static final String SIGNATURE = "6048ce7ba15c2af2e8cec12991ec13cf";
public static final String TIMESTAMP = "1764597591";
public static void main(String[] args) throws Exception {
OkHttpClient client = new OkHttpClient().newBuilder()
.build();
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, "");
Request request = new Request.Builder()
.url(URL)
.method("POST", body)
.addHeader("user", USER)
.addHeader("accessKey", ACCESS_KEY)
.addHeader("signature", SIGNATURE)
.addHeader("timestamp", TIMESTAMP)
.build();
Response response = client.newCall(request).execute();
System.out.println(response.body().string());
}
}Python请求示例
python
import requests
import json
url = "https://scnet-demo.accloud.cn/api/user/v3/tokens"
payload = {}
headers = {
"user": "test",
"accessKey": "934e4dd887264b63a797ccb27f86048f",
"signature": "6048ce7ba15c2af2e8cec12991ec13cf",
"timestamp": "1764597591"
}
response = requests.request("POST", url, headers=headers, data=payload)
print(response.text)5.响应消息
返回参数:
| 名称 | 类型 | 描述 | 示例 |
|---|---|---|---|
| msg | string | 信息 | 0 |
| code | string | 状态码 | success |
| data | array | 区域信息列表 | |
| clusterName | string | 区域名称 | OpenAPI计算中心 |
| clusterId | string | 区域ID | 11112 |
| token | string | 区域token | eyJhbGciOiJIUzI1NiIsInR5cC... |
返回示例:
json
{
"msg":"success",
"code":"0",
"data":[
{
"clusterName":"OpenAPI计算中心",
"clusterId":"11112",
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb21wdXRlVXNlciI6Imhhb3dqIiwiYWNjb3VudFN0YXR1cyI6Ik93ZSIsImNyZWF0b3IiOiJhYyIsInJvbGUiOiIxIiwiZXhwaXJlVGltZSI6IjE2MzQyODY2MDMwNjYiLCJjbHVzdGVySWQiOiIxMTEyNiIsImludm9rZXIiOiJ4eHl5YWdlYSIsInVzZXIiOiJoYW93aiJ9.mprLWvhNLNK1YuQVLewnJ7AG10K644g38xAt-xO3GwY"
},
{
"clusterName":"test中心",
"clusterId":"111131",
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb21wdXRlVXNlciI6Imhhb3dqIiwiYWNjb3VudFN0YXR1cyI6IkRpc2FibGUiLCJjcmVhdG9yIjoiYWMiLCJyb2xlIjoiMSIsImV4cGlyZVRpbWUiOiIxNjM0Mjg2NjAzMDgwIiwiY2x1c3RlcklkIjoiMTExMTMxIiwiaW52b2tlciI6Inh4eXlhZ2VhIiwidXNlciI6Imhhb3dqIn0.zKhISUwMa2Y16SH0LOBvfSJN_ctvABPUHMsjHj7vJfA"
},
{
"clusterName":"ac",
"clusterId":"0",
"token":"eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJjb21wdXRlVXNlciI6Imhhb3dqIiwiYWNjb3VudFN0YXR1cyI6Ik93ZSIsImNyZWF0b3IiOiJhYyIsInJvbGUiOiIxIiwiZXhwaXJlVGltZSI6IjE2MzQyODY2MDMwODciLCJjbHVzdGVySWQiOiIxMTEyNSIsImludm9rZXIiOiJ4eHl5YWdlYSIsInVzZXIiOiJoYW93aiJ9.bIGdJpUoCZaKSJB71o_ZKUBzpcdW4_y54afU_arRDIQ"
}
]
}6.错误码
| 错误码 | 说明 |
|---|---|
| 10001 | 内部错误 |
| 10003 | 参数不全 |
| 10004 | 参数无效 |
| 10008 | 权限不足 |
| 10009 | 校验失败 |
| 0 | 接口调用成功 |