Skip to content

前端接口请求签名指南

这是什么?

想象一下,就像你在快递单上签名一样,我们需要给每个接口请求添加一个"数字签名"。这个签名可以:

  • ✅ 证明请求确实来自合法用户
  • ✅ 确保数据在传输过程中没有被篡改
  • ✅ 防止黑客伪造请求

这个功能特别适合那些不需要登录就能访问的接口。

📝 如何实现签名?

第一步:准备签名工具

首先,我们需要创建一个sign.js文件来处理签名:

javascript
// 1. 引入必要的工具
import config from '@/config/index.js'
import CryptoJS from 'crypto-js'  // 记得先安装这个加密库

// 2. 处理签名参数
export function getSignAllMap(path, json, signJson) {
    // 把复杂的数据结构转换成简单的键值对
    if (null != json) {
        let type = Object.prototype.toString.call(json);
        if (type == "[object Object]") {
            // 处理对象
            for (let key in json) {
                let value = json[key];
                if (null != value && undefined != value) {
                    let type2 = Object.prototype.toString.call(value);
                    let path2 = key;
                    if (path) {
                        path2 = path + "." + key;
                    }
                    if (type2 == "[object Object]") {
                        getSignAllMap(path2, value, signJson)
                    } else if (type2 == "[object Array]") {
                        for (let i = 0; i < value.length; i++) {
                            getSignAllMap(path2 + "[" + i + "]", value[i], signJson)
                        }
                    } else {
                        signJson[path2] = value;
                    }
                }
            }
        } else if (type == "[object Array]") {
            // 处理数组
            for (let i = 0; i < json.length; i++) {
                getSignAllMap(path + "[" + i + "]", json[i], signJson)
            }
        } else {
            signJson[path] = json;
        }
    }
}

// 3. 生成签名字符串
export function getSignStr(json) {
    let signJson = {};
    getSignAllMap("", json, signJson)

    // 获取所有参数名并排序
    let keys = Object.keys(signJson).sort();

    // 拼接参数
    let signStr = keys.map(key => 
        key + "=" + signJson[key]
    ).join("&");

    return signStr;
}

// 4. 生成随机字符串(防止重放攻击)
function guid() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = Math.random() * 16 | 0,
            v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}

// 5. 获取最终签名
export function getSign(url, data) {
    // 复制原始数据
    let sinData = JSON.parse(JSON.stringify(data))
    
    // 添加签名必要信息
    let randomStr = guid();                // 随机字符串
    let timestamp = +new Date();           // 当前时间戳
    sinData.appId = config.appId;          // 应用ID
    sinData.appSecret = config.appSecret;  // 应用密钥
    sinData.randomStr = randomStr;         // 随机字符串
    sinData.timestamp = timestamp;         // 时间戳
    
    // 生成签名字符串并计算签名
    let signStr = getSignStr(sinData);
    console.log('签名字符串:', signStr);
    let sign = CryptoJS.SHA1(signStr).toString();
    
    // 返回带签名的URL
    return `${url}?appId=${config.appId}&randomStr=${randomStr}&timestamp=${timestamp}&sign=${sign}`
}

第二步:配置应用信息

创建config.js文件,设置应用信息:

javascript
export default {
    appId: 'test',                                    // 你的应用ID
    appSecret: '11e1ebfd58254b84a6f3c1d81d27a562',   // 你的应用密钥
}

第三步:在代码中使用

javascript
// 1. 引入签名工具
import { getSign } from './sign.js'

// 2. 准备要发送的数据
let data = {
    "accountNo": "admin",
    "password": "123456"
};

// 3. 获取带签名的URL
let signUrl = getSign(url, data);

// 4. 发送请求
axios.post(signUrl, data)
    .then(response => {
        console.log('请求成功:', response);
    })
    .catch(error => {
        console.error('请求失败:', error);
    });

第四步:配置服务器

在服务器配置文件中添加签名验证规则:

yaml
wueasy:
  gateway:
    filter:
      merchant: 
        enabled: true  # 启用签名验证
        items:
        - app-id: test  # 应用ID
          app-secret: 11e1ebfd58254b84a6f3c1d81d27a562  # 应用密钥
          name: 测试应用  # 应用名称
          time-verify: true  # 检查请求时间是否有效
          time-interval: PT30M  # 请求30分钟内有效
          one-verify: true  # 防止重复请求
          one-time-interval: PT1H  # 签名1小时内有效
          sign-type: ALL  # 签名方式
          urls:  # 需要验证签名的接口
          - /demo/login

💡 工作原理

签名是如何生成的?

  1. 📦 收集数据

    • 业务数据(如用户名密码)
    • 应用信息(appId)
    • 时间戳(防止重放)
    • 随机字符串(防止重复)
  2. 🔄 处理数据

    • 将所有数据转换为键值对
    • 按键名排序
    • 拼接成字符串
  3. 🔐 计算签名

    • 使用SHA1算法计算签名
    • 将签名添加到URL中

服务器如何验证?

  1. 时间检查

    • 验证请求是否在有效期内
    • 默认30分钟内有效
  2. 🔍 重复检查

    • 验证是否是重复请求
    • 使用随机字符串防重放
  3. 签名验证

    • 使用相同方法计算签名
    • 比对签名是否一致

❓ 常见问题

1. 签名验证失败?

  • ✓ 检查appId和appSecret是否正确
  • ✓ 确认系统时间是否准确
  • ✓ 验证参数排序是否正确
  • ✓ 打印签名字符串进行对比

2. 请求被拒绝?

  • ✓ 检查请求是否超时
  • ✓ 确认是否重复请求
  • ✓ 验证URL是否正确配置

3. 开发调试问题?

  • ✓ 打开详细日志
  • ✓ 打印签名参数
  • ✓ 使用调试工具跟踪

🎯 最佳实践

开发环境

  1. 👨‍💻 调试建议

    • 打印签名字符串
    • 关闭时间验证
    • 使用固定测试数据
  2. 🔧 配置建议

    • 延长请求有效期
    • 简化签名参数
    • 开启详细日志

生产环境

  1. 🛡️ 安全建议

    • 定期更换密钥
    • 启用所有验证
    • 使用HTTPS传输
  2. 📊 监控建议

    • 记录签名失败日志
    • 监控异常请求
    • 定期检查安全性

🆘 需要帮助?

如果遇到问题,可以:

  1. 📝 查看日志文件
  2. 🔍 打印签名参数
  3. 🌐 检查网络请求
  4. 📋 验证配置正确
  5. 💬 联系技术支持