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…...
【android bluetooth 框架分析 04】【bt-framework 层详解 1】【BluetoothProperties介绍】
1. BluetoothProperties介绍 libsysprop/srcs/android/sysprop/BluetoothProperties.sysprop BluetoothProperties.sysprop 是 Android AOSP 中的一种 系统属性定义文件(System Property Definition File),用于声明和管理 Bluetooth 模块相…...
c#开发AI模型对话
AI模型 前面已经介绍了一般AI模型本地部署,直接调用现成的模型数据。这里主要讲述讲接口集成到我们自己的程序中使用方式。 微软提供了ML.NET来开发和使用AI模型,但是目前国内可能使用不多,至少实践例子很少看见。开发训练模型就不介绍了&am…...
IoT/HCIP实验-3/LiteOS操作系统内核实验(任务、内存、信号量、CMSIS..)
文章目录 概述HelloWorld 工程C/C配置编译器主配置Makefile脚本烧录器主配置运行结果程序调用栈 任务管理实验实验结果osal 系统适配层osal_task_create 其他实验实验源码内存管理实验互斥锁实验信号量实验 CMISIS接口实验还是得JlINKCMSIS 简介LiteOS->CMSIS任务间消息交互…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
【HTTP三个基础问题】
面试官您好!HTTP是超文本传输协议,是互联网上客户端和服务器之间传输超文本数据(比如文字、图片、音频、视频等)的核心协议,当前互联网应用最广泛的版本是HTTP1.1,它基于经典的C/S模型,也就是客…...
浅谈不同二分算法的查找情况
二分算法原理比较简单,但是实际的算法模板却有很多,这一切都源于二分查找问题中的复杂情况和二分算法的边界处理,以下是博主对一些二分算法查找的情况分析。 需要说明的是,以下二分算法都是基于有序序列为升序有序的情况…...
Map相关知识
数据结构 二叉树 二叉树,顾名思义,每个节点最多有两个“叉”,也就是两个子节点,分别是左子 节点和右子节点。不过,二叉树并不要求每个节点都有两个子节点,有的节点只 有左子节点,有的节点只有…...
python执行测试用例,allure报乱码且未成功生成报告
allure执行测试用例时显示乱码:‘allure’ �����ڲ����ⲿ���Ҳ���ǿ�&am…...
零基础在实践中学习网络安全-皮卡丘靶场(第九期-Unsafe Fileupload模块)(yakit方式)
本期内容并不是很难,相信大家会学的很愉快,当然对于有后端基础的朋友来说,本期内容更加容易了解,当然没有基础的也别担心,本期内容会详细解释有关内容 本期用到的软件:yakit(因为经过之前好多期…...
算术操作符与类型转换:从基础到精通
目录 前言:从基础到实践——探索运算符与类型转换的奥秘 算术操作符超级详解 算术操作符:、-、*、/、% 赋值操作符:和复合赋值 单⽬操作符:、--、、- 前言:从基础到实践——探索运算符与类型转换的奥秘 在先前的文…...
