php微信小程序授权登录,thinkphp 微信登录
源码也在我的开源代码库中给出
https://github.com/wulongtao/think-wxminihelper
下面结合框架框架来实现以下微信小程序的登录流程,这些流程是结合了官网和开源代码库的一个网站综合实现的
https://mp.weixin.qq.com/debug/wxadoc/dev/api/api-login.html?t=2017112#wxloginobject
https://github.com/cantoo/learning-wxapp/blob/master/微信小程序登录态验证流程。钔
我已经把登录流程做了一下简单的封装,你也可以直接使用设计者下载直接使用:
设计者需要xxh/think-wxminihelper
登录流程图参考了如下两个图:
按照上面的步骤,代码实现如下:
/**
* 登录
函数wxLogin(func) {
//调用登录接口
//1.小程序调用wx。登录得到代码。
wx.login({
成功:函数(资源){
var code=RES[ code ];
//2.小程序调用wx.getUserInfo得到原始数据,签名,加密数据。
wx.getUserInfo({
成功:函数(信息){
控制台。日志(信息);
var raw data=info[ raw data ];
var signature=info[ signature ];
var encrypt data=info[ encrypt data ];
var加密数据=info[加密数据];//注意是加密数据不是加密数据.坑啊
var iv=info[ iv ];
//3.小程序调用计算机网络服务器获取代币接口,传入代码、原始数据、签名、加密数据。
wx.request({
网址:常量。登录_网址,
数据:{
代码:代码,
原始数据:原始数据,
签名:签名,
encryptData : encryptData,
四:四,
“加密数据”:加密数据
成功:函数(资源){
if(res.statusCode!=200) {
wx.showModal({
标题: 登录失败
func== func func的类型(RES . data);
$code=input(code ,, htmlspecialchars _ decode );
$rawData=input(rawData ,, htmlspecialchars _ decode );
$signature=input(signature ,, htmlspecialchars _ decode );
$ encrypted data=input( encrypted data ,, htmlspecialchars _ decode );
$iv=输入( iv ,, htmlspecialchars _ decode );
* 4 .服务器调用微信提供的jsoncode2session接口获取openid,会话密钥,调用失败应给予客户端反馈
* , 微信侧返回错误则可判断为恶意请求,可以不返回。微信文档链接
* 这是一个超文本传送协议接口,开发者服务器使用登录凭证密码获取会话密钥和openid。其中会话密钥是对用户数据进行加密签名的密钥。
* 为了自身应用安全,会话密钥不应该在网络上传输。
* 接口地址: https://API。微信。QQ。 com/SNS/jscode 2会话? APPID=APPID SECRET=SECRET js _ code=JSCODE grant _ type=authorization _ code
$params=[
appid=$this- appid,
secret=$this- secret,
js_code=$code,
grant_type=$this- grant_type
$res=makeRequest($this- url,$ params);
if ($res[code]!==200 !isset($res[result]) !isset($ RES[ result ]){
返回JSON(ret _ message(请求令牌失败));
$ req data=JSON _ decode($ RES[ result ],true);
如果(!isset($ req data[ session _ key ]){
返回JSON(ret _ message(请求令牌失败));
$ session key=$ req data[ session _ key ];
* 5 .服务器计算签名,并与小程序传入的签名比较,校验签名的合法性,不匹配则返回签名不匹配的错误。不匹配的场景可判断为恶意请求,可以不返回。
* 通过调用接口(如wx.getUserInfo)获取敏感数据时,接口会同时返回原始数据、签名,其中签名=sha1(原始数据会话密钥)
* 将签名、原始数据、以及用户登录态发送给开发者服务器,开发者在数据库中找到该用户对应的会话密钥
* ,使用相同的算法计算出签名签名2,比对签名与签名2即可校验数据的可信度。
$signature2=sha1($rawData .$会话密钥);
if ($signature2!==$签名)返回ret _ message( signo match );
* 6.使用第四步返回的会话密钥解密加密数据,将解得的信息与原始数据中信息进行比较,需要完全匹配,
* 解得的信息中也包括openid,也需要与第四步返回的信息匹配。解密失败或不匹配应该返回客户相应错误。
* (使用官方提供的方法即可)
$ PC=new WXBizDataCrypt($ this-appid,$ session key);
$ errCode=$ PC-解密数据($加密数据,$iv,$ data);
if ($errCode!==0) {
返回JSON(ret _ message( encryptDataNotMatch ));
* 7.生成第三方第三届会议,用于第三方服务器和小程序之间做登录态校验。为了保证安全性,第三届会议应该满足:
*答.长度足够长。建议有2^128种组合,即长度为16B
* b .避免使用srand(当前时间)然后兰德()的方法,而是采用操作系统提供的真正随机数机制,比如Linux操作系统操作系统下面读取/dev/urandom设备
* c .设置一定有效时间,对于过期的第三次会议视为不合法
* 以$session3rd为密钥,会话密钥信息为值,写入服务器
$data=json_decode($data,true);
$ session 3 rd=randomFromDev(16);
$ data[ session 3 rd ]=$ session 3 rd;
缓存($session3rd,$data[openId].$会话密钥);
函数ret_message($message=) {
if ($message== )返回[result=0, message = ];
$ ret=lang($ message);
if (count($ret)!=2) {
return [result=-1, message=未知错误];
返回数组(
result=$ret[0],
message=$ret[1]
* 发起超文本传送协议(超文本传输协议的缩写)请求
* @param string $url访问路径
* @param array $params参数,该数组多于一个,表示为邮政
* @param int $expire请求超时时间
* @param array $extend请求伪造包头参数
* @ param stringhostIp主机的地址
* @返回数组返回的为一个请求状态,一个内容
函数makeRequest($url,$params=array(),$expire=0,$extend=array(),$hostIp= )
if (empty($url)) {
返回数组(“代码”=“100”);
$ _ curl=curl _ init();
$_header=array(
接受-语言:中文-中文,
连接:保持活动状态,
"缓存控制:无缓存"
//方便直接访问要设置宿主的地址
如果(!空($hostIp)) {
$ urlInfo=parse _ URL($ URL);
if(empty($ urlInfo[ host ]){
$urlInfo[host]=substr(DOMAIN,7,-1);
$ url= http://{ $ hostIp } { $ url }
}否则{
$ URL=str _ replace($ urlInfo[ host ],$hostIp,$ URL);
$ _ header[]= Host:{ $ urlInfo[ Host ]} ;
//只要第二个参数传了值之后,就是邮政的
如果(!empty($params)) {
curl_setopt($_curl,CURLOPT_POSTFIELDS,http _ build _ query($ params));
curl_setopt($_curl,CURLOPT_POST,true);
if (substr($url,0,8)==https://) {
curl_setopt($_curl,CURLOPT_SSL_VERIFYPEER,FALSE);
curl_setopt($_curl,CURLOPT_SSL_VERIFYHOST,FALSE);
curl_setopt($_curl,CURLOPT_URL,$ URL);
curl_setopt($_curl,CURLOPT_RETURNTRANSFER,true);
curl_setopt($_curl,CURLOPT_USERAGENT, API PHP CURL );
curl_setopt($_curl,CURLOPT_HTTPHEADER,$ _ header);
如果($expire 0){
curl_setopt($_curl,CURLOPT_TIMEOUT,$ expire);//处理超时时间
curl_setopt($_curl,CURLOPT_CONNECTTIMEOUT,$ expire);//建立连接超时时间
//额外的配置
如果(!empty($extend)) {
curl_setopt_array($_curl,$ extend);
$ result[ result ]=curl _ exec($ _ curl);
$ result[ CODE ]=curl _ getinfo($ _ curl,CURLINFO _ HTTP _ CODE);
$ result[ info ]=curl _ getinfo($ _ curl);
if ($result[result]===false) {
$ result[ result ]=curl _ error($ _ curl);
$ result[ code ]=-curl _ errno($ _ curl);
curl _ close($ _ curl);
返回$结果
* 读取/dev/urandom获取随机数
* @param $len
* @返回混合字符串
函数randomFromDev($len) {
$fp=@fopen(/dev/urandom , Rb );
$ result=
if ($fp!==假){
$结果. f=@ fread($ FP,$ len);
@ fclose($ FP);
其他
触发器_错误(无法打开/dev/urandom。);
//从二进制转换为字符串
$ result=base64 _ encode($ result);
//不删除任何全球资源定位器(Uniform Resource Locator)字符
$result=strtr($result,/,-_ );
返回substr($result,0,$ len);
}