PHP实现一个简单的接口签名方法以及思路分析
文章目录
- 签名生成说明
- 签名生成示例代码
- 签名校验示例代码
签名生成说明
B项目需要调用A项目的接口,由A项目为B项目分配 AccessKey 和 SecretKey,用于接口加密,确保不易被穷举,生成算法不易被猜测。
最终需要确保包含签名的参数只能被有效的请求一次,重复请求则视为无效参数;并且设定参数有效时长(例如5分钟),超时则视为无效参数。
AccessKey 和 SecretKey分配:
测试环境:
ACCESS_KEY = test_access
SECRET_KEY = test_secret正式环境:(另行配置)
假设A项目和B项目通过json格式传递参数,在PHP中对请求的json参数转化为数组,然后对原本的请求参数追加如下字段值:
AccessKey:已分配的请求key,固定值;timestamp:当前毫秒时间戳;nonce:唯一随机10位字符串,15分钟内不允许重复;
例如,原本的请求参数 $params 为:
Array
([ToUserName] => wxdd5624bd15b1691a[FromUserName] => sys[CreateTime] => 1717554600[MsgType] => event[Event] => sys_approval_change[AgentID] => 1000043
)
对 $params 追加 AccessKey 和 timestamp 和 nonce 之后:
Array
([ToUserName] => wxdd5624bd15b1691a[FromUserName] => sys[CreateTime] => 1717554600[MsgType] => event[Event] => sys_approval_change[AgentID] => 1000043[AccessKey] => test_access[timestamp] => 1717659814771[nonce] => 6bc6f34969
)
将 $params 的 key 值按照字母升序排列(PHP中的 ksort 函数):
Array
([AccessKey] => test_access[AgentID] => 1000043[CreateTime] => 1717554600[Event] => sys_approval_change[FromUserName] => sys[MsgType] => event[ToUserName] => wxdd5624bd15b1691a[nonce] => 756c577626[timestamp] => 1717659831355
)
然后,将上述参数赋给一个临时的变量(例如:$tmp_params),并且拼接 SecretKey,然后整体json_encode,再次md5之后,得到sign值,代码如下:
$sign = md5(json_encode($tmp_params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));
将 sign值 追加到 $params 参数中(注意:是$params参数,不是 $tmp_params ),最终参数如下:
Array
([AccessKey] => test_access[AgentID] => 1000043[CreateTime] => 1717554600[Event] => sys_approval_change[FromUserName] => sys[MsgType] => event[ToUserName] => wxdd5624bd15b1691a[nonce] => 137c128684[timestamp] => 1717660145228[sign] => ff0ea47d561eb2d9735771f0bc85ad33
)
将上述参数转化为json后作为最终的请求参数:
{"AccessKey": "test_access","AgentID": "1000043","CreateTime": "1717554600","Event": "sys_approval_change","FromUserName": "sys","MsgType": "event","ToUserName": "wxdd5624bd15b1691a","nonce": "fb212b7327","timestamp": 1717660335729,"sign": "9e5321b10ddc975b89a228e94d8e5f04"
}
签名生成示例代码
public function createSign()
{$mock_json = '{"ToUserName": "wxdd5624bd15b1691a","FromUserName": "sys","CreateTime": "1717554600","MsgType": "event","Event": "sys_approval_change","AgentID": "1000043"}';$params = json_decode($mock_json, true);//对原本的请求参数追加如下字段值:$params['AccessKey'] = 'test_access'; //已分配的请求key,固定值$params['timestamp'] = intval(microtime(true) * 1000); //当前毫秒时间戳$params['nonce'] = substr(uniqid(), -6) . rand(1000, 9999); //唯一随机10位字符串,15分钟内不允许重复//按照上述所有请求参数的key值的字母升序排列(PHP中的 `ksort` 函数):ksort($params);//然后,将上述参数赋给一个临时的变量,并且拼接 SecretKey, 然后整体json_encode,再次md5之后,得到sign值$tmp_params = $params;$tmp_params['SecretKey'] = 'test_secret';$sign = md5(json_encode($tmp_params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES));//将 sign值 追加到 $params 参数中(注意:是$params参数,不是 $tmp_params )$params['sign'] = $sign;//将上述参数转化为json后作为最终的请求参数:echo json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);
}
签名校验示例代码
<?phpclass Demo
{//时间常量const TIME_OUT = 300; //超时时间 5分钟const NONCE_INTERVAL = 900; //允许nonce时间间隔 15分钟/*** 签名验证* @param $params array 客户端请求来的原本的参数数组* @return array* @throws \Exception*/public function checkSign($params){$request_params = $params;if (empty($params['timestamp']) || empty($params['nonce']) || empty($params['sign'])) {throw new \Exception('签名基础参数校验失败', 201);}//校验超时$timestamp = intval($params['timestamp'] / 1000);if (abs(time() - $timestamp) > self::TIME_OUT) {throw new \Exception('请求参数已超时', 201);}//从配置文件中读取ACCESS_KEY和SECRET_KEY$access_key = env('ACCESS_KEY');$secret_key = env('SECRET_KEY');if (empty($access_key) || empty($secret_key)) {throw new \Exception('NEW_CRM_REQUEST配置异常', 201);}if ($access_key != $params['AccessKey']) {throw new \Exception('无效的AccessKey', 201);}$nonce_key = 'test_nonce:' . $params['timestamp'] . '_' . $params['nonce'];$exist_nonce = RedisUtils::init()->get($nonce_key);if ($exist_nonce) {throw new \Exception('无效的nonce值', 201);}$sign = $params['sign'];unset($params['sign']);ksort($params);$params['SecretKey'] = $secret_key;$params_json = json_encode($params, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES);$params_sign = md5($params_json);if ($params_sign != $sign) {//todo 写入错误log 或 发送报警信息//todo 校验频繁请求失败的IP,可以考虑将这些IP加入黑名单throw new \Exception('签名校验失败', 201);}RedisUtils::init()->set($nonce_key, 1, self::NONCE_INTERVAL);unset($params['AccessKey']);unset($params['SecretKey']);unset($params['nonce']);unset($params['timestamp']);return $params;}
}
最终效果,同样的请求参数如果被抓包,再次请求就会失败:

相关文章:
PHP实现一个简单的接口签名方法以及思路分析
文章目录 签名生成说明签名生成示例代码签名校验示例代码 签名生成说明 B项目需要调用A项目的接口,由A项目为B项目分配 AccessKey 和 SecretKey,用于接口加密,确保不易被穷举,生成算法不易被猜测。 最终需要确保包含签名的参数只…...
StartAI”梦想合伙人 ”招募计划
我们正火热招募AI设计师产品合伙人!如果你对AI技术充满好奇,对设计有着独特的见解和热情,亦或者你想在日常的设计工作中提高效率,无论你是电商设计师、UI设计师、建筑师、插画师等其他各类设计领域的人才。那么这就是你不容错过的…...
记录:podman安装redis
Linux系统上安装redis: podman pull redis # 拉取最新的redis版本 podman images # 查看所有本地的镜像,包括刚拉取的redis镜像mkdir -p /etc/redis/conf /etc/redis/data # 创建2个目录文件,保存redis的数据和配置文件 tou…...
TrinityCore启动报错: MySQL library version (8.0.37 id 80037) does not match
TrinityCore启动的时候报错: TrinityCore/src/server/database/Database/DatabaseWorkerPool.cpp:73 in DatabaseWorkerPool FATAL ERROR: Used MySQL library version (8.0.37 id 80037) does not match the version id used to compile TrinityCore (id 80036). S…...
代码随想三刷字符串篇
代码随想三刷字符串篇 344. 反转字符串题目代码541. 反转字符串 II题目代码54. 替换数字(第八期模拟笔试)题目代码151. 反转字符串中的单词题目代码55. 右旋字符串(第八期模拟笔试题目代码28. 实现 strStr()题目代码459.重复的子字符串题目代码344. 反转字符串 题目 链接 …...
华为支持手指关节手势的原理
华为的指关节手势有指关节截屏、指关节录屏、指关节区域截屏、指关节分屏等。该技术的实现是靠触控结合了其他一些传感器实现的。 华为的专利: 一种手势控制方法、装置、终端设备和存储介质——华为技术有限公司 专利中提到以往终端设备对于手势的识别都是基于位置和…...
Flink的简单学习五
一 动态表与连续查询 1.1 动态表 1.是flink的支持流数据Table API 和SQL的核心概念。动态表随时间的变化而变化 2.在流上面定义的表在内部是没有数据的 1.2 连续查询 1.永远不会停止,结果是一张动态表 二 Flink SQL 2.1 sql行 1.先启动启动flink集群 yarn-see…...
C++|哈希应用->位图
目录 一、概念 1.1原理分析: 1.2效率分析: 二、模拟实现 2.1位图框架初始化空间 2.2映射 2.3清零 2.4判断 2.5测试代码 三、位图扩展应用 一、概念 位图,本质上也是一个数组,通过哈希思想构造的一种数据结构,…...
Rust 实战丨SSE(Server-Sent Events)
📌 SSE(Server-Sent Events)是一种允许服务器向客户端浏览器推送信息的技术。它是 HTML5 的一部分,专门用于建立一个单向的从服务器到客户端的通信连接。SSE的使用场景非常广泛,包括实时消息推送、实时通知更新等。 S…...
Django API开发实战:前后端分离、Restful风格与DRF序列化器详解
系列文章目录 Django入门全攻略:从零搭建你的第一个Web项目Django ORM入门指南:从概念到实践,掌握模型创建、迁移与视图操作Django ORM实战:模型字段与元选项配置,以及链式过滤与QF查询详解Django ORM深度游ÿ…...
React基础教程:TodoList案例
todoList案例——增加 定义状态 // 定义状态state {list: ["kevin", "book", "paul"]}利用ul遍历list数组 <ul>{this.state.list.map(item ><li style{{fontWeight: "bold", fontSize: "20px"}} key{item.i…...
PHP超详细安装及应用
目录 所需安装包如下 一、PHP安装 依赖包安装 安装扩展工具(先将PHP所需的软件包全部拖进centos根目录下) 安装libmcrypt 安装mhash 安装mcrypt 安装PHP 二、设置LAMP组件环境(要保证mysql、http都安装完成了) Php.ini的建…...
【算法篇】大数加法JavaScript版
题目描述 以字符串的形式读入两个数字,编写一个函数计算它们的和,以字符串形式返回。 数据范围:s.length,t.length≤100000,字符串仅由’0’~‘9’构成 要求:时间复杂度 𝑂(𝑛) 示例1 输入&…...
【LeetCode 128】 最长连续子序列
判断前一位数在不在字典中是这道题的关键之处,这样就可以避免重复查找,从而达到O(n) 的时间复杂度。如果没有这个判断,那么时间复杂度最坏也得是O(N^2)级别的。 1. 题目 2. 分析 合理利用数据结构。本题中使用了set来保存数组的元素&#x…...
SpringCloud-面试篇(二十六)
(1)Sentinel核心API-ProcessorslotChain...
使用__try...__except和try...catch捕获异常实例分享(附源码)
在C/C++的代码中,为了防止代码块执行的过程中产生异常导致软件崩溃,我们会给代码块添加__try...__except或try...catch保护,防止软件因为操作内部触发的异常产生崩溃。本文简单地介绍一下这两种异常捕获的使用示例。 1、概述 当软件运行过程中代码抛出异常,如果异常没有处…...
基于51单片机的简易温控水杯恒温杯仿真设计( proteus仿真+程序+设计报告+讲解视频)
基于51单片机的简易温控水杯恒温杯仿真设计( proteus仿真程序设计报告讲解视频) 仿真图proteus7.8及以上 程序编译器:keil 4/keil 5 编程语言:C语言 设计编号:S0099 1. 主要功能: 基于51单片机的简易温控水杯恒温…...
王德峰视频讲座,王德峰视频全部大全集,百度云百度网盘资源下载
王德峰教授的视频讲座其内容丰富、观点独到,深受广大学者和爱好者的喜爱。很多朋友想下载王德峰教授的讲座视频,今天我给大家分享一个下载王德峰教授视频的方法 搜索 “方圆资源网官网” 打开 “方圆资源网官网,找到王德峰教授的讲座 总之&a…...
Visual Studio和BOM历史渊源
今天看文档无意间碰到了微软对编码格式解释,如下链接: Understanding file encoding in VS Code and PowerShell - PowerShell | Microsoft LearnConfigure file encoding in VS Code and PowerShellhttps://learn.microsoft.com/en-us/powershell/scrip…...
虚拟现实(VR)游戏与增强现实(AR)游戏的区别
随着科技的飞速发展,沉浸式游戏体验已经成为现代娱乐的重要组成部分。虚拟现实(VR)游戏和增强现实(AR)游戏是这类体验中的两大主流,但它们在技术实现、用户体验和应用场景上有显著的区别。本文将详细探讨VR…...
【网络】每天掌握一个Linux命令 - iftop
在Linux系统中,iftop是网络管理的得力助手,能实时监控网络流量、连接情况等,帮助排查网络异常。接下来从多方面详细介绍它。 目录 【网络】每天掌握一个Linux命令 - iftop工具概述安装方式核心功能基础用法进阶操作实战案例面试题场景生产场景…...
手游刚开服就被攻击怎么办?如何防御DDoS?
开服初期是手游最脆弱的阶段,极易成为DDoS攻击的目标。一旦遭遇攻击,可能导致服务器瘫痪、玩家流失,甚至造成巨大经济损失。本文为开发者提供一套简洁有效的应急与防御方案,帮助快速应对并构建长期防护体系。 一、遭遇攻击的紧急应…...
R语言AI模型部署方案:精准离线运行详解
R语言AI模型部署方案:精准离线运行详解 一、项目概述 本文将构建一个完整的R语言AI部署解决方案,实现鸢尾花分类模型的训练、保存、离线部署和预测功能。核心特点: 100%离线运行能力自包含环境依赖生产级错误处理跨平台兼容性模型版本管理# 文件结构说明 Iris_AI_Deployme…...
理解 MCP 工作流:使用 Ollama 和 LangChain 构建本地 MCP 客户端
🌟 什么是 MCP? 模型控制协议 (MCP) 是一种创新的协议,旨在无缝连接 AI 模型与应用程序。 MCP 是一个开源协议,它标准化了我们的 LLM 应用程序连接所需工具和数据源并与之协作的方式。 可以把它想象成你的 AI 模型 和想要使用它…...
聊聊 Pulsar:Producer 源码解析
一、前言 Apache Pulsar 是一个企业级的开源分布式消息传递平台,以其高性能、可扩展性和存储计算分离架构在消息队列和流处理领域独树一帜。在 Pulsar 的核心架构中,Producer(生产者) 是连接客户端应用与消息队列的第一步。生产者…...
【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
vulnyx Blogger writeup
信息收集 arp-scan nmap 获取userFlag 上web看看 一个默认的页面,gobuster扫一下目录 可以看到扫出的目录中得到了一个有价值的目录/wordpress,说明目标所使用的cms是wordpress,访问http://192.168.43.213/wordpress/然后查看源码能看到 这…...
接口自动化测试:HttpRunner基础
相关文档 HttpRunner V3.x中文文档 HttpRunner 用户指南 使用HttpRunner 3.x实现接口自动化测试 HttpRunner介绍 HttpRunner 是一个开源的 API 测试工具,支持 HTTP(S)/HTTP2/WebSocket/RPC 等网络协议,涵盖接口测试、性能测试、数字体验监测等测试类型…...
BLEU评分:机器翻译质量评估的黄金标准
BLEU评分:机器翻译质量评估的黄金标准 1. 引言 在自然语言处理(NLP)领域,衡量一个机器翻译模型的性能至关重要。BLEU (Bilingual Evaluation Understudy) 作为一种自动化评估指标,自2002年由IBM的Kishore Papineni等人提出以来,…...
抽象类和接口(全)
一、抽象类 1.概念:如果⼀个类中没有包含⾜够的信息来描绘⼀个具体的对象,这样的类就是抽象类。 像是没有实际⼯作的⽅法,我们可以把它设计成⼀个抽象⽅法,包含抽象⽅法的类我们称为抽象类。 2.语法 在Java中,⼀个类如果被 abs…...
