API签名算法,go后端生成签名和验证签名 2个月前

这次主要的实践内容是 API接口签名设计,以下是一些关键的步骤: 给前端分配一个 secretKey ,

以下是对这段代码的解读及教程:

一、代码功能概述 这段代码定义了一个名为getDataTest的函数,其主要功能是生成特定参数的签名,然后使用这些参数发送请求,并在请求成功后打印响应结果。签名的生成过程包括对给定参数进行排序、拼接特定字符串并使用 MD5 算法进行哈希计算。

前端使用第三方的库

import crypto from 'crypto-js';

二、代码详细解读

const getDataTest = () => {
  const secretKey = 'helloWorld';
  const params = {
    v: '1.0',
    page: "1",
    pageSize: "10",
  };

  // 获取当前时间戳
  const timestamp = "1724383084118";

  // 对参数进行 key 排序
  const sortedParams = {};
  Object.keys(params)
    .sort()
    .forEach(key => {
      sortedParams[key] = params[key];
    });

  // 生成签名
  const signatureData = Object.keys(sortedParams)
    .map(key => `${key}${sortedParams[key]}`)
    .join('') + `secretKey${secretKey}timestamp${timestamp}`;
  // 使用 MD5 算法进行哈希计算
  const hashedString = crypto.MD5(signatureData).toString();

  // 发送请求,(可以自己封装Axios)
  getData({
    ...sortedParams,
    timestamp,
    sign: hashedString,
  }
  ).then((res) => {
    console.log(res);
  });

}

3.调整参数和密钥 根据实际需求,可以调整params对象中的参数值以及secretKey的值。同时,如果时间戳不是固定的,可以使用动态生成时间戳的方法替代硬编码的时间戳。

4.处理请求结果 根据实际业务需求,对请求成功后的响应结果进行进一步的处理。在代码中,目前只是简单地打印了响应结果,可以根据具体情况进行更复杂的操作。

请注意,代码中的时间戳和密钥等可能需要根据实际情况进行动态生成和管理,以确保安全性和有效性。同时,确保getData函数的正确性和稳定性,以便成功发送请求并处理响应。

5.后端部分,以下是对这段代码的解读及使用教程:

package main

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "sort"
    "strconv"
    "strings"
    "time"

    "github.com/gin-gonic/gin"
)

// generateSignature 根据给定参数和密钥生成签名
func generateSignature(params map[string]interface{}, secretKey string, timestamp int64) string {
    // 移除签名和时间戳参数
    delete(params, "sign")
    delete(params, "timestamp")

    // 获取参数的键列表并排序
    keys := make([]string, 0, len(params))
    for k := range params {
        keys = append(keys, k)
    }
    sort.Strings(keys)

    var signatureBuilder strings.Builder
    // 拼接参数键值和密钥、时间戳
    for _, key := range keys {
        signatureBuilder.WriteString(key)
        signatureBuilder.WriteString(params[key].(string))
    }
    signatureBuilder.WriteString("secretKey" + secretKey)
    signatureBuilder.WriteString("timestamp" + strconv.FormatInt(timestamp, 10))

    fmt.Printf("|generateSignature: %s\n", signatureBuilder.String())
    // 计算 MD5 哈希并返回十六进制编码的签名
    hash := md5.Sum([]byte(signatureBuilder.String()))
    return hex.EncodeToString(hash[:])
}

// ValidateSignature 封装签名验证逻辑
func ValidateSignature(c *gin.Context, secretKey string) bool {
    receivedParams := make(map[string]interface{})
    if err := c.Bind(&receivedParams); err != nil {
        c.JSON(400, gin.H{"error": "Invalid request"})
        return false
    }

    receivedTimestamp, err := strconv.ParseInt(receivedParams["timestamp"].(string), 10, 64)
    if err != nil {
        c.JSON(400, gin.H{"error": "Invalid timestamp"})
        return false
    }

    currentTime := time.Now().UnixNano() / int64(time.Millisecond)
    if currentTime-receivedTimestamp > 120000 { // 允许 2 分钟的时间差
        c.JSON(400, gin.H{"error": "Timestamp expired"})
        return false
    }

    receivedSignature := receivedParams["sign"]

    expectedSignature := generateSignature(receivedParams, secretKey, receivedTimestamp)
    fmt.Print(expectedSignature)
    // 验证签名是否一致
    if receivedSignature != expectedSignature {
        return false
    } else {
        return true
    }
}

func main() {
    r := gin.Default()
    r.GET("/order", func(c *gin.Context) {
        secretKey := "helloWorld"
        if !ValidateSignature(c, secretKey) {
            return
        }

        c.JSON(200, gin.H{"message": "Request is valid", "secretKey": secretKey})
    })
    r.Run() // 监听并在 0.0.0.0:8080 上启动服务
}

客户端在发送请求时,需要在请求参数中包含正确的时间戳和签名。签名可以按照以下步骤生成: 确定请求参数,不包括sign和timestamp参数。 对参数的键进行排序。 将排序后的键值对拼接起来,再拼接上密钥和时间戳。 使用 MD5 算法计算哈希值,并将其转换为十六进制编码作为签名。

请注意,在实际应用中,可以根据具体需求对时间戳的有效期、密钥的生成和管理等进行进一步的优化和调整,以提高安全性和稳定性。

image
小白
我们奔跑在曲折的时空,过去与未来发生交折。
1
发布数
1
关注者
713
累计阅读

热门教程文档

Spring Cloud
8小节
Djiango
17小节
Objective-C
29小节
C++
73小节
Python
76小节