博客列表 >531-微信公众平台开发:本地环境搭建和签名校验与获取access_token

531-微信公众平台开发:本地环境搭建和签名校验与获取access_token

小威的博客
小威的博客原创
2018年06月03日 01:09:202387浏览
  •  搭建本地开发环境

由于微信公众平台开发,涉及到与平台对接,所以需要公网域名,而内网映射到公网的方法:国内有花生壳,但是蛋疼的是80端口要花钱买,而微信只对80端口开放对接。没办法只能用国外免费的NGROK,国外的网真难撸

  • 1. 先注册ngrok帐号 注册地址:https://dashboard.ngrok.com/user/signup 注意在注册时会出现验证码项,但天朝有些不明原因被屏蔽了,弄了一天也没注册成功,后来用谷歌浏览器+谷歌访问助手,成功注册到了。。。

0.png

  • 2. 注册成功 登录帐号  下载ngrok程序,解压到项目根目录,例如:D:\myphp_www\PHPTutorial\WWW\tp51

  • 3. 用命令行 安装程序  并运行程序

1.png

  • 4. 安装成功,如下图界面:并且获取到外网域名了

2.png

  • 注意:norok程序运行窗口,在开发过程中最好不要关闭,一关闭就会断线,再开启公网域名就会更新了

  • 5. 配置本地域名管理器-PHP工具箱。

3.png

  • 到此,本地开发环境就配置成功了,,但是后续开发服务号需要备案域名,所以云服务器+备案域名是最佳运行环境。


  • 接入微信公众平台开发,开发者需要按照如下步骤完成:

一、填写服务器配置

登录微信公众平台官网后,在公众平台官网的开发-基本设置页面,勾选协议成为开发者,点击“修改配置”按钮,填写服务器地址(URL)、Token和EncodingAESKey,其中URL是开发者用来接收微信消息和事件的接口URL。Token可由开发者可以任意填写,用作生成签名(该Token会和接口URL中包含的Token进行比对,从而验证安全性)。EncodingAESKey由开发者手动填写或随机生成,将用作消息体加解密密钥。

4.png

URL  根据开发环境域名配置    Token 协议密钥  开发者自定义   EncodingAESKey 开发者自定义或随机生成43个字符

二、验证服务器地址的有效性

开发者提交信息后,微信服务器将发送GET请求到填写的服务器地址URL上,GET请求携带参数如下表所示:

signature    微信加密签名  timestamp    时间戳     nonce    随机数     echostr    随机字符串    

我们这里用get的方法拿:signature timestamp nonce   echostr 这四项参数

 $signature = input('get.signature');
 $timestamp = input('get.timestamp');
 $nonce = input('get.nonce');
 $echostr = input('get.echostr');
 
 $token = config('app.token');

token 是我们自定义的,所以让我们提供:$token = ‘abcd12345’

而在企业级开发中,一般密钥口令之类的,我们不能写在项目中,而是写到配置中  再在项目中调用的

//微信配置
'token'            => 'aMCikdpelcnEk1omMjK4'

开发者通过检验signature对请求进行校验(下面有校验方式)。若确认此次GET请求来自微信服务器,请原样返回echostr参数内容,则接入生效,成为开发者成功,否则接入失败。加密/校验流程如下:

先将获取到的参数,保存到本地记事本,看看能否获得到相关参数

file_put_contents('D://data.txt','signature='.$signature.' timestamp='.$timestamp.' nonce='.$nonce.' echostr='.$echostr);

1)将token、timestamp、nonce三个参数进行字典序排序 

$tmpArr = array($timestamp,$nonce,$token);  //将几个参数放到一个数组中
sort($tmpArr, SORT_STRING); //sort(,SORT_STRING)   对数组进行排序

2)将三个参数字符串拼接成一个字符串进行sha1加密 

$str = implode($tmpArr);//implode 拼接字符串
$sign = sha1($str);//sha1加密字符串
echo $sign;//输出一下看看效果
exit;

QQ截图20180603000140.png

3)开发者获得加密后的字符串可与signature对比,标识该请求来源于微信

if ($sign !=$signature) {//如果检验不匹配
            exit('signature error');//返回一个签名错误
        }
        exit($echostr);//如果匹配通过,原样返回

以上所有校验代码都可以进行优化,将校验过程封装到模型中做为校验方法:tp51/application/model/Weixin.php

<?php
namespace app\index\model;
use think\Model;
use think\facade\Cache;

class Weixin extends Model{

    // 签名校验
    public function valid(){
        $signature = input('get.signature');
        $timestamp = input('get.timestamp');
        $nonce = input('get.nonce');
        $echostr = input('get.echostr');
        $token = config('app.token');

        $tmpArr = array($timestamp,$nonce,$token);
        sort($tmpArr, SORT_STRING);
        $str = implode($tmpArr);
        if(sha1($str) != $signature){
            return false;
        }
        return true;
    }

而在控制器中直接用valid()方法调用:

<?php
namespace app\index\controller;
use think\Controller;
use think\facade\Cache;//导入门面模式缓存方法

class Weixin extends Controller{
    public function __construct(){
        parent::__construct();
        $this->model = model('Weixin');//用构造器方法  方便后期整体参数修改
    }
    public function valid(){
        $valid = $this->model->valid();
        if(!$valid){
            exit('signature error');
        }
        exit(input('get.echostr'));
    }

三、依据接口文档实现业务逻辑

验证URL有效性成功后即接入生效,成为开发者。你可以在公众平台网站中申请微信认证,认证成功后,将获得更多接口权限,满足更多业务需求。

成为开发者后,用户每次向公众号发送消息、或者产生自定义菜单、或产生微信支付订单等情况时,开发者填写的服务器配置URL将得到微信服务器推送过来的消息和事件,开发者可以依据自身业务逻辑进行响应,如回复消息。

  • 获取access_token

access_token是公众号的全局唯一接口调用凭据,公众号调用各接口时都需使用access_token。开发者需要进行妥善保存。access_token的存储至少要保留512个字符空间。access_token的有效期目前为2个小时,需定时刷新,重复获取将导致上次获取的access_token失效。

1. 公众号可以使用AppID和AppSecret调用本接口来获取access_token。

2. AppID和AppSecret可在“微信公众平台-开发-基本配置”页中获得(需要已经成为开发者,且帐号没有异常状态)。

3. 调用接口时,请提前将服务器IP地址添加到IP白名单中,点击查看设置方法,否则将无法调用成功。

5.png

接口https请求方式: GET:

https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=APPID&secret=APPSECRET

此请求URL中有两个重要参数: APPID  APPSECRET  这两个参数一般不直接写在项目中,而是写到项目配置中APP

//微信配置
    'token'            => 'aMCikdpelc00k1omMjK4',

    'appid'                  => 'wxdb8a19000a62f575',

    'appsecret'              => '8084703db2897e05000024975dc1708',

URL请求方式:GET,微信官方有给我们提供实例程序如下:把它写到公共文件下面:tp51/application/common.php

<?
// 应用公共文件
function http_Get($url){
	$curl = curl_init();
	curl_setopt($curl,CURLOPT_URL,trim($url));
	curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
	curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
	curl_setopt($curl,CURLOPT_HEADER,0);
	curl_setopt($curl,CURLOPT_CUSTOMREQUEST,'GET');//需要要传送的内容
	curl_setopt($curl,CURLOPT_RETURNTRANSFER,1);
	$return_str = curl_exec($curl);
	curl_close($curl);
	return $return_str;
}

这个实例程序怎么写的,为什么这样写,我们都不用管它,尽管按官方的方法写就行

curl:就是在应用程序里面模拟浏览器去访问一些URL资源

//获取access_token
    public function get_access_token(){
        $appid = config('app.appid');
        $appsecret = config('app.appsecret');
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret;
        $res = http_Get($url);
        dump($res); exit;
        }

此处$appid   $appsecret 都是调用配置文件的值   URL用字符串拼接的方式       用http_Get请求的方法

6.png

测试得到错误信息是:IP不在白名单内,只需添加公网IP到白名单即可获取到access_token

7.png

由于微信公众平台的access_token有调用次数限制,服务号是10000次,个人号更少,每天调用完就没得用了,还会造成通讯浪费,对于固定密钥我们可以一个策略方法:将获取到的access_token缓存到本地目录中,当需要时直接从本地目录调用即可。

8.png

然而access_token只有2个小时的有效期,到期就更新,所以我们又要想到缓存周期为2小时内,当快过2小时时,再次从平台获取缓存

$res = json_decode($res,true);//json_decode对JSON数据进行解码,转换为PHP变量
Cache::set('access_token',$res['access_token'],$res['expires_in']-300);
//cache::set() 方法  有三个参数:1. 键 2. 值 3. 时间

前提要先导入方法:use think\facade\Cache;//导入门面模式缓存方法

9.png

同样我们也要把这个获取access_token的方法,封装到模型中:tp51/application/model/Weixin.php

//获取access_token
	public function access_token($iscache = true){
	$key = 'access_token'; //简化常量
        if(!$iscache){
            Cache::rm($key);
        }
		$data = Cache::get($key);
		if($data && $iscache){
			return $data;
		}
		$appid = config('app.appid');
    	$appsecret = config('app.appsecret');
    	$url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret;
    	$res = http_get($url);
    	$res = json_decode($res,true);
    	if(!isset($res['access_token'])){
    		return false;
    	}
    	Cache::set($key,$res['access_token'],($res['expires_in']-100));
    	return $res['access_token'];
	}

1. access_token($iscache = true)  默认要缓存 access_token

2. 判断是否要删除缓存

if(!$iscache){
           Cache::rm($key);
       }

3. 判断是否有缓存数据:如果有就直接从缓存拿数据  如果没有就从平台获取数据

$data = Cache::get($key);
		if($data && $iscache){
			return $data;
		}

而在控制器中直接用get_access_token()方法调用:

//获取access_token
    public function get_access_token(){
        $key = 'access_token';
        $access_token = Cache::get($key);
        if($access_token){
            return $access_token;
        }

        $appid = config('app.appid');
        $appsecret = config('app.appsecret');
        $url = 'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid='.$appid.'&secret='.$appsecret;
        $res = http_Get($url);
        $res = json_decode($res,true);
        Cache::set($cache_key,$res['access_token'],$res['expires_in']-600);
        return $res['access_token'];
    }

总结:其实整个过程就是:

1. 开发者网站发出接入请求,微信公众平台发出GET请求,signature timestamp nonce   echostr 等参数(这些参数由微信公众平台和开发者共同约定设置好的,只有两者知道),开发者网站与其对比匹配,其中将token、timestamp、nonce三个参数进行字典序排序,拼接,加密。。如果对比通过,就允许接入。对比不通过,就是非法请求,拒绝!

2. 微信公众平台为了通讯的安全性,设定了个口令,并且2小时更新一次,开发者网站后续功能操作,需要实时检验口令,口令通过才能继续通讯操作相关功能。。由于官方口令的限制性,我们又对口令采取了缓存本地并且每2小时内重新从微信平台获取口令一次的策略

以上两部完成了对接和验证功能,就可以继续后面的工作开发。。。

其实第三方平台对接都是这个策略,先互相校验设定好的口令(类似于江湖上的对暗号),暗号对上了,就可以开始互相交换相关数据,并开发相关功能操作。。。

声明:本文内容转载自脚本之家,由网友自发贡献,版权归原作者所有,如您发现涉嫌抄袭侵权,请联系admin@php.cn 核实处理。
全部评论
文明上网理性发言,请遵守新闻评论服务协议