php签名认证
一、概述
开年第一篇,该篇主要讲述了接口开发中,如何安全认证、如何用php签名认证。
二、说说历史
签名认证是什么?为什么要做签名认证?签名认证哪里会用到?no、no、no.....是不是,是不是,一下子疑问就这么多了!没事儿,通过追溯历史,我们来明白这些。
1、签名认证是什么?
2、为什么要做签名认证?
在使用http或者soap传输数据的时候,签名作为其中一个参数,可以起到关键作用:1、鉴权(通过客户的密钥,服务端的密钥匹配);2、数据防篡改(参数是明文传输,将参数及密钥加密作为签名与服务器匹配);下面来分析下具体的方式:
将请求参数中的各个键值对按照key的字符串顺序升序排列(大小写敏感),把key和value拼成一串之后最后加上密钥,组成key1value1key2value2PRIVATEKEY的格式,转成utf-8编码的字节序列后计算md5,作为请求的签名。计算出来的签名串应当全为小写形式。如果某个参数的值为空,则此参数不参与签名。
3、签名认证哪里会用到?
最常见的使我们在开发接口的时候,为了不被非法访问,往往我们会做签名认证,比如支付接口......
然后就是第三方平台的开发,比如微信公众平台......
三、流程分析
客户端:首先我们为提供给用户一份接口文档,文档里面我们给用户提供api地址、签名算法解析过程、数据说明。
服务端:进行客户端检验,通常就是参数个数、格式验证,app_key验证(这个是博主这里使用的,这个app_key会交给用户,用户访问接口的时候必须带上该app_key),签名结果验证。
以我这次写的为例子来描述一下整个流程:
用户参照我们提供的接口文档,请求我们的接口,用户按照我们接口说明的签名算法生成签名串作为参数,然后带上必要的参数(GET、POST),如果服务端验证成功,则返回真实数据。
在服务端:我们首要验证提交参数的个数、格式是否正确,然后我们通过提交的参数用签名算法生成一个签名串,最后服务端生成的签名串和客户端提交过来的签名串进行比较,成功返回真实数据。
四、上代码
- <?php
- namespace ceshi;
- /**
- * 签名认证算法
- * HMAC-SHA256加密方式
- * 登录认证加入access_token:access-token通过登录接口去获取,通过刷新接口去刷新,需要注意返回的过期时间,要在过期时间之前刷新重新获取access-token。目前约定所有接口都必须传access-token,也就是用户必须先登录才可以看到相关内容
- * 随机函数可换更好的方法-本实例随机函数比较简单,随机性不够
- * ApiSign类作为服务端,类以外的代码作为客户端示例代码
- * author jiechengyang https://www.cnblogs.com/YangJieCheng/
- */
- class ApiSign
- {
- CONST DELAY_TIME = 2000;
- CONST ACCESS_TOCEN_PATH = './access_token';
- private $_config = [];
- protected $AppKey = 'voBVVQxfMxDmhuxV70';
- protected $AppSecret = 'QJF5P8qWFJakF9Ve89ZcIstHKbkt5fVA';
- protected $timeout = 300;
- protected $algo = 'sha256';
- public $loginCheck = false;
- public function __construct($config, $loginCheck)
- {
- $this->_config = $config;
- empty($this->AppKey) && $this->AppKey = $this->generateRandomString();
- empty($this->AppSecret) && $this->AppSecret = $this->generateRangeNum();
- $this->loginCheck = $loginCheck;
- if ($this->init()) {
- echo '<span style="color:red" id="sign_success">恭喜,签名认证成功</span><script type="text/javascript"></script>';
- echo <<<JS
- <script>
- var colors = ['#ffff00', '#ff66ff', '#99cc33', '#66ff33', '#000000', '#FF83FA', '#CAE1FF'];
- var tmp = 0;
- var timer = setInterval(colorChanage, 1000);
- function colorChanage()
- {
- if(tmp == colors.length) {
- tmp = 0;
- }
- document.getElementById('sign_success').style.color = colors[tmp++];
- }
- </script>
- JS;
- }
- }
- protected function init()
- {
- if (!isset($this->_config['_key'])
- || !isset($this->_config['_sign'])
- || !isset($this->_config['_time'])
- || !isset($this->_config['_nonce'])
- || strlen($this->_config['_nonce']) !== 32
- || !is_numeric($this->_config['_time'])) {
- $this->callback(['message' => '请求参数不全, 或参数不规范'], 'error');
- }
- if (!isset($this->_config['_time']) || $this->getIsTimeOut()) {
- $this->callback(['message' => '请求超时'], 'error');
- }
- // 客户端验证
- $requestSignature = $this->_config['_sign'];
- $requestSignature = str_replace(' ', '+', $requestSignature);
- if($this->_config['_key'] !== $this->AppKey) {
- $this->callback(['message' => '非法的app_key'], 'error');
- }
- $signature = $this->generateSign($this->_config);
- if ($requestSignature != $signature) {
- $this->callback(['message' => '签名错误'], 'error');
- }
- $accessToken = $this->getAccessToken();
- // 用户登录token验证
- if ($this->loginCheck && $accessToken != $this->_config['access_token']) {
- $this->callback(['message' => 'access_token错误'], 'error');
- }
- return true;
- }
- private function callback($json=[], $status='ok')
- {
- $config = [
- 'ok' => [200, '操作成功'],
- 'error' => [300, '操作失败'],
- 'timeout' => [300, '操作超时'],
- ];
- $json['statusCode'] = $config[$status][0];
- !isset($json['message']) && $json['message'] = $config[$status][1];
- echo json_encode($json);
- exit;
- }
- private function getIsTimeOut()
- {
- if (abs($this->_config['_time'] - time()) > $this->timeout) {
- return true;
- }
- return false;
- }
- /**
- * 生成随便数
- */
- public function generateRangeNum($length = 32, $isToLower = false)
- {
- $str = $this->generateRandomString($length);
- if ($isToLower) {
- $str = strtolower($str);
- }
- return $str;
- }
- private function generateRandomString($length = 10) {
- $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
- $randomString = '';
- for ($i = 0; $i < $length; $i++) {
- $randomString .= $characters[rand(0, strlen($characters) - 1)];
- }
- return $randomString;
- }
- protected function generateSign($params)
- {
- if (isset($params['_sign'])) {
- unset($params['_sign']);
- }
- if($this->loginCheck && isset($params['access_token'])) {
- unset($params['access_token']);
- }
- ksort($params);
- $str = '';
- foreach ($params as $key => $value) {
- $str .= $key . '=' . $value . '&';
- }
- $str = rtrim($str, '&');
- return hash_hmac($this->algo, $str, $this->AppSecret, false);
- }
- public function getAccessToken()
- {
- if (!file_exists(self::ACCESS_TOCEN_PATH)) {
- $json = ['value' => $this->_config['access_token'], 'expires_in' => 7200, 'time' => time()];
- file_put_contents(self::ACCESS_TOCEN_PATH, json_encode($json));
- return $this->_config['access_token'];
- }
- $accessToken = json_decode(file_get_contents(self::ACCESS_TOCEN_PATH), true);
- if (time() - $accessToken['time'] > $accessToken['expires_in'] - self::DELAY_TIME) {
- $json = ['value' => $this->_config['access_token'], 'expires_in' => 7200, 'time' => time()];
- file_put_contents(self::ACCESS_TOCEN_PATH, json_encode($json));
- return $this->_config['access_token'];
- }
- return $accessToken['value'];
- }
- }
- /**
- * 生成随便数
- */
- function generateRangeNum($length = 32, $isToLower = false)
- {
- $str = generateRandomString($length);
- if ($isToLower) {
- $str = strtolower($str);
- }
- return $str;
- }
- function generateRandomString($length = 10) {
- $characters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
- $randomString = '';
- for ($i = 0; $i < $length; $i++) {
- $randomString .= $characters[rand(0, strlen($characters) - 1)];
- }
- return $randomString;
- }
- function generateSign($algo, $params, $AppSecret)
- {
- if (isset($params['_sign'])) {
- unset($params['_sign']);
- }
- ksort($params);
- $str = '';
- foreach ($params as $key => $value) {
- $str .= $key . '=' . $value . '&';
- }
- $str = rtrim($str, '&');
- return hash_hmac($algo, $str, $AppSecret, false);
- }
- header("content-type:text/html;charset:utf-8");
- $algo = 'sha256';
- $AppKey = 'voBVVQxfMxDmhuxV70';
- $AppKey = 'Rd1bW719zRbCXOBx3L';//---用于公司项目测试
- $AppSecret = 'QJF5P8qWFJakF9Ve89ZcIstHKbkt5fVA';
- $AppSecret = '73ZBAnbwVPDu0dvdlYE0RMvzsbhehejd';//---用于公司项目测试
- $nonce = generateRangeNum(32);
- $nonce = 'kj4ESP2Qcngaj3eAjpnrhCQR9g4yKnTM';//---用于公司项目测试
- $loginCheck = false;
- $params = [
- '_key' => $AppKey,
- '_time' => time(),
- '_nonce' => $nonce,
- ];
- $sign = generateSign($algo, $params, $AppSecret);
- echo $params['_time'],'<hr/>';//---用于公司项目测试
- echo $sign;exit;//---用于公司项目测试
- $params['_sign'] = $sign;
- $loginCheck && $params['access_token'] = generateRangeNum(16);
- // echo '<pre>';print_r($params);
- $apiSignModel = new ApiSign($params, $loginCheck);
php签名认证的更多相关文章
- REST签名认证
139 开放平台与应用之间以REST协议进行通讯,为了保证通信的安全性,开放平台加入签名认证机制.应用一旦创建,系统生成唯一并且不公开的secretkey,只有应用的拥有者和开放平台知道.因此,当应用 ...
- 关于下载SAE日志签名认证的方法——PHP版
之前需要下载SAE上的日志存入数据库,因此研究了下SAE的签名认证和日志下载.这个链接是SAE官方给出的API文档.https://www.sinacloud.com/doc/api.html#qia ...
- ASP.NET Web API 2 使用 DelegatingHandler(委托处理程序)实现签名认证
Ø 前言 在前一篇ASP.NET Web API 2 使用 AuthorizationFilter(授权过滤器)实现 Basic 认证文章中实现了采用 Basic 认证的方式,但是这种方式存在安全隐 ...
- ASP.NET WebApi 基于OAuth2.0实现Token签名认证
一.课程介绍 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将是我们需要思考的问题.为了保护我们的WebApi数 ...
- ASP.NET WebApi 基于JWT实现Token签名认证
一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...
- ASP.NET WebApi 基于分布式Session方式实现Token签名认证
一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...
- kbmmw 做REST 服务签名认证的一种方式
一般对外提供提供REST 服务,由于信息安全的问题, 都要采用签名认证,今天简单说一下在KBMMW 中如何 实现简单的签名服务? 整个签名服务,模仿阿里大鱼的认证方式,大家可以根据实际情况自己修改. ...
- 火币网API文档——REST API 签名认证
安全认证 目前关于apikey申请和修改,请在“账户 - API管理”页面进行相关操作.其中AccessKey为API 访问密钥,SecretKey为用户对请求进行签名的密钥(仅申请时可见).Pro站 ...
- ASP.NET WebApi 基于分布式Session方式实现Token签名认证(发布版)
一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...
随机推荐
- 源码解析之ConcurrentHashmap
ConcurrentHashmap算是我看的集合源码里最难理解的了(当然ConcurrentLinkedList虽然代码少但理解起来也累),在Java1.8版本中DougLea大师巧通过妙地代码把锁粒 ...
- python入门(十三):面向对象(继承、重写、公有、私有)
1. 三种类定义的写法 class P1:#定义类 加不加()都可以 pass class P2(): #带(),且括号中为空,类定义 pass ...
- Oracle主从同步、双向同步的配置
(本教程展示了Windows环境的oracle数据库主从同步,Linux环境一样也可以) (把主数据库obpm 和从数据库orcl 用实际的数据库名给替换掉) (配置主从同步后,再配置双向同步,可能会 ...
- 微信小程序如何接入?
1.线下扫码:小程序最基础的获取方式,是二维码.大家可以打开扫一扫,通过微信扫描线下二维码的方式进入小程序.这也是官方宣传中,最普遍的实用场景. 如何生成小程序导入码? 2.微信搜索 3.公众号关联 ...
- AXI
1.Cachable和bufferable 一个Master发出一个读写的request,中间要经过很多Buffer,最后才能送到memory.这些Buffer的添加是为了outstanding,ti ...
- chm制作及Haroopad使用(makedown工具)
所需工具 1.网文快捕(可以制作chm的工具,在IE浏览起立可以右键把复制内容保存到软件里) 下载地址:http://www.05sun.com/downinfo/278913.html 2.Haro ...
- Codeforces Round #552 (Div. 3) B题
题目链接:http://codeforces.com/contest/1154/problem/B 题目大意:给出n个数,每个数都可以加上或减去这个一个数D,求对这n个数操作之后当所有数都相等时,D的 ...
- redis各类错误可能的解决方案
.报Timeout performing EVAL 这个可能是连到读库从库了,直接改成写库就没问题了. 2. 各种ConnectTimeout 一般是偶尔或经常就超时,这种情况,找了各种回答,最后在s ...
- Oracle语言环境变量配置
创建系统环境变量,以下为GBK和UTF8两种模式: 变量名:NLS_LANG变量值:SIMPLIFIED CHINESE_CHINA.ZHS16GBK 变量名:NLS_LANG变量值:SIMPLIFI ...
- gitlab 与 jenkins 关联
一.搭建 gitlab :https://www.cnblogs.com/carriezhangyan/p/10729158.html 二.搭建jenkins :https://www.cnblogs ...