签名机制
📌
签名大体过程如下:
以访问凭证令牌举例:
1) appid=557ADoER&sign_method=hmac_sha256×tamp=16854380449999 + 秘钥
示例:
2) md5:
appid=557ADoER&sign_method=md5×tamp=16854380449999 + 秘钥
示例:
Java示例
import org.apache.commons.codec.digest.HmacAlgorithms;
import org.apache.commons.codec.digest.HmacUtils;
import org.springframework.util.DigestUtils;
md5加密
String sign = DigestUtils.md5DigestAsHex((appid=557ADoER&sign_method=md5×tamp=16854380449999密钥).getBytes())
HMAC_SHA_256 加密
String sign = new HmacUtils(HmacAlgorithms.HMAC_SHA_256, 密钥).hmacHex(appid=557ADoER&sign_method=hmac_sha256×tamp=16854380449999)
C#示例
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Security.Cryptography;
using System.Text;
namespace SignUtilsDemo
{
public class SignUtils
{
private const string APPID = "appid";
private const string TIMESTAMP = "timestamp";
private const string SIGNATURE = "sign";
private const string SIGN_METHOD = "sign_method";
private const string SIGN_TYPE = "sign_type";
private const string NONCE = "nonce";
private Dictionary<string, Func<string, string, string>> _handleMap = new Dictionary<string, Func<string, string, string>>()
{
{ "md5", GetMd5Sign },
{ "hmac_sha256", GetHmacSha256Sign }
};
public string SupportSignMethod => string.Join(",", _handleMap.Keys);
private static string GetMd5Sign(string paramStr, string secret)
{
using (var md5 = MD5.Create())
{
var bytes = md5.ComputeHash(Encoding.UTF8.GetBytes(paramStr + secret));
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
}
private static string GetHmacSha256Sign(string paramStr, string secret)
{
using (var hmacSha256 = new HMACSHA256(Encoding.UTF8.GetBytes(secret)))
{
var bytes = hmacSha256.ComputeHash(Encoding.UTF8.GetBytes(paramStr));
return BitConverter.ToString(bytes).Replace("-", "").ToLower();
}
}
private string GenerateSign(string body, Dictionary<string, string> parameters, string appSecret, Func<string, string, string> signMethodHandle)
{
var sortedParams = parameters.OrderBy(p => p.Key, StringComparer.Ordinal);
var paramStr = string.Join("&", sortedParams.Select(p => $"{p.Key}={p.Value}"));
var sb = new StringBuilder();
if (!string.IsNullOrWhiteSpace(body))
{
sb.Append($"body={body}&");
}
sb.Append(paramStr);
var str = sb.ToString();
return signMethodHandle(str, appSecret);
}
public string Sign(Dictionary<string, string> parameters, string signMethodType, string appSecret, object bodyObject)
{
if (!_handleMap.TryGetValue(signMethodType, out var signMethodHandle))
{
throw new ArgumentException($"Unsupported sign method: {signMethodType}");
}
var body = JsonConvert.SerializeObject(bodyObject);
var newSign = GenerateSign(body, parameters, appSecret, signMethodHandle);
return newSign;
}
}
}
F#示例
open System
open System.Collections.Generic
open System.Security.Cryptography
open System.Text
open Newtonsoft.Json
type SignUtils() =
let mutable support_sign_method = "md5,hmac_sha256"
let get_md5_sign (param_str: string) (secret: string) =
let data = param_str + secret
use md5 = MD5.Create()
md5.ComputeHash(Encoding.UTF8.GetBytes(data)) |> Array.map (fun b -> b.ToString("x2")) |> String.concat ""
let get_hmac_sha256_sign (param_str: string) (secret: string) =
let data = Encoding.UTF8.GetBytes(param_str)
let key = Encoding.UTF8.GetBytes(secret)
use sha256 = new HMACSHA256(key)
sha256.ComputeHash(data) |> Array.map (fun b -> b.ToString("x2")) |> String.concat ""
let generate_sign (body: string) (parameters: IDictionary<string, string>) (app_secret: string) (sign_method_handle: Func<string, string, string>) =
let keys = parameters.Keys |> Seq.sort
let param_str =
match body with
| "" -> ""
| _ -> "body=" + body + "&"
parameters
|> Seq.fold (fun acc k -> acc + k + "=" + parameters.[k] + "&") param_str
|> fun s -> s + app_secret
sign_method_handle s app_secret
member this.Sign (parameters: IDictionary<string, string>) (sign_method_type: string) (app_secret: string) (body_object: obj) =
let sign_method_handle =
match sign_method_type with
| "md5" -> this.get_md5_sign
| "hmac_sha256" -> this.get_hmac_sha256_sign
| _ -> failwith "Unsupported sign method: " + sign_method_type
let body = JsonConvert.SerializeObject(body_object)
let timestamp = int (DateTime.UtcNow - DateTime(1970, 1, 1)).TotalSeconds
parameters.[APPID_KEY] <- "your_app_id"
parameters.[TIMESTAMP_KEY] <- string timestamp
parameters.[NONCE_KEY] <- "your_nonce"
parameters.[SIGN_METHOD_KEY] <- sign_method_type
parameters.[SIGN_TYPE_KEY] <- "MD5"
this.generate_sign body parameters app_secret sign_method_handle
member this.GetSupportSignMethod() = support_sign_method
member this.SetSupportSignMethod(s: string) = support_sign_method <- s
Golang示例
package signutils
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha256"
"encoding/hex"
"encoding/json"
"fmt"
"sort"
"strings"
"time"
)
const (
appIDKey = "appid"
timestampKey = "timestamp"
signatureKey = "sign"
signMethodKey = "sign_method"
signTypeKey = "sign_type"
nonceKey = "nonce"
)
type SignUtils struct {
SupportSignMethod string
}
type SignMethodHandle func(string, string) string
func NewSignUtils() *SignUtils {
return &SignUtils{
SupportSignMethod: "md5,hmac_sha256",
}
}
func (su *SignUtils) GetMd5Sign(paramStr, secret string) string {
h := md5.New()
h.Write([]byte(paramStr + secret))
return hex.EncodeToString(h.Sum(nil))
}
func (su *SignUtils) GetHmacSha256Sign(paramStr, secret string) string {
h := hmac.New(sha256.New, []byte(secret))
h.Write([]byte(paramStr))
return hex.EncodeToString(h.Sum(nil))
}
func (su *SignUtils) GenerateSign(body string, parameters map[string]string, appSecret string, signMethodHandle SignMethodHandle) string {
keys := make([]string, 0, len(parameters))
for k := range parameters {
keys = append(keys, k)
}
sort.Strings(keys)
sb := strings.Builder{}
if len(body) > 0 {
sb.WriteString(fmt.Sprintf("body=%s&", body))
}
for _, k := range keys {
sb.WriteString(fmt.Sprintf("%s=%s&", k, parameters[k]))
}
str := sb.String()
return signMethodHandle(str, appSecret)
}
func (su *SignUtils) Sign(parameters map[string]string, signMethodType, appSecret string, bodyObject interface{}) string {
handleMap := map[string]SignMethodHandle{
"md5": su.GetMd5Sign,
"hmac_sha256": su.GetHmacSha256Sign,
}
signMethodHandle, ok := handleMap[signMethodType]
if !ok {
panic(fmt.Sprintf("Unsupported sign method: %s", signMethodType))
}
bodyBytes, _ := json.Marshal(bodyObject)
body := string(bodyBytes)
timestamp := time.Now().Unix()
parameters[appIDKey] = "your_app_id"
parameters[timestampKey] = fmt.Sprintf("%d", timestamp)
parameters[nonceKey] = "your_nonce"
parameters[signMethodKey] = signMethodType
parameters[signTypeKey] = "MD5"
newSign := su.GenerateSign(body, parameters, appSecret, signMethodHandle)
return newSign
}
PHP示例
NodeJS示例
Rust示例
C++示例
#include <iostream>
#include <string>
#include <vector>
#include <map>
#include <algorithm>
#include <openssl/md5.h>
#include <openssl/hmac.h>
#include <openssl/evp.h>
#include <openssl/bio.h>
#include <openssl/buffer.h>
#include <chrono>
#include <ctime>
#include <nlohmann/json.hpp>
using json = nlohmann::json;
const std::string APPID_KEY = "appid";
const std::string TIMESTAMP_KEY = "timestamp";
const std::string SIGNATURE_KEY = "sign";
const std::string SIGN_METHOD_KEY = "sign_method";
const std::string SIGN_TYPE_KEY = "sign_type";
const std::string NONCE_KEY = "nonce";
class SignUtils {
private:
std::string support_sign_method = "md5,hmac_sha256";
std::string get_md5_sign(std::string param_str, std::string secret) {
unsigned char md[MD5_DIGEST_LENGTH];
std::string data = param_str + secret;
MD5(reinterpret_cast<const unsigned char*>(data.c_str()), data.size(), md);
std::stringstream ss;
for (int i = 0; i < MD5_DIGEST_LENGTH; i++) {
ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(md[i]);
}
return ss.str();
}
std::string get_hmac_sha256_sign(std::string param_str, std::string secret) {
unsigned int result_len;
unsigned char result[EVP_MAX_MD_SIZE];
HMAC(EVP_sha256(), reinterpret_cast<const unsigned char*>(secret.c_str()), secret.size(), reinterpret_cast<const unsigned char*>(param_str.c_str()), param_str.size(), result, &result_len);
std::stringstream ss;
for (unsigned int i = 0; i < result_len; i++) {
ss << std::hex << std::setfill('0') << std::setw(2) << static_cast<unsigned int>(result[i]);
}
return ss.str();
}
std::string generate_sign(std::string body, std::map<std::string, std::string> parameters, std::string app_secret, std::function<std::string(std::string, std::string)> sign_method_handle) {
std::vector<std::string> keys;
for (const auto& kv : parameters) {
keys.push_back(kv.first);
}
std::sort(keys.begin(), keys.end());
std::stringstream ss;
for (const auto& key : keys) {
ss << key << "=" << parameters[key] << "&";
}
ss << app_secret;
std::string param_str = ss.str();
return sign_method_handle(param_str, app_secret);
}
public:
std::string sign(std::map<std::string, std::string>& parameters, std::string sign_method_type, std::string app_secret, json body_object) {
std::function<std::string(std::string, std::string)> sign_method_handle;
if (sign_method_type == "md5") {
sign_method_handle = [this](std::string param_str, std::string secret) { return this->get_md5_sign(param_str, secret); };
} else if (sign_method_type == "hmac_sha256") {
sign_method_handle = [this](std::string param_str, std::string secret) { return this->get_hmac_sha256_sign(param_str, secret); };
} else {
throw std::invalid_argument("Unsupported sign method: " + sign_method_type);
}
auto body = body_object.dump();
auto timestamp = std::chrono::duration_cast<std::chrono::seconds>(std::chrono::system_clock::now().time_since_epoch()).count();
parameters[APPID_KEY] = "your_app_id";
parameters[TIMESTAMP_KEY] = std::to_string(timestamp);
parameters[NONCE_KEY] = "your_nonce";
parameters[SIGN_METHOD_KEY] = sign_method_type;
parameters[SIGN_TYPE_KEY] = "MD5";
auto new_sign = generate_sign(body, parameters, app_secret, sign_method_handle);
return new_sign;
}
std::string get_support_sign_method() {
return support_sign_method;
}
void set_support_sign_method(std::string support_sign_method) {
this->support_sign_method = support_sign_method;
}
};
Lua示例
Python示例
Swift示例
Kotlin示例
调用示例
1.
参数 | 名称 |
---|---|
appid | AppKey |
sign_method | 签名算法, 目前支持的签名算法有两种:MD5(sign_method=md5),HMAC_SHA256(sign_method=hmac-sha256) |
timestamp | 时间戳,默认2分钟内有效 |
sign | 签名内容 |
2.
签名示例:
签名方式:hmac-sha256
明文:appid=PltO3gTJ×tamp=1685590016123
密钥(appsecret):627ab1bb0c3095e75b4a864edb060db499fa2863
签名结果(sign):da42d239f9114218d3ac3cd221b9b6376ccdbbe6ef4abb8c07f9236ad9d3c151
方法:new HmacUtils(HmacAlgorithms.HMAC_SHA_256, 密钥).hmacHex(明文)
签名方式:md5
明文:appid=PltO3gTJ&sign_method=md5×tamp=1685597220000
密钥(appsecret):627ab1bb0c3095e75b4a864edb060db499fa2863
签名结果(sign):8c9be0645d8afc6406fd32a319a80c0c
方法: DigestUtils.md5DigestAsHex((明文 + 密钥).getBytes())
修改于 2024-04-19 07:50:07