1.5【必看】签名加密方式

签名生成通用步骤

1将所有发送的数据设为集合A

2将集合A内非空参数值的参数按照参数名ASCII码从小到大排序(字典序),使用URL键值对的格式(即key1=value1&key2=value2…)拼接成字符串$queryString。

3按照指定规则加密算出sign值


特别注意以下重要规则:

●参数名ASCII码从小到大排序(字典序);

●如果参数的值为空不参与签名;

●参数名区分大小写;

●传送的sign参数不参与签名,将生成的签名与该sign值作校验。

●sign签名失效时间为2分钟

●open_app_sign签名失效时间为2分钟



sign签名加密算法


$sign = md5($queryString . $apiKey . base64_encode($timestamp . $apiKey . $queryString) . $nonceStr);


open_app_sign签名加密算法


$sign = md5('913702023503242914' . $openAppId . $queryString . md5($timestamp . $openAppApiKey . $queryString) . $nonceStr)


举例

假设请求参数如下:


id: 10

name: test


第一步:对参数按照key=value的格式,并按照参数名ASCII字典序排序如下:


id=10&name=test


第二步:计算签名(以sign为例):


$sign = md5("id=10&name=test" . "ucPFmeGuuTMh1t8BAsTFdztlJDKRJeGs" . base64_encode(1609754777 . "ucPFmeGuuTMh1t8BAsTFdztlJDKRJeGs" . "id=10&name=test") . 1609754777);


最终得到最终发送的数据:


cc115a7c187f061dce2b2d3c4cb1eed3


各语言请求示例


PHP请求示例


    // 当前时间戳

    $timestamp = time();

    // 商城V5 API_KEY

    $apiKey = 'V5TEST';


    // 开放应用APP_ID

    $openAppId = 100001;


    // 开放应用API_KEY

    $openAppApiKey = 'V9cfFexSl7ka79k7VM2L95XQNNxk7hAP';


    // 所有请求参数

    $params = [

        // 公共请求参数

        'api_key' => $apiKey,

        'timestamp' => $timestamp,

        'open_app_id' => $openAppId,

        'nonce_str' => StringHelper::random(32),// mLqpaOIV3igna9dPTfSKuxhZPv5lcKQS


        // 接口请求参数

        'uniacid' => 2,

    ];


    // 字典排序

    ksort($params);

    $queryString = '';

    foreach ($params as $key => $value) {

        if (is_array($value)) {

          $value = json_encode($value);

        }

      $queryString .= '&' . ($key . '=' . $value);

    }


    // 转为字符串

    $queryString = substr($queryString, 1); // api_key=V5TEST&open_app_id=100001×tamp=1609818812&uniacid=2


    // 计算签名

    $params['sign'] = md5($queryString . $apiKey . base64_encode($timestamp . $apiKey . $queryString) . $params['nonce_str']);    // 8c7c488aff05f21230053e7db204697e

    $params['open_app_sign'] = md5('913702023503242914' . $openAppId . $queryString . md5($timestamp . $openAppApiKey . $queryString) . $params['nonce_str']);    // c61e2d4d96ffb1452cc6f2603b3dbef1


    // 调用接口

    $res = HttpHelper::get('https://www.domain.com/addons/renren_shop/public/index.php?r=client/apps/openApi/shop/get-shop-id&' . http_build_query($params), [

        'headers' => [

            'shop-id' => 2,

        ]

    ]);

    var_dump($res); // string(23) "{"error":0,"shop_id":2}"


Python请求示例


import base64

import hashlib

import string

import time

from random import randint

from typing import Dict


import requests



# 随机字符串

def random_str(long=32):

    base = "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"

    result = ""

    for i in range(long):

        result += base[randint(0, len(base) - 1)]

    return result



# 封装md5

def md5(text: string):

    hl = hashlib.md5()

    hl.update(text.encode(encoding='utf-8'))

    return hl.hexdigest()



# 字典排序

def k_sort_str(d: Dict[str, str]):

    d_keys = list(d.keys())

    d_keys.sort()


    result = ""

    for k in d_keys:

        result += f"{k}={d[k]}"


        if k != d_keys[-1]:

            result += '&'


    return result



# 演示请求

def demo_request():

    # 定义当前时间戳

    timestamp = str(int(time.time()))


    # 商城V5店铺创建的API_KEY

    api_key = 'V5suyZ45GcSyIURW2kPqVpQyQqC0Vx1z'


    # 开放应用的APP_ID

    open_app_id = '100001'


    # 开放应用的APP_API_KEY

    open_app_api_key = 'V9cfFexSl7ka79k7VM2L95XQNNxk7hAP'


    # 请求接口地址

    url = 'https://yousitedomain.com/wap/3/api/apps/openApi/user/index/check-password'


    # 请求参数Dict

    request_params = {

        # 公共请求参数

        'api_key': api_key,

        'timestamp': timestamp,

        'open_app_id': open_app_id,

        'nonce_str': random_str(),


        # 业务参数

        'username': 'admin',

        'password': 'admin',

    }


    # 字典排序后转为字符串

    query_string = k_sort_str(request_params)


    # 计算sign中的base64值

    base64_str = str(timestamp) + api_key + query_string

    base64_encode_str = base64.b64encode(base64_str.encode('utf-8')).decode('utf-8')


    # 计算open_app_sign中的md5值

    md5_encode = md5(timestamp + open_app_api_key + query_string)


    # 计算签名

    request_params.update({

        'sign': md5(query_string + api_key + base64_encode_str + request_params['nonce_str']),

        'open_app_sign': md5(

            '913702023503242914' + open_app_id + query_string + md5_encode + request_params['nonce_str']),

    })


    # 执行请求

    response = requests.request('POST', url, headers={}, data=request_params, files=[])


    # 返回信息

    print(response.text)



# 执行demo

demo_request()


Golang请求示例


package main


import (

    "bytes"

    "crypto/md5"

    "encoding/base64"

    "encoding/hex"

    "fmt"

    "io/ioutil"

    "math/rand"

    "mime/multipart"

    "net/http"

    "sort"

    "strconv"

    "strings"

    "time"

)


func main() {


    // 商城V5店铺创建的API_KEY

    apiKey := "V5suyZ45GcSyIURW2kPqVpQyQqC0Vx1z"


    // 开放应用的APP_ID

    openAppID := "100001"


    // 开放应用的APP_API_KEY

    openAppApiKey := "Aojtd3ZwUdfuoNu6joJ6DuZ96O6FID9T"


     # 请求接口地址

    url := "https://yousitedomain.com/wap/3/api/apps/openApi/user/index/check-password"


    // 定义当前时间戳

    timestamp := timestampStr()


    // 请求参数

    requestParams := map[string]string{

        // 公用请求参数

        "api_key":     apiKey,

        "timestamp":   timestamp,

        "open_app_id": openAppID,

        "nonce_str":   randomStr(32),


        // 业务请求参数

        "username": "admin",

        "password": "admin",

    }


    // 字典排序后转为字符串

    queryString := kSort2Str(requestParams)


    // 计算sign中的base64值

    bas64Str := base64.StdEncoding.EncodeToString([]byte(timestamp + apiKey + queryString))


    // 计算open_app_sign中的md5值

    md5Encode := md5Str(timestamp + openAppApiKey + queryString)


    // 计算签名

    requestParams["sign"] = md5Str(queryString + apiKey + bas64Str + requestParams["nonce_str"])

    requestParams["open_app_sign"] = md5Str("913702023503242914" + openAppID + queryString + md5Encode + requestParams["nonce_str"])


    // 以下开始请求!!! 可以换成自己的httpClient


    res, err := request(url, requestParams)

    if err != nil {

        panic(err)

    }


    // 打印返回结果

    fmt.Println(res)

}


// 执行请求(POST)

// url 请求的地址

// params 请求的参数

func request(url string, params map[string]string) (resStr string, err error) {


    payload := &bytes.Buffer{}

    writer := multipart.NewWriter(payload)


    // 追加请求参数

    for k, v := range params {

        _ = writer.WriteField(k, v)

    }


    err = writer.Close()

    if err != nil {

        return

    }


    client := &http.Client{}

    req, err := http.NewRequest("POST", url, payload)


    if err != nil {

        return

    }

    req.Header.Set("Content-Type", writer.FormDataContentType())

    res, err := client.Do(req)

    if err != nil {

        return

    }

    defer func() {

        _ = res.Body.Close()

    }()


    body, err := ioutil.ReadAll(res.Body)

    if err != nil {

        return

    }


    resStr = string(body)

    return

}


// 获取当前时间戳(转为string)

func timestampStr() string {

    now := time.Now().Unix()

    return strconv.FormatInt(now, 10)

}


// 字典排序

// params 要排序的参数

func kSort2Str(params map[string]string) string {


    // ksort

    var keys []string

    for k, _ := range params {

        keys = append(keys, k)

    }

    sort.Strings(keys)


    var str string


    // 拼接

    for _, k := range keys {

        if k == "sign" {

            continue

        }

        str = str + k + "=" + params[k] + "&"

    }


    return str[0 : len(str)-1]

}


// 计算字符串的Md5

// string 要计算的字符串

func md5Str(string string) string {

    md := md5.New()

    md.Write([]byte(string))

    cSign := hex.EncodeToString(md.Sum(nil))

    return cSign

}


// 随机字符串

// length 要随机的长度

func randomStr(length int) string {


    // 字符

    chars := "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"


    sLen := strings.Count(chars, "") - 1

    str := ""


    for length > 0 {

        random := rand.Intn(sLen)

        str += string(chars[random])

        length--

    }


    return str

}


Nodejs请求示例



const request = require('request')

const md5 = require('md5-node')


/**

 * base64加密

 * @param content 要加密的内容

 * @returns {string}

 * @author likexin

 */

function base64Encode(content) {

  return Buffer.from(content).toString('base64')

}


/**

 * 随机生成字符串

 * @param len 生成的长度

 * @returns {string}

 * @author likexin

 */

function randomStr(len = 32) {


  // 字符

  const chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"


  // 字符长度

  const sLen = chars.length


  // 待生成的字符串

  let str = ''


  for (let i = 0; i < len; i++) {

    str += chars.charAt(Math.floor(Math.random() * sLen))

  }


  return str

}


/**

 * 字典排序后转为字符串

 * @param params

 * @returns {string}

 * @author likexin

 */

function kSort2Str(params) {

  let keys = Object.keys(params)

  keys.sort()

  const kLen = keys.length


  let str = ''


  keys.forEach((k) => {

    str += k + "=" + params[k]


    if (k !== keys[kLen - 1]) {

      str += '&'

    }

  })


  return str

}


/**

 * 演示请求

 * @author likexin

 */

function demoRequest() {

  // 商城V5店铺创建的API_KEY

  const apiKey = 'V5szyZ35GcSyIURW2kPqVpQ1QqC0Vxzx'


  // 开放应用的APP_ID

  const openAppId = '900030'


  // 开放应用的APP_API_KEY

  const openAppApiKey = 'Aojtd3Zwwdfuo2u6joJ6DuZ96O6FID31'


  // 接口地址

  const apiUrl = 'https://yoursitedomain.com/wap/1223/api/apps/openApi/user/index/check-password'


  // 定义当前时间戳

  const timestamp = Math.floor(Date.now() / 1000);


  // 请求参数

  let requestParams = {

    // 公用请求参数

    'api_key': apiKey,

    'timestamp': timestamp,

    'open_app_id': openAppId,

    'nonce_str': randomStr(32),


    // 业务请求参数

    'username': 'admin',

    'password': 'admin',

  }


  // 字典排序后转为字符串

  const queryString = kSort2Str(requestParams)


  // 计算签名

  requestParams['sign'] = md5(queryString + apiKey + base64Encode(timestamp + apiKey + queryString) + requestParams['nonce_str']);

  requestParams['open_app_sign'] = md5('913702023503242914' + openAppId + queryString + md5(timestamp + openAppApiKey + queryString) + requestParams['nonce_str']);


  // 下面开始请求,可以换成自己的httpClient

  request({

    'method': 'POST',

    'url': apiUrl,

    'headers': {},

    formData: requestParams

  }, (error, response) => {

    if (error) {

      console.error(error)

      return

    }


    // 返回结果

    console.log(response.body);

  })

}


// 执行demo

demoRequest()


Java请求示例



package cn.likexin.demo;


import okhttp3.*;

import org.springframework.boot.autoconfigure.SpringBootApplication;

import org.springframework.util.Base64Utils;

import org.springframework.util.DigestUtils;


import java.io.IOException;

import java.util.Date;

import java.util.HashMap;

import java.util.Random;

import java.util.TreeMap;


@SpringBootApplication

    public class DemoApplication {


        /**

        * 程序入口

        * @param args 参数

        * @throws IOException

        * @author likexin

        */

        public static void main(String[] args) throws IOException {

            // SpringApplication.run(DemoApplication.class, args);


            // 商城V5店铺创建的API_KEY

            String apiKey = "V5suyZ45GcSyIURW2kPqVpQyQqC0Vx1z";


            // 开放应用的APP_ID

            String openAppID = "100001";


            // 开放应用的APP_API_KEY

            String openAppApiKey = "Aojtd3ZwUdfuoNu6joJ6DuZ96O6FID9T";


            // 请求接口地址

            String url = "https://yousitedomain.com/wap/3/api/apps/openApi/user/index/check-password";


            // 定义当前时间戳

            String timestamp = timestampStr();


            // 定义请求参数为HashMap

            HashMaprequestParams = new HashMap<>();


            // 公用请求参数

            requestParams.put("api_key", apiKey);

            requestParams.put("timestamp", timestamp);

            requestParams.put("open_app_id", openAppID);

            requestParams.put("nonce_str", randomStr(32));


            // 业务参数

            requestParams.put("username", "admin");

            requestParams.put("password", "admin");


            // 字典排序后转为字符串

            String queryString = kSort2Str(requestParams);


            // 计算sign中的base64值

            String bas64Str = base64Str(timestamp + apiKey + queryString);


            // 计算open_app_sign中的md5值

            String md5Encode = md5Str(timestamp + openAppApiKey + queryString);


            // 计算签名

            requestParams.put("sign", md5Str(queryString + apiKey + bas64Str + requestParams.get("nonce_str")));

            requestParams.put("open_app_sign", md5Str("913702023503242914" + openAppID + queryString + md5Encode + requestParams.get("nonce_str")));



            // 以下开始请求!!! 可以换成自己的httpClient

            OkHttpClient client = new OkHttpClient().newBuilder().build();


            MultipartBody.Builder builder = new MultipartBody.Builder().setType(MultipartBody.FORM);

            for (String key : requestParams.keySet()) {

                builder.addFormDataPart(key, requestParams.get(key));

            }


            RequestBody body = builder.build();


            Request request = new Request.Builder()

                .url(url)

                .method("POST", body)

                .build();

            Response response = client.newCall(request).execute();


            // 打印接口返回结果

            System.out.println(response.body().string());


        }


        /**

        * 获取当前时间戳

        *

        * @return 当前时间戳(秒)

        * @author likexin

        */

        private static String timestampStr() {

            return String.valueOf(new Date().getTime() / 1000);

        }


        /**

        * 获取随机字符串

        *

        * @param length 长度

        * @return String

        * @author likexin

        */

        private static String randomStr(int length) {

            String str = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";

            Random random = new Random();

            StringBuffer sb = new StringBuffer();

            for (int i = 0; i < length; i++) {

            int number = random.nextInt(62);

            sb.append(str.charAt(number));

            }

            return sb.toString();

}


        /**

        * 排序并且转为String

        *

        * @param params 所有参数

        * @return 拼接后的字符串

        * @author likexin

        */

        private static String kSort2Str(HashMapparams) {

            TreeMapparamTreeMap = new TreeMap<>(params);

            

            StringBuilder str = new StringBuilder();

            

            for (String key : paramTreeMap.keySet()) {

            str.append(key).append("=").append(paramTreeMap.get(key)).append("&");

            }

            

            return str.substring(0, str.length() - 1);

        }


        /**

        * MD5

        *

        * @param str 要MD5的字符串

        * @return MD5后的字符串

        * @author likexin

        */

        private static String md5Str(String str) {

        return DigestUtils.md5DigestAsHex(str.getBytes());

        }


        /**

        * Base64encode

        *

        * @param str 要encode的字符串

        * @return encoded的字符串

        * @author likexin

        */

        private static String base64Str(String str) {

        return Base64Utils.encodeToString(str.getBytes());

        }


}



Powered by www.sdsdsoft.com-© 2001-2024 微助 备案号鄂ICP备16018351号-2      微助学院 | 微助商城| 微助互动

联系我们
8年品牌,专注移动电商
扫码立即咨询
027-63376568
QQ:1010751194