一、概述

        开年第一篇,该篇主要讲述了接口开发中,如何安全认证、如何用php签名认证。

  二、说说历史

        签名认证是什么?为什么要做签名认证?签名认证哪里会用到?no、no、no.....是不是,是不是,一下子疑问就这么多了!没事儿,通过追溯历史,我们来明白这些。

     1、签名认证是什么?

        数字签名是一种类似写在纸上的普通的物理签名,但是使用了公钥加密领域的技术实现,用于鉴别数字信息的方法。一套数字签名通常定义两种互补的运算,一个用于签名,另一个用于验证。
数字签名,就是只有信息的发送者才能产生的别人无法伪造的一段数字串,这段数字串同时也是对信息的发送者发送信息真实性的一个有效证明。
        在这个以“数据为生命”的时代,每一个开发商都尽可能的收集客户的数据建立自己的BI库,各系统、各平台间数据的传输和调用变得非常普遍且非常重要;那么作为开发人员,我们不但要防止系统被攻击被入侵,我们还要确保数据的安全和完整

       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签名认证的更多相关文章

  1. REST签名认证

    139 开放平台与应用之间以REST协议进行通讯,为了保证通信的安全性,开放平台加入签名认证机制.应用一旦创建,系统生成唯一并且不公开的secretkey,只有应用的拥有者和开放平台知道.因此,当应用 ...

  2. 关于下载SAE日志签名认证的方法——PHP版

    之前需要下载SAE上的日志存入数据库,因此研究了下SAE的签名认证和日志下载.这个链接是SAE官方给出的API文档.https://www.sinacloud.com/doc/api.html#qia ...

  3. ASP.NET Web API 2 使用 DelegatingHandler(委托处理程序)实现签名认证

    Ø  前言 在前一篇ASP.NET Web API 2 使用 AuthorizationFilter(授权过滤器)实现 Basic 认证文章中实现了采用 Basic 认证的方式,但是这种方式存在安全隐 ...

  4. ASP.NET WebApi 基于OAuth2.0实现Token签名认证

    一.课程介绍 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将是我们需要思考的问题.为了保护我们的WebApi数 ...

  5. ASP.NET WebApi 基于JWT实现Token签名认证

    一.前言 明人不说暗话,跟着阿笨一起玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NET WebServi ...

  6. ASP.NET WebApi 基于分布式Session方式实现Token签名认证

    一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...

  7. kbmmw 做REST 服务签名认证的一种方式

    一般对外提供提供REST 服务,由于信息安全的问题, 都要采用签名认证,今天简单说一下在KBMMW 中如何 实现简单的签名服务? 整个签名服务,模仿阿里大鱼的认证方式,大家可以根据实际情况自己修改. ...

  8. 火币网API文档——REST API 签名认证

    安全认证 目前关于apikey申请和修改,请在“账户 - API管理”页面进行相关操作.其中AccessKey为API 访问密钥,SecretKey为用户对请求进行签名的密钥(仅申请时可见).Pro站 ...

  9. ASP.NET WebApi 基于分布式Session方式实现Token签名认证(发布版)

    一.课程介绍 明人不说暗话,跟着阿笨一起学玩WebApi!开发提供数据的WebApi服务,最重要的是数据的安全性.那么对于我们来说,如何确保数据的安全将会是需要思考的问题.在ASP.NETWebSer ...

随机推荐

  1. 变量新声明之let、const

    一.let 1.通过let声明变量不会变量声明提升 let a = 10; console.log( a ) 会报错 2. let a = 10; let a = 10; 会报错,(a 已被定义) 3 ...

  2. linux dd 本地挂载

    losetup /dev/loop0 /root/test.img mkfs.ext4 /dev/loop0 mount /dev/loop0 /data

  3. mysqli链接数据库

    <?php $uid = $_GET['uid']; $host = 'localhost';$database = 'test';$username = 'root';$password = ...

  4. Java 定时任务的几种实现方式

    JAVA实现定时任务的几种方式 @(JAVA)[spring|quartz|定时器]  近期项目开发中需要动态的添加定时任务,比如在某个活动结束时,自动生成获奖名单,导出excel等,此类任务由于活动 ...

  5. linux下Vim文本编辑器的常用快捷键

    Linux插入命令 a 在光标之后插入字符 A  把光标移动到行首尾进入插入模式 i 在光标之前插入字符 I 把光标移动到行首并进入插入模式 o 在光标下插入新行 O 在光标上插入新行 Linux定位 ...

  6. rsa加密算法及js的JSEncrypt实现前端加密

    最近的项目中用到了rsa加密算法,在实现了相关功能之后,我去了解了一下rsa相关原理,于是就写了这篇博客啦. 首先介绍一下什么是rsa加密算法: 作为非对称加密算法的老大,rsa号称是地球上最安全的加 ...

  7. Ubuntu16.04 藍牙連上,但是聲音裏面找不到設備

    解決辦法: 1. sudo apt-get install blueman bluez* 2. sudo vim /etc/pulse/default.pa 注釋掉下面的代碼: #.ifexists ...

  8. flock - 必应词典

    flock - 必应词典 美[flɑk]英[flɒk] v.聚集:群集:蜂拥 n.(羊或鸟)群:(尤指同类人的)一大群 网络羊群:大量:羊群,一群 变形复数:flocks:过去分词:flocked:现 ...

  9. js实现接口隔离

    昨天公司培训了接口隔离,简单说一下 接口隔离:类间的依赖关系应该建立在最小的接口上.接口隔离原则将非常庞大.臃肿的接口拆分成更小具体的接口,这样客户讲会只需要知道他们感兴趣的方法. 接口隔离原则的目的 ...

  10. VS code 代码格式整理的配置

    { "workbench.iconTheme": "material-icon-theme", "vetur.validation.template& ...