You need to enable JavaScript to run this app.
导航
GMP ak/sk 鉴权计算说明
最近更新时间:2025.03.04 14:13:59首次发布时间:2025.03.04 14:13:59
我的收藏
有用
有用
无用
无用

说明

ak/sk获取方式:GMP首页--》项目管理--》Openapi鉴权--》创建ak/sk

Image

概述

鉴权算法输入

  1. 原始请求体,一个字符串
  2. 请求路径、请求HTTP方法
  3. 请求query参数,一个map,按key排好序(因为服务端进行验证计算的时候也会排序)
  4. 客户端自定义的签名超时时间(单位:秒)
  5. ak / sk

鉴权算法流程

(详见鉴权码计算脚本)

  1. 使用ak、当前时间戳(秒)、过期时间 拼接得到一个 sign_key_info
  2. 使用sk对sign_key_info进行sha256_hmac计算得到sign_key
  3. 使用请求HTTP方法、请求url路径、请求url的query参数、原始请求体组装出算法输入text
  4. 使用sign_key对text进行sha256_hmac就算得到sign_result
  5. 将sign_key_info与sign_result拼接得到authorization
  6. 将authorization放到请求头部的Authorization字段

鉴权码计算脚本

python

import time
import hashlib
import hmac
import json

def _do_sign(ak, sk, expiration, text):
    print("text = ", text)
    sign_key_info = 'ak-v1/%s/%d/%d' % (ak, time.time(), expiration)
    print("sign_key_info = ", sign_key_info)
    sign_key = _sha256_hmac(sk, sign_key_info)
    print("sign_key = ", sign_key)
    sign_result = _sha256_hmac(sign_key, text)
    return '%s/%s' % (sign_key_info, sign_result)

def _canonical_method(method):    
    return "HTTPMethod:" + method

def _canonical_url(url):
    return "CanonicalURI:" + url

def _canonical_param(params):
    res = 'CanonicalQueryString:'
    if not params:
        return res
    kvs = []
    for k, v in params.items():
        kvs.append('{}={}'.format(k, v))
    return res + '&'.join(kvs)

def _canonical_body(body):
    res = "CanonicalBody:"
    if not body:
        return res
    return res + body

def _sha256_hmac(key, data):
    return hmac.new(str.encode(key, 'utf-8'), str.encode(data, 'utf-8'), hashlib.sha256).hexdigest()

"""
    :param ak:accessKey
    :param sk:secretKey
    :param expiration_seconds:过期时间,单位秒
    :param method:方法,GET, POST, PUT
    :param uri_path:请求的path,非完整的url
    :param params:请求参数
    :param body:请求的json体
    :return:
    """
def sign(ak, sk, expiration_seconds, method, uri_path, params, body):
    canonical_method = _canonical_method(method)
    canonical_url = _canonical_url(uri_path)
    canonical_param = _canonical_param(params)
    canonical_body = _canonical_body(body)
    text = '{}\n{}\n{}\n{}'.format(canonical_method, canonical_url, canonical_param, canonical_body)
    return _do_sign(ak, sk, expiration_seconds, text)

ak = "1-8256"
sk = "JZBMEclYMcQRajsweQr4Pokh7zegTb4tAc5n0qmvTh1nEQx"
expiration_seconds = 300
method = "POST"
# 请求的path,非完整的url
uri = "/gmp/openapi/v1/resource_space/getResourceSpaceDefaultMaterial"
params = {}

request_body = {
    "app_id": 1,
    "data_ver": 0
}

auth = sign(ak, sk, expiration_seconds, method, uri, params, json.dumps(request_body))
print(auth)

    

JS 示例代码

const crypto = require('crypto');
function hash(ak, sk, expiration_seconds, method, path, params, body) {
    const timestamp = (+new Date() / 1000).toFixed(0);
    const signKeyInfo = `ak-v1/${ak}/${timestamp}/${expiration_seconds}`;
    const signKey = sha256HMAC(sk, signKeyInfo);
    const data = canonicalRequest(method, path, params, body);
    const signResult = sha256HMAC(signKey, data);
    return signKeyInfo + '/' + signResult;
}

function sha256HMAC(sk, data) {
    const hmac = crypto.createHmac('sha256', sk)
    return hmac.update(data).digest('hex')
}

function canonicalRequest(method, url, params, body) {
    let cm = canonicalMethod(method);
    let cu = canonicalUrl(url);
    let cp = canonicalParam(params);
    let cb = canonicalBody(body);
    return cm + '\n' + cu + '\n' + cp + '\n' + cb;
}

function canonicalMethod(method) {
    return 'HTTPMethod:' + method;
}

function canonicalUrl(url) {
    return 'CanonicalURI:' + url;
}

function canonicalParam(params) {
    let res = 'CanonicalQueryString:'
    if (!params) {
        return res;
    }
    return res + queryString(params);
}

function canonicalBody(body) {
    res = "CanonicalBody:"
    if (!body){
        return res;
    }
    return res + body;
}

Java

AuthUtil.java

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Map;

public class AuthUtils {

        /**
     * 
     * @param ak accessKey
     * @param sk secretKey
     * @param expirationSeconds 过期时间,单位秒
     * @param method 方法,GET, POST, PUT
     * @param uriPath 请求的path,非完整的url
     * @param params 请求参数
     * @param body 请求的json体
     * @return
     */
    public static String sign(String ak, String sk, int expirationSeconds, String method, String uriPath, Map<String, String> params, String body) {
        String cm = canonicalMethod(method);
        String cu = canonicalUrl(uriPath);
        String cp = canonicalParam(params);
        String cb = canonicalBody(body);
        String text = cm + "\n" + cu + "\n" + cp + "\n" + cb;
        return doSign(ak, sk, expirationSeconds, text);
    }

    private static String canonicalMethod(String method) {
        return "HTTPMethod:" + method;
    }

    private static String canonicalUrl(String url) {
        return "CanonicalURI:" + url;
    }

    private static String canonicalParam(Map<String, String> params) {
        String res = "CanonicalQueryString:";
        if (params == null || params.isEmpty()) {
            return res;
        }
        for (String key : params.keySet()) {
            res += formatKeyValue(key, params.get(key)) + "&";
        }
        return res.substring(0, res.length() - 1);
    }

    private static String formatKeyValue(String key, String value) {
        return key + "=" + value;
    }

    private static String canonicalBody(String body) {
        String res = "CanonicalBody:";
        if (body == null) {
            return res;
        } else {
            return res + body;
        }
    }

    private static String doSign(String ak, String sk, int expiration, String text) {
        String signKeyInfo = "ak-v1/" + ak + "/" + (int) (System.currentTimeMillis() / 1000) + "/" + expiration;
        String signKey = sha256Hmac(signKeyInfo, sk);
        String signResult = sha256Hmac(text, signKey);
        return signKeyInfo + "/" + signResult;
    }


    private static String sha256Hmac(String message, String secret) {
        String hash = "";
        try {
            Mac sha256_HMAC = Mac.getInstance("HmacSHA256");
            SecretKeySpec secret_key = new SecretKeySpec(secret.getBytes(), "HmacSHA256");
            sha256_HMAC.init(secret_key);
            byte[] bytes = sha256_HMAC.doFinal(message.getBytes());
            hash = byteArrayToHexString(bytes);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        } catch (InvalidKeyException e) {
            e.printStackTrace();
        }
        return hash;
    }

    private static String byteArrayToHexString(byte[] b) {
        StringBuilder hs = new StringBuilder();
        String stmp;
        for (int n = 0; b != null && n < b.length; n++) {
            stmp = Integer.toHexString(b[n] & 0XFF);
            if (stmp.length() == 1) {
                hs.append('0');
            }
            hs.append(stmp);
        }
        return hs.toString().toLowerCase();
    }
}

调用

import java.util.LinkedHashMap;
import java.util.Map;

public class AuthGenDemo {

    //分配的accessKey和secretKey
    private static String accessKey = "****";
    private static String secretKey = "****";
    // 单位秒
    private static Integer expirationSeconds = 300;

    public static void main(String[] args) {
        String method = "POST";
        // 请求的path,非完整的url
        String uri = "/dataprofile/openapi/v1/751/users/185";
        Map<String, String> exampleQueryParams = new LinkedHashMap<>();
        exampleQueryParams.put("set_once", "true");
        String exampleQueryBodyJson = "{\"name\":\"name\",\"value\":\"zhangsan\"}";

        String authorization = AuthUtils.sign(accessKey, secretKey, expirationSeconds,
                method, uri, exampleQueryParams, exampleQueryBodyJson);
        System.out.println("authorization: " + authorization);
    }
}

用于计算的Body请务必与最终发送的body完全一致

测试使用鉴权脚本

在鉴权脚本中替换内容并计算签名:

  • ak/sk:参照文档最上面获取
  • method:请求方法,需要大写
  • url:请求路径,注意最前面有“/”
  • params:请求参数建值对,按key排序:
  • request_body:请求体

运行脚本

将CanonicalBody:后的内容替换到postman的请求体输入框中(注意前后不要有空格/换行):

在Header中添加字段Authorization并添加上图框2中的内容:

发送请求即可。

  • 如果原请求没有请求体,则postman和脚本中都只保留一对大括号便可:
  • 如果原请求没有请求参数,则脚本中保留大括号:

postman测试脚本
  • 脚本中红色的aksk改为测试环境的ak\sk
var CryptoJS = require('crypto-js');
console.log("bodyData = " + pm.request.url);

// 获取当前请求的body数据
var u=pm.request.url.toString()
var p = u.split('?')[1]
var bodyData = pm.request.body.toString();

const paramArr = p.match(/([^&=]+)=?([^&]*)/g); 
const paramsData = new Map();
paramArr.map((param) => {
const [key, val] = param.split("=");
    paramsData.set(key,val);
})

console.log(paramsData);
// 打印到控制台
// console.log("paramsData = " + paramsData);
console.log("bodyData = " + bodyData);

const ak = "5er18yxAa4f";
const sk = "4514514515";
const sign_method = pm.request.method;


let paths = JSON.parse(JSON.stringify(pm.request.url.path))
if (pm.request.url.path[0].startsWith('fedev-')){
    paths.splice(0, 1)
}
let path = '/' + paths.join('/')


let sign = hash(ak,sk,3600,sign_method,path,paramsData,bodyData)
pm.request.headers.add({key: 'Authorization', value: sign})

// const crypto = require('crypto');
function hash(ak, sk, expiration_seconds, method, path, params, body) {
    const timestamp = (+new Date() / 1000).toFixed(0);
    const signKeyInfo = `ak-v1/${ak}/${timestamp}/${expiration_seconds}`;
    const signKey = sha256HMAC(sk, signKeyInfo);
    const data = canonicalRequest(method, path, params, body);
    const signResult = sha256HMAC(signKey, data);
    return signKeyInfo + '/' + signResult;
}

function sha256HMAC(sk, data) {
    // const hmac = CryptoJS.SHA256(sk)
    return CryptoJS.HmacSHA256(data,sk).toString(CryptoJS.enc.Hex)
}

function canonicalRequest(method, url, params, body) {
    let cm = canonicalMethod(method);
    let cu = canonicalUrl(url);
    let cp = canonicalParam(params);
    let cb = canonicalBody(body);
    return cm + '\n' + cu + '\n' + cp + '\n' + cb;
}

function canonicalMethod(method) {
    return 'HTTPMethod:' + method;
}

function canonicalUrl(url) {
    return 'CanonicalURI:' + url;
}

function canonicalParam(params) {
    let res = 'CanonicalQueryString:'
    if (!params) {
        return res;
    }
    return res + queryString(params);
}

function queryString(params) {
    var arrayObj=Array.from(params);
    console.log(arrayObj)

    arrayObj.sort(function(a,b){return a[0].localeCompare(b[0])});
    var res =''
    for (var [key, value] of arrayObj) {
        res=res+key + '=' + value+'&';
            console.log("res"+res)
    }
    if (res!=''){
        res= res.substr(0,res.length-1)
    }
    console.log("res"+res)
    return res;
}
function canonicalBody(body) {
    let res = "CanonicalBody:"
    if (!body){
        return res;
    }
    return res + body;
}