PHP实现一个简单的接口签名方法以及思路分析

news2024/9/20 8:04:21

文章目录

  • 签名生成说明
  • 签名生成示例代码
  • 签名校验示例代码

签名生成说明

B项目需要调用A项目的接口,由A项目为B项目分配 AccessKeySecretKey,用于接口加密,确保不易被穷举,生成算法不易被猜测。

最终需要确保包含签名的参数只能被有效的请求一次,重复请求则视为无效参数;并且设定参数有效时长(例如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 追加 AccessKeytimestampnonce 之后:

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);
}

签名校验示例代码

<?php

class 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;
    }
}

最终效果,同样的请求参数如果被抓包,再次请求就会失败:
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1794282.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

vscode 编程工具配置Java开发环境

vs code 开发环境配置。 环境准备&#xff1a; 1. 安装JDK/安装maven/安装vs code 首先安装好vs code 之后&#xff0c;需要安装 Extension Pack for Java 这么个插件 配置maven&#xff0c;进入setting&#xff0c; 3&#xff1a;配置 maven安装目录&#xff0c;4&#xff1a…

超详细!新手入门PMP®考试指南,收藏起来备考更高效​!

回复数字“6”&#xff0c;查看PMP考试过关口诀 无论你是刚刚踏入项目管理领域的新手&#xff0c;对于PMP考试充满好奇与期待&#xff1b; 还是已经在职场中摸爬滚打多年&#xff0c;希望通过PMP认证来进一步提升自己的项目管理能力和职业竞争力。 相信这份指南都会为你提供…

react 中使用 swiper

最近项目中需要用到轮播图&#xff0c;我立马想起了 swiper &#xff0c;那么本文就来带大家体验一下如何在 React 中使用这个插件&#xff0c;使用的是 函数组 hooks 的形式。 需求非常简单&#xff0c;就是一个可以自动播放、点击切换的轮播图&#xff08;跑马灯&#xff0…

UDSonCAN刷写之StayInBOOT和FlashDiver

目录 0 前言 1 StayInBOOT 2 Flash Driver 0 前言 最近在做刷写相关的工作&#xff0c;顺便搞懂了StayInBOOT和FlashDiver&#xff0c;写出来作为分享&#xff0c;如果有哪里不对也请多多指正。 1 StayInBOOT StayInBOOT在整个流程中的位置如下图所示&#xff0c;从图中可…

青否数字人直播源码超级管理后台操作步骤!

青否数字人直播源码超级管理后台&#xff0c;我们将详细介绍一下数字人的管理后台的详细操作步骤&#xff01; 1.管理端入口 2.管理后台预览 账号管理&#xff0c;模特管理&#xff0c;声音管理&#xff0c;任务管理&#xff0c;卡类管理&#xff0c;代理商&#xff0c;克隆端 …

python绘制热力图

python绘制热力图 热力图效果代码 热力图 热力图&#xff08;Heatmap&#xff09;是一种数据可视化技术&#xff0c;用于显示数据的密度或强度。通过颜色的变化来反映数值的大小或分布情况&#xff0c;热力图能够直观地展示数据的聚集区域、模式和趋势。它广泛应用于各个领域&…

基于51单片机的简易温控水杯恒温杯仿真设计( proteus仿真+程序+设计报告+讲解视频)

基于51单片机的简易温控水杯恒温杯仿真设计( proteus仿真程序设计报告讲解视频&#xff09; 仿真图proteus7.8及以上 程序编译器&#xff1a;keil 4/keil 5 编程语言&#xff1a;C语言 设计编号&#xff1a;S0099 1. 主要功能&#xff1a; 基于51单片机的简易温控水杯恒温…

百元级蓝牙耳机推荐,五大最新真香品牌机型盘点!

蓝牙耳机已成为我们不可或缺的伴侣无论是通勤路上的音乐陪伴&#xff0c;还是健身房里的动感节奏&#xff0c;一副高品质的蓝牙耳机都能为我们带来无与伦比的听觉享受&#xff0c;今天我将为大家盘点五大最新真香品牌机型&#xff0c;这些百元级的蓝牙耳机不仅价格亲民&#xf…

Qt如何让按钮的菜单出现在按钮的右侧

直接上代码&#xff0c;我们用到了一个eventfilter的函数功能。这个函数比较厉害和重要&#xff0c;大家务必经常拿出来看看。 void MainWindow::initMenu() { QMenu* menuLiXiang new QMenu; QAction* actXiangMuZhangCheng new QAction("项目章程"); …

cocos入门4:项目目录结构

Cocos Creator 项目结构教程 Cocos Creator 是一个功能强大的游戏开发工具&#xff0c;它为开发者提供了直观易用的界面和强大的功能来快速创建游戏。在使用 Cocos Creator 开发游戏时&#xff0c;合理地组织项目结构对于项目的可维护性和扩展性至关重要。以下是一个关于如何设…

新一代企业共享服务中心,开启企业智慧管理决策新纪元

随着数字化浪潮加速来袭&#xff0c;企业面临着与以往全然不同的挑战与机遇。 业务与人员的增长致使服务请求与日俱增&#xff0c;业务类型愈加复杂&#xff0c;大量来自不同业务线的服务请求使内部服务压力增加。业务激增后只得依赖更多资源投入&#xff0c;势必掣肘服务效率。…

Nvidia/算能 +FPGA+AI大算力边缘计算盒子:医疗健康智能服务

北京天星医疗股份有限公司(简称“天星医疗”)作为国产运动医学的领导者&#xff0c;致力于提供运动医学的整体临床解决方案&#xff0c;公司坐落于北京经济技术开发区。应用于肩关节、膝关节、足/踝关节、髋关节、肘关节、手/腕关节的运动医学设备、植入物和手术器械共计300多个…

Postgresql源码(135)生成执行计划——Var的调整set_plan_references

1 总结 set_plan_references主要有两个功能&#xff1a; 拉平&#xff1a;生成拉平后的RTE列表&#xff08;add_rtes_to_flat_rtable&#xff09;。调整&#xff1a;调整前每一层计划中varno的引用都是相对于本层RTE的偏移量。放在一个整体计划后&#xff0c;需要指向一个统一…

Cochrane Library循证医学数据库的介绍及文献下载

今天要讲的数据库是Cochrane Library循证医学数据库&#xff0c;我们先来了解一下该数据库&#xff1a; Cochrane Library是国际Cochrane Collaboration的主要产品&#xff0c;由英国Wiley InterScience公司出版发行。是一个提供高质量证据的数据库&#xff0c;是循证医学的证…

如何把试卷上的字去掉再打印?分享三种方法

如何把试卷上的字去掉再打印&#xff1f;随着科技的不断发展&#xff0c;现代教育和学习方式也在逐渐变革。在学习过程中&#xff0c;我们经常需要对试卷进行整理和分析&#xff0c;以便更好地掌握知识点和复习。然而&#xff0c;传统的试卷整理方法往往效率低下且容易出错。幸…

前端实现大文件分片并行上传、断点续传、秒传(完整解析)

一、总体流程图 二、具体步骤 简单理解&#xff1a;前端先将文件切割多份&#xff0c;在进行上传&#xff0c;由后端进行切片合并操作。 具体逻辑&#xff1a; 1. 前端选中上传文件&#xff08;如果是批量上传就把选中的文件存入选中文件列表数组中&#xff0c;后续在遍历上…

java版CRM客户关系管理系统源码:CRM客户关系管理系统的功能详解

CRM客户关系管理系统是一款功能全面的客户管理工具&#xff0c;旨在帮助企业和销售团队提高客户管理效率&#xff0c;优化销售流程。该系统包含多个模块&#xff0c;覆盖了从线索到回款的全流程管理&#xff0c;为用户提供了一个集成化的客户关系管理平台。 一、待办事项模块&a…

Python 技巧分享:NEF 文件的元数据提取

介绍 随着摄影技术的不断发展&#xff0c;NEF 文件作为尼康相机的 RAW 格式文件&#xff0c;因其包含丰富的图像数据和元数据&#xff0c;备受摄影爱好者和专业摄影师的青睐。提取 NEF 文件中的元数据对照片管理、分析及处理具有重要意义。本文将介绍如何使用 Python 技术&…

nltk报错Error loading stopwords: <urlopen error [Errno 11004]

最佳解决方案是手动下载并安装 nltk 数据。这里是详细步骤&#xff0c;确保每一步都能正确执行&#xff1a; 步骤 1: 手动下载 stopwords 数据集 下载 stopwords 数据集&#xff1a; 打开浏览器&#xff0c;访问以下链接下载 stopwords 数据集&#xff1a; stopwords.zip 解…

sap 应用日志-Application Log

文章目录 sap 应用日志-Application Log概念事务代码函数创建程序显示配置文件运行结果弹出式全屏式 程序剖析清空日志创建日志模拟数据添加日志消息显示日志BAL_DSP_LOG_DISPLAY-显示内存消息 全部程序 sap 应用日志-Application Log 概念 SAP 应用日志&#xff08;Applicat…