ARMCLOUD 开发者文档中心
  • 简体中文
  • English
  • 简体中文
  • English
  • 产品介绍
  • 产品计费
  • 服务端 OpenAPI
    • 使用指南
    • 接口签名v1.0
    • 接口文档
    • OpenAPI 3.1规范(AI工具专用)
    • LLMs.txt (AI快速参考)
    • 错误码说明
    • 回调业务类型码
    • 实例列表
    • 安卓改机属性列表
    • 更新日志
  • Android端 SDK
    • 示例搭建
    • 接口说明
    • 回调函数
    • 错误码
    • 更新日志
  • Web H5端 SDK
    • 示例搭建
    • 接口说明
    • 回调函数
    • 错误码
    • 更新日志
  • Windows PC端 SDK
    • 示例搭建
    • 接口说明
    • 回调函数
    • 更新日志
  • 端侧与云机通信开发
    • AIDL接入方式
    • 系统服务API(aidl)
  • 场景解决方案
    • 类XP、LSP Hook框架
    • 传感器数据动态仿真
  • 常见问题
    • 平台基础问题
    • 存储相关问题
    • 网络连接问题
    • 应用管理问题
    • 开发集成问题
    • 性能优化问题
    • 计费相关问题
    • 技术支持
  • 相关协议
    • 云手机SDK隐私政策

概述

版本说明

此文档描述的是V1.0版本的签名验证方案。推荐新项目使用更简单的V2.0版本。

ArmCloud的服务端OpenAPI V1.0签名验证是一套完整的API鉴权方案。每次请求会对您的签名进行验证,确保您的云手机实例信息安全,请妥善保管好您账号的Access Key ID和Secret Access Key信息(后续简称AK/SK)。

开发必要参数说明

每次 API 请求的 Headers 中必须包含以下参数进行身份验证:

参数名用途和获取说明
x-date发送请求的时间戳,使用UTC时间,精确到秒如:20240301T093700Z
x-host接口访问域名固定值openapi-hk.armcloud.net
content-type资源的MIME类型, 以实际接口指定值为准,如:application/json
authorization每次请求的授权签名信息,具体生成规则请参考authorization授权签名。
如:HMAC-SHA256 Credential={AK}/{xDate}/armcloud-paas/request, SignedHeaders=content-type;host;x-content-sha256;x-date, Signature={signature}

Authorization授权签名

Authorization授权签名信息生成,为方便客户接入,官方提供SDK-JAVA、SDK-PYTHON参考模板,内部已经实现加签验证,通过调用AuthorizationUtil.authorizationCreate传入(AK,SK,请求的时间戳,固定域名,请求报文格式,请求报文信息,请求类型)会自动计算生成请求authorization授权签名。

获取账号(AK/SK)参考

AuthorizationUtil签名生成类说明

SDK-JAVA参考模板

SDK-PYTHON参考模板

获取账号(AK/SK)

在开始生成授权签名前,需要获取 Access Key ID 和 Secret Access Key,用于 API请求鉴权。
操作步骤:在ARMCloud平台登录后,用户管理 -> 账户信息 菜单下,appKey为AK, appSecret为SK。

AuthorizationUtil签名生成类说明

SDK-JAVA Authorization.authorizationCreate签名生成方法解析。
类名:AuthorizationUtil
授权签名生成方法: AuthorizationUtil.authorizationCreate(String AK, String SK, String xDate, String xHost, String contentTypeJson, Map<String,Object> requestBody, String httpMethodStr)

参数名类型示例值参数描述
AKStringxxxx账号的 Access Key ID
SKStringxxxx账号的 Secret Access Key
xDateString20240301T093700Z请求的时间戳,使用UTC时间,精确到秒
xHostStringopenapi-hk.armcloud.net固定域名
contentTypeJsonStringapplication/json请求报文格式
requestBodyMap<String,Object>new Map<String,Object>请求报文信息
httpMethodStrStringPOST请求方式:GET或POST
/**
 * 签名工具类
*/
public static class AuthorizationUtil {
    private static final String service = "armcloud-paas";               //固定服务名
    private static final String algorithm = "HMAC-SHA256";               //固定签名算法

    /**
     * authorization生成工具方法
     *
     * @param AK              账号的 Access Key ID
     * @param SK              账号的 Secret Access Key
     * @param xDate           遵循 ISO 8601 标准时间的格式:YYYYMMDD'T'HHMMSS'Z'  例如:20201103T104027Z
     * @param xHost           固定域名
     * @param contentTypeJson 请求内容格式
     * @param requestBody     请求json数据
     * @param httpMethodStr   请求方式:GET或POST
     * @return authorization
     * @throws Exception
     */
    public static String authorizationCreate(String AK, String SK, String xDate, String xHost, String contentTypeJson
            , Map<String,Object> requestBody, String httpMethodStr) throws Exception {
        byte[] body = new byte[0];
        if (requestBody != null) {
            if ("GET".equals(httpMethodStr)) {
                StringBuilder sb = new StringBuilder();
                Iterator<String> keys = requestBody.keySet().iterator();
                while (keys.hasNext()) {
                    String key = keys.next();
                    sb.append(key).append("=").append(requestBody.get(key)).append("&");
                }
                // 移除最后一个'&'字符(如果存在)
                if (sb.length() > 0) {
                    sb.setLength(sb.length() - 1);
                }
                body = sb.toString().getBytes(StandardCharsets.UTF_8);
                
            } else {
                body = MapToJsonUtil.mapToJson(requestBody).getBytes(StandardCharsets.UTF_8);
            }
        }

        final String xContentSha256 = hashSHA256(body);
        //短时间格式
        final String shortDate = xDate.substring(0, 8);
        String signedHeaders = "content-type;host;x-content-sha256;x-date";
        String canonicalStringBuilder =
                "host:" + xHost + "\n" + "x-date:" + xDate + "\n" + "content-type:" + contentTypeJson + "\n" 
                        + "signedHeaders:" + signedHeaders + "\n" + "x-content-sha256:" + xContentSha256;
        String hashCanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
        String credentialScope = shortDate + "/" + service + "/request";
        String signString = algorithm + "\n" + xDate + "\n" + credentialScope + "\n" + hashCanonicalString;
        byte[] signKey = genSigningSecretKeyV4(SK, shortDate, service);
        String signature = bytesToHex(hmacSHA256(signKey, signString));
        //authorization
        String authorization = "HMAC-SHA256 Credential=" + AK + "/" + xDate + "/" + service 
                + "/request, SignedHeaders=" + signedHeaders + ", Signature=" + signature;
        return authorization;
    }

    private static byte[] genSigningSecretKeyV4(String secretKey, String shortXDate, String service) throws Exception {
        byte[] kDate = hmacSHA256((secretKey).getBytes(), shortXDate);
        byte[] kService = hmacSHA256(kDate, service);
        return hmacSHA256(kService, "request");
    }

    private static String hashSHA256(byte[] content) throws Exception {
        try {
            MessageDigest md = MessageDigest.getInstance("SHA-256");
            return bytesToHex(md.digest(content));
        } catch (Exception e) {
            throw new Exception("Unable to compute hash while signing request: " + e.getMessage(), e);
        }
    }

    private static String bytesToHex(byte[] bytes) {
        if (bytes == null || bytes.length == 0) {
            return "";
        }
        final StringBuilder result = new StringBuilder();
        for (byte b : bytes) {
            result.append(String.format("%02x", b));
        }
        return result.toString();
    }

    private static byte[] hmacSHA256(byte[] key, String content) throws Exception {
        try {
            Mac mac = Mac.getInstance("HmacSHA256");
            mac.init(new SecretKeySpec(key, "HmacSHA256"));
            return mac.doFinal(content.getBytes());
        } catch (Exception e) {
            throw new Exception("Unable to calculate a request signature: " + e.getMessage(), e);
        }
    }
}

SDK-JAVA参考模板

下载SDK-JAVA

package net.armcloud.console.sdk.test;

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.time.ZonedDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;

/**
 * 签名测试类
 */
public class AuthorizationTest {
    //GET签名请求测试--POST签名请求测试
    public static void main(String[] args) throws Exception {
        //替换成自己账号的AK
        final String AK = "xxxxxx";
        //替换成自己账号的SK
        final String SK = "xxxx";
        //固定域名
        final String xHost = "openapi-hk.armcloud.net";
        //请求报文格式
        final String contentType = "application/json";

        //查询支持的回调类型接口
        selectList( AK, SK, xHost, contentType);
        //实例分组列表接口
        groupInfos( AK, SK, xHost, contentType);

    }

    /**
     * 查询支持的回调类型接口
     * @param AK
     * @param SK
     * @param xHost
     * @param contentType
     * @throws Exception
     */
    private static void selectList ( String AK, String SK, String xHost, String contentType) throws Exception {
        String postUrlAddress = "https://"+xHost+"/openapi/open/config/selectList";
        Map<String,Object> getRequestBody = new HashMap<>();
        get(postUrlAddress, AK, SK, xHost, contentType, getRequestBody);
    }

    /**
     * 实例分组列表接口
     * @param AK
     * @param SK
     * @param xHost
     * @param contentType
     * @throws Exception
     */
    private static void groupInfos ( String AK, String SK, String xHost, String contentType) throws Exception {
        String postUrlAddress = "https://"+xHost+"/openapi/open/group/infos";
        List<Integer> jsonArray = new ArrayList<>();
        jsonArray.add(1);
        Map<String,Object> postRequestBody = new HashMap<>();
        postRequestBody.put("padCode", "AC32010180376");
        postRequestBody.put("groupIds", jsonArray);
        post(postUrlAddress, AK, SK, xHost, contentType, postRequestBody);
    }



    /**
     * GET封装请求方法
     *
     * @param urlAddress    请求地址
     * @param AK            AK
     * @param SK            SK
     * @param xHost         固定域名
     * @param contentType   请求报文格式
     * @param requestBody   请求报文
     * @throws Exception
     */
    public static String get(String urlAddress, String AK, String SK, String xHost, String contentType
            , Map<String,Object> requestBody) throws Exception {
        LocalDateTime localDateTime = LocalDateTime.now();                                   // 当前时间
        String xDate = localDateTimeToStringUTC(localDateTime);                              // UTC时间格式
        URL url = new URL(urlAddress + getParamString(requestBody));                    // 创建URL对象
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();             // 打开连接
        connection.setRequestMethod("GET");
        connection.setConnectTimeout(5000);                                                  // 设置连接超时时间为5秒
        connection.setReadTimeout(5000);                                                     // 设置读取超时时间为5秒
        connection.setRequestProperty("content-type", contentType);                          // 设置请求头
        connection.setRequestProperty("x-host", xHost);
        connection.setRequestProperty("x-date", xDate);
        //SDK AuthorizationUtil工具类authorizationCreate方法获取认证authorization接口
        String authorization = AuthorizationUtil.authorizationCreate(AK, SK, xDate, xHost, contentType
                , requestBody, "GET");
        connection.setRequestProperty("authorization", authorization);
        try {
            InputStream in = connection.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));
            StringBuilder response = new StringBuilder();
            String line;
            while ((line = reader.readLine()) != null) {
                response.append(line);
            }
            System.out.println("GET Response Body: " + response);
            return String.valueOf(response);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            connection.disconnect();
        }
        return null;
    }



    /**
     * post封装请求方法
     *
     * @param urlAddress    请求地址
     * @param AK            AK
     * @param SK            SK
     * @param xHost         固定域名
     * @param contentType   请求报文格式
     * @param requestBody   请求报文
     * @throws Exception
     */
    public static String post(String urlAddress, String AK, String SK, String xHost, String contentType
            , Map<String,Object> requestBody) throws Exception {
        LocalDateTime localDateTime = LocalDateTime.now();                                  //当前时间
        String xDate = localDateTimeToStringUTC(localDateTime);                             //UTC时间格式
        URL url = new URL(urlAddress);                                                      // 创建URL对象
        HttpURLConnection connection = (HttpURLConnection) url.openConnection();            // 打开连接
        connection.setRequestMethod("POST");
        connection.setConnectTimeout(5000);                                                 // 设置连接超时时间为5秒
        connection.setReadTimeout(5000);                                                    // 设置读取超时时间为5秒
        connection.setRequestProperty("content-type", contentType);                         // 设置请求头
        connection.setRequestProperty("x-host", xHost);
        connection.setRequestProperty("x-date", xDate);
        connection.setDoOutput(true);                                                       // 允许写入请求体
        String authorization = AuthorizationUtil.authorizationCreate(AK, SK, xDate, xHost, contentType
                , requestBody, "POST");
        connection.setRequestProperty("authorization", authorization);
        // 将 JSON 数据转换为字节数组
        byte[] outputInBytes = MapToJsonUtil.mapToJson(requestBody).getBytes(StandardCharsets.UTF_8);
        try {
            // 获取输出流并写入数据
            OutputStream os = connection.getOutputStream();
            os.write(outputInBytes);
            Scanner scanner = new Scanner(connection.getInputStream(), StandardCharsets.UTF_8.name());
            StringBuilder response = new StringBuilder();
            while (scanner.hasNext()) {
                response.append(scanner.next());
            }
            System.out.println("POST Response Body: " + response);
            return String.valueOf(response);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            connection.disconnect();
        }
        return null;
    }

    /**
     * 时区转换
     *
     * @param localDateTime
     * @return
     */
    public static String localDateTimeToStringUTC(LocalDateTime localDateTime) {
        ZoneId zoneId = ZoneId.systemDefault();
        ZonedDateTime zonedDateTime = ZonedDateTime.of(localDateTime, zoneId);
        ZonedDateTime utcDateTime = zonedDateTime.withZoneSameInstant(ZoneId.of("UTC"));
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern("yyyyMMdd'T'HHmmss'Z'");

        return utcDateTime.format(formatter);
    }

    /**
     * get请求参数简单解析拼接
     *
     * @param map
     * @return
     */
    public static String getParamString(Map<String, Object> map) {
        StringBuilder sb = new StringBuilder();
        if (map != null) {
            sb.append("?");

            Iterator<String> keys = map.keySet().iterator();
            while (keys.hasNext()) {
                String key = keys.next();
                sb.append(key).append("=").append(map.get(key)).append("&");
            }
            // 移除最后一个'&'字符(如果存在)
            if (sb.length() > 0) {
                sb.setLength(sb.length() - 1);
            }
        }
        return sb.toString();
    }


    /**
     * map转换JsonUtil工具类
     */
    public static class MapToJsonUtil {

        public static String mapToJson(Map<String, Object> map) {
            StringBuilder jsonString = new StringBuilder();

            jsonString.append("{");

            Set<Map.Entry<String, Object>> entrySet = map.entrySet();
            boolean firstEntry = true;

            for (Map.Entry<String, Object> entry : entrySet) {
                if (!firstEntry) {
                    jsonString.append(",");
                }
                firstEntry = false;

                jsonString.append("\"");
                jsonString.append(entry.getKey());
                jsonString.append("\":");

                Object value = entry.getValue();
                if (value instanceof String) {
                    jsonString.append("\"");
                    jsonString.append(value);
                    jsonString.append("\"");
                } else if (value instanceof Number || value instanceof Boolean) {
                    jsonString.append(value);
                } else if (value instanceof Map) {
                    jsonString.append(mapToJson((Map<String, Object>) value));
                } else if (value instanceof Iterable<?>) {
                    jsonString.append(iterableToJson((Iterable<?>) value));
                } else if (value == null) {
                    jsonString.append("null");
                } else {
                    // Handle other types if necessary
                    jsonString.append("\"");
                    jsonString.append(value.toString());
                    jsonString.append("\"");
                }
            }

            jsonString.append("}");
            return jsonString.toString();
        }

        private static String iterableToJson(Iterable<?> iterable) {
            StringBuilder jsonArray = new StringBuilder();
            jsonArray.append("[");

            boolean firstElement = true;
            for (Object element : iterable) {
                if (!firstElement) {
                    jsonArray.append(",");
                }
                firstElement = false;

                if (element instanceof String) {
                    jsonArray.append("\"");
                    jsonArray.append(element);
                    jsonArray.append("\"");
                } else if (element instanceof Number || element instanceof Boolean) {
                    jsonArray.append(element);
                } else if (element instanceof Map) {
                    jsonArray.append(mapToJson((Map<String, Object>) element));
                } else if (element instanceof Iterable<?>) {
                    jsonArray.append(iterableToJson((Iterable<?>) element));
                } else if (element == null) {
                    jsonArray.append("null");
                } else {
                    // Handle other types if necessary
                    jsonArray.append("\"");
                    jsonArray.append(element.toString());
                    jsonArray.append("\"");
                }
            }

            jsonArray.append("]");
            return jsonArray.toString();
        }


    }



    /**
     * 签名工具类
     */
    public static class AuthorizationUtil {
        private static final String service = "armcloud-paas";               //固定服务名
        private static final String algorithm = "HMAC-SHA256";               //固定签名算法

        /**
         * authorization生成工具方法
         *
         * @param AK              账号的 Access Key ID
         * @param SK              账号的 Secret Access Key
         * @param xDate           遵循 ISO 8601 标准时间的格式:YYYYMMDD'T'HHMMSS'Z'  例如:20201103T104027Z
         * @param xHost           固定域名
         * @param contentTypeJson 请求内容格式
         * @param requestBody     请求json数据
         * @param httpMethodStr   请求方式:GET或POST
         * @return authorization
         * @throws Exception
         */
        public static String authorizationCreate(String AK, String SK, String xDate, String xHost
                , String contentTypeJson, Map<String,Object> requestBody, String httpMethodStr) throws Exception {
            byte[] body = new byte[0];
            if (requestBody != null) {
                if ("GET".equals(httpMethodStr)) {
                    StringBuilder sb = new StringBuilder();
                    Iterator<String> keys = requestBody.keySet().iterator();
                    while (keys.hasNext()) {
                        String key = keys.next();
                        sb.append(key).append("=").append(requestBody.get(key)).append("&");
                    }
                    // 移除最后一个'&'字符(如果存在)
                    if (sb.length() > 0) {
                        sb.setLength(sb.length() - 1);
                    }
                    body = sb.toString().getBytes(StandardCharsets.UTF_8);
                } else {
                    body = MapToJsonUtil.mapToJson(requestBody).getBytes(StandardCharsets.UTF_8);
                }
            }

            final String xContentSha256 = hashSHA256(body);
            //短时间格式
            final String shortDate = xDate.substring(0, 8);
            String signedHeaders = "content-type;host;x-content-sha256;x-date";
            String canonicalStringBuilder =
                    "host:" + xHost + "\n" + "x-date:" + xDate + "\n" + "content-type:" + contentTypeJson + "\n" 
                            + "signedHeaders:" + signedHeaders + "\n" + "x-content-sha256:" + xContentSha256;
            String hashCanonicalString = hashSHA256(canonicalStringBuilder.getBytes());
            String credentialScope = shortDate + "/" + service + "/request";
            String signString = algorithm + "\n" + xDate + "\n" + credentialScope + "\n" + hashCanonicalString;
            byte[] signKey = genSigningSecretKeyV4(SK, shortDate, service);
            String signature = bytesToHex(hmacSHA256(signKey, signString));
            //authorization
            String authorization = "HMAC-SHA256 Credential=" + AK + "/" + xDate + "/" + service 
                    + "/request, SignedHeaders=" + signedHeaders + ", Signature=" + signature;
            return authorization;
        }

        private static byte[] genSigningSecretKeyV4(String secretKey, String shortXDate
                , String service) throws Exception {
            byte[] kDate = hmacSHA256((secretKey).getBytes(), shortXDate);
            byte[] kService = hmacSHA256(kDate, service);
            return hmacSHA256(kService, "request");
        }

        private static String hashSHA256(byte[] content) throws Exception {
            try {
                MessageDigest md = MessageDigest.getInstance("SHA-256");
                return bytesToHex(md.digest(content));
            } catch (Exception e) {
                throw new Exception("Unable to compute hash while signing request: " + e.getMessage(), e);
            }
        }

        private static String bytesToHex(byte[] bytes) {
            if (bytes == null || bytes.length == 0) {
                return "";
            }
            final StringBuilder result = new StringBuilder();
            for (byte b : bytes) {
                result.append(String.format("%02x", b));
            }
            return result.toString();
        }

        private static byte[] hmacSHA256(byte[] key, String content) throws Exception {
            try {
                Mac mac = Mac.getInstance("HmacSHA256");
                mac.init(new SecretKeySpec(key, "HmacSHA256"));
                return mac.doFinal(content.getBytes());
            } catch (Exception e) {
                throw new Exception("Unable to calculate a request signature: " + e.getMessage(), e);
            }
        }
    }
}

SDK-PYTHON参考模板

下载SDK-PYTHON

import hmac
import hashlib
import json
from typing import Dict, Optional

# 定义常量
SERVICE = "armcloud-paas"
ALGORITHM = "HMAC-SHA256"
X_HOST = "openapi-hk.armcloud.net"
CONTENT_TYPE_JSON = "application/json"

def authorization_create(ak: str, sk: str, request_body: Optional[Dict], x_date: str, http_method: str) -> str:
    """
    生成 Authorization 请求头
    :param ak: Access Key
    :param sk: Secret Key
    :param request_body: 请求体(字典形式)
    :param x_date: 时间戳
    :param http_method: HTTP 方法(GET/POST)
    :return: Authorization 请求头
    """
    body = b""
    if request_body is not None:
        if http_method.upper() == "GET":
            # GET 请求时,将参数拼接为 key1=value1&key2=value2 的形式
            body = "&".join(f"{key}={value}" for key, value in request_body.items()).encode("utf-8")
        else:
            # POST 请求时,将请求体转换为 JSON 字符串
            body = map_to_json(request_body).encode("utf-8")

    x_content_sha256 = hash_sha256(body)
    short_date = x_date[:8]
    signed_headers = "content-type;host;x-content-sha256;x-date"
    canonical_string = (
        f"host:{X_HOST}\n"
        f"x-date:{x_date}\n"
        f"content-type:{CONTENT_TYPE_JSON}\n"
        f"signedHeaders:{signed_headers}\n"
        f"x-content-sha256:{x_content_sha256}"
    )
    hash_canonical_string = hash_sha256(canonical_string.encode("utf-8"))
    credential_scope = f"{short_date}/{SERVICE}/request"
    sign_string = f"{ALGORITHM}\n{x_date}\n{credential_scope}\n{hash_canonical_string}"
    sign_key = gen_signing_secret_key_v4(sk, short_date, SERVICE)
    signature = bytes_to_hex(hmac_sha256(sign_key, sign_string.encode("utf-8")))
    authorization = (
        f"{ALGORITHM} Credential={ak}/{x_date}/{SERVICE}/request, "
        f"SignedHeaders={signed_headers}, Signature={signature}"
    )
    return authorization

def gen_signing_secret_key_v4(secret_key: str, short_x_date: str, service: str) -> bytes:
    """
    生成签名密钥
    :param secret_key: 密钥
    :param short_x_date: 短日期(yyyyMMdd)
    :param service: 服务名称
    :return: 签名密钥的字节数据
    """
    k_date = hmac_sha256(secret_key.encode("utf-8"), short_x_date.encode("utf-8"))
    k_service = hmac_sha256(k_date, service.encode("utf-8"))
    return hmac_sha256(k_service, b"request")

def hash_sha256(content: bytes) -> str:
    """
    计算 SHA-256 哈希值
    :param content: 输入内容(字节数据)
    :return: 哈希值的十六进制字符串
    """
    sha256 = hashlib.sha256()
    sha256.update(content)
    return sha256.hexdigest()

def bytes_to_hex(bytes_data: bytes) -> str:
    """
    将字节数据转换为十六进制字符串
    :param bytes_data: 字节数据
    :return: 十六进制字符串
    """
    if not bytes_data:
        return ""
    return "".join(f"{byte:02x}" for byte in bytes_data)

def hmac_sha256(key: bytes, content: bytes) -> bytes:
    """
    计算 HMAC-SHA256
    :param key: 密钥(字节数据)
    :param content: 输入内容(字节数据)
    :return: HMAC 结果的字节数据
    """
    return hmac.new(key, content, hashlib.sha256).digest()

def map_to_json(map_obj):
    json_string = "{"
    first_entry = True

    for key, value in map_obj.items():
        if not first_entry:
            json_string += ","
        first_entry = False

        json_string += f'"{key}":'

        if isinstance(value, str):
            json_string += f'"{value}"'
        elif isinstance(value, (int, float, bool)):
            json_string += str(value).lower() if isinstance(value, bool) else str(value)
        elif isinstance(value, dict):
            json_string += map_to_json(value)
        elif isinstance(value, (list, tuple)):
            json_string += iterable_to_json(value)
        elif value is None:
            json_string += "null"
        else:
            json_string += f'"{str(value)}"'

    json_string += "}"
    return json_string

def iterable_to_json(iterable):
    json_string = "["
    first_item = True

    for item in iterable:
        if not first_item:
            json_string += ","
        first_item = False

        if isinstance(item, str):
            json_string += f'"{item}"'
        elif isinstance(item, (int, float, bool)):
            json_string += str(item).lower() if isinstance(item, bool) else str(item)
        elif isinstance(item, dict):
            json_string += map_to_json(item)
        elif isinstance(item, (list, tuple)):
            json_string += iterable_to_json(item)
        elif item is None:
            json_string += "null"
        else:
            json_string += f'"{str(item)}"'

    json_string += "]"
    return json_string

# 示例用法
if __name__ == "__main__":
    ak = "ak"
    sk = "sk"
    request_body = {}  # 请求体
    x_date = "20250126T230940Z"  # 时间戳
    http_method = "GET"  # HTTP 方法

    authorization = authorization_create(ak, sk, request_body, x_date, http_method)
    print("Authorization Header:", authorization)
Prev
使用指南
Next
接口文档