主题
开发者接入指南-登录鉴权
云从公有云平台使用OAuth2.0授权调用开放API,开发者调用开放能力前,需要先使用申请的App Key、App Secret获取令牌access_token,然后携带access_token调用开放能力。
能力调用域名:https://api-ai.cloudwalk.com
- 注意: 请额外依赖下述JAR包:
4.1. Token获取
接口说明:
用于获取访问云从公有云平台开放能力的身份令牌,为保障系统安全性,开发者需要安全管理令牌。令牌有过期时间,过期前可以重复使用,令牌的过期维护需要调用方自己处理。
调用流程:

请求 URL:
/sso/oauth/token请求参数
method: POST
请求头参数:"Content-Type":"application/x-www-form-urlencoded"
表单参数:
| 参数名称 | 必填 | 数据类型 | 长度 | 参数描述 |
|---|---|---|---|---|
| clientId | 是 | String | 1-32 | 客户端ID,对应创建应用生成的App Key |
| clientSecret | 是 | String | 1-255 | 加密后的客户端密钥,使用创建应用生成的App Secret和SM2公钥进行加密 |
| scope | 是 | String | 1-32 | 权限范围,固定值为scope |
请求示例:
Content-Type: application/x-www-form-urlencoded
scope:scope
clientId:xxxxxxxx
clientSecret:xxxxxxxxxx响应参数
| 参数名称 | 数据类型 | 长度 | 参数描述 |
|---|---|---|---|
| access_token | String | 1-32 | 访问令牌 |
| token_type | String | 1-32 | 令牌类型 bearer |
| expires_in | Long | 1-32 | 令牌有效期,单位:秒,默认12小时 |
| scope | String | 1-32 | 授权范围 返回scope |
响应示例:
{
"access_token": "xxxxxxxxxxxxxx",
"token_type": "bearer",
"expires_in": 170932,
"scope": "scope"
}示例代码(JAVA)
java
package cloudwalk.kaleidoscope;
import cn.hutool.crypto.ECKeyUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import cn.hutool.http.HttpUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import org.bouncycastle.crypto.engines.SM2Engine;
import java.util.HashMap;
import java.util.Map;
public class tokenTest {
/**
* sm2-sm4加密算法的应用详情中的App Key和App Secret、SM2公钥
*/
public static String APP_KEY = "xxxxxxxx";
public static String APP_SECRET = "xxxxxxxxxxxxxxxx";
public static String SM2_PUB = "xxxxxxxxxxxxxxxxxxxxxxxxxxx";
/**
* 调用地址
*/
public static String HTTP_ADDRESS = "https://api-ai.cloudwalk.com";
/**
* Token管理请求路径
*/
private static final String TOKEN_URL = HTTP_ADDRESS + "/sso/oauth/token";
public static void main(String[] args) throws Exception {
getToken();
}
private static String sm2Encrypt(String plain) {
SM2 sm2 = new SM2(null, ECKeyUtil.toSm2PublicParams("04".concat(SM2_PUB)));
sm2.setMode(SM2Engine.Mode.C1C2C3);
return sm2.encryptHex(plain, KeyType.PublicKey);
}
private static String getToken() {
Map<String, String> paramMap = new HashMap<>(2);
paramMap.put("clientId", APP_KEY);
paramMap.put("clientSecret", sm2Encrypt(APP_SECRET));
HttpRequest request = HttpUtil.createPost(HTTP_TEST_URL + uri);
request.form(paramMap);
String result = request.execute().body();
System.out.println(result);
JSONObject object = JSON.parseObject(result);
return object.getString("access_token");
}
}示例代码(GO语言)
go
package main
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"io"
"math/big"
"net/http"
"net/url"
"strings"
"github.com/tjfoc/gmsm/sm2"
)
const (
// sm2-sm4加密算法的应用详情中的App Key和App Secret、SM2公钥
APP_KEY = "xxxxxxxx"
APP_SECRET = "xxxxxxxxxxxxxxxx"
SM2_PUB = "xxxxxxxxxxxxxxxxxxxxxxxxxxx"
// 调用地址
HTTP_ADDRESS = "https://api-ai.cloudwalk.com"
// Token管理请求路径
TOKEN_URL = HTTP_ADDRESS + "/sso/oauth/token"
)
func main() {
getToken()
}
// sm2Encrypt 使用SM2公钥加密明文,返回十六进制字符串
// 对应Java: sm2.encryptHex(plain, KeyType.PublicKey) with Mode.C1C2C3
func sm2Encrypt(plain string) (string, error) {
// Java代码中使用 "04" + SM2_PUB 作为未压缩公钥
pubKeyHex := "04" + SM2_PUB
pubBytes, err := hex.DecodeString(pubKeyHex)
if err != nil {
return "", fmt.Errorf("decode public key hex failed: %v", err)
}
// 未压缩公钥格式: 04 + X(32字节) + Y(32字节) = 65字节
if len(pubBytes) != 65 || pubBytes[0] != 0x04 {
return "", fmt.Errorf("invalid uncompressed public key format, expected 65 bytes with 0x04 prefix")
}
// 解析 X 和 Y 坐标
curve := sm2.P256Sm2()
x := new(big.Int).SetBytes(pubBytes[1:33])
y := new(big.Int).SetBytes(pubBytes[33:65])
// 创建公钥
pubKey := &sm2.PublicKey{
Curve: curve,
X: x,
Y: y,
}
// 使用 C1C2C3 模式加密(与 Java Hutool 的 SM2Engine.Mode.C1C2C3 一致)
cipher, err := sm2.Encrypt(pubKey, []byte(plain), rand.Reader, sm2.C1C2C3)
if err != nil {
return "", fmt.Errorf("sm2 encrypt failed: %v", err)
}
return hex.EncodeToString(cipher), nil
}
// getToken 获取访问令牌
func getToken() (string, error) {
// 使用SM2加密APP_SECRET
encryptedSecret, err := sm2Encrypt(APP_SECRET)
if err != nil {
return "", fmt.Errorf("encrypt APP_SECRET failed: %v", err)
}
// 准备表单参数
formData := url.Values{}
formData.Set("clientId", APP_KEY)
formData.Set("clientSecret", encryptedSecret)
// 创建POST请求
req, err := http.NewRequest(http.MethodPost, TOKEN_URL, strings.NewReader(formData.Encode()))
if err != nil {
return "", fmt.Errorf("create request failed: %v", err)
}
// 设置请求头
req.Header.Set("Content-Type", "application/x-www-form-urlencoded")
// 发送请求
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", fmt.Errorf("send request failed: %v", err)
}
defer resp.Body.Close()
// 读取响应
respBytes, err := io.ReadAll(resp.Body)
if err != nil {
return "", fmt.Errorf("read response failed: %v", err)
}
// 打印原始响应
fmt.Println(string(respBytes))
// 解析JSON响应
var result map[string]interface{}
if err := json.Unmarshal(respBytes, &result); err != nil {
return "", fmt.Errorf("parse json failed: %v, response: %s", err, string(respBytes))
}
// 提取access_token
accessToken, ok := result["access_token"].(string)
if !ok {
return "", fmt.Errorf("access_token not found in response, response: %s", string(respBytes))
}
return accessToken, nil
}内容输出:
{"access_token":"xxxxxxxx","token_type":"bearer","expires_in":172342,"scope":"scope"}