记录一次开发微信登录网站并关注公众号功能的实现方法

Blog原文:一木林多 - https://www.l5v.cn/archives/95/

前言

近期在做一个项目,甲方爸爸要求平台系统接入微信登录的功能。我寻思着好像微信开发平台好像有这个功能(不是微信公众号平台是微信开发平台)。

但是我去微信开发平台看了一下,要接入网站着实有点麻烦。于是我就放弃了通过微信开发平台接入网站登录的功能。当我在百度上搜索相关解决方案的时候突然发现:可以利用公众号的一些功能来实现甲方爸爸的要求!


实现过程

1、首先需要准备一个认证的微信服务号(或者测试号)。测试账号的申请地址:

https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login

无需公众帐号、快速申请接口测试号直接体验和测试公众平台所有高级接口。

由于项目目前还是在本地localhost的开发环境,我在ngrok里面买了个frp用来访问外网。测试环境下如何安装ngrok的frp,请参考ngrok的官方文档。

我们先来写一个WeChat类以实现一些必要的基本操作。直接贴代码:


Class WeChat{

	protected $appid;
    protected $secret;
    protected $accessToken;

	function __construct(){
		$this->appid       = "公众号的appID";
		$this->secret      = "公众号的appsecret";
		$this->accessToken = $this->getAccessToken();
	}

	/***
	 * 获取access_token
	 * token的有效时间为2小时,这里可以做下缓存处理,提高效率
	 * @return
	 **/
	private function getAccessToken(){
		$url = "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=".$this->appid."&secret=".$this->secret;
		$res = json_decode($this->httpRequest($url),true);
		return $res['access_token'];
	}

	/***
	 * POST/GET请求
	 * @url 请求url
	 * @data POST数据
	 * @return
	 **/
	private function httpRequest($url, $data = ""){
		$curl = curl_init();
		curl_setopt($curl, CURLOPT_URL, $url);
		curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, FALSE);
		curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, FALSE);
		if(!empty($data)){	//判断是否为POST请求
			curl_setopt($curl, CURLOPT_POST, 1);
			curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
		}
		curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
		$output = curl_exec($curl);
		curl_close($curl);
		return $output;
	}

	/***
	 * 获取openID和unionId
	 * @code 微信授权登录返回的code
	 * @return
	 **/
	public function getOpenIdOrUnionId($code){
		$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$this->appid."&secret=".$this->secret."&code=".$code."&grant_type=authorization_code";
		$data = $this->httpRequest($url);
		return $data;
	}

	/***
	 * 通过openId获取用户信息
	 * @openId
	 * @return
	 **/
	public function getUserInfo($openId){
		$url  = "https://api.weixin.qq.com/cgi-bin/user/info?access_token=".$this->accessToken."&openid=".$openId."&lang=zh_CN";
		$data = $this->httpRequest($url);
		return $data;
	}

	/***
	 * 生成带参数的二维码
	 * @scene_id 自定义参数(整型)
	 * @return
	 **/
	public function getQrcode($scene_id){
		$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$this->accessToken;
		$data = array(
			"expire_seconds" => 3600, //二维码的有效时间(1小时)
			"action_name" => "QR_SCENE",
			"action_info" => array("scene" => array("scene_id" => $scene_id))
		);
		$result = $this->httpRequest($url, json_encode($data));
		return $result;
	}

	/***
	 * 生成带参数的二维码
	 * @scene_str 自定义参数(字符串)
	 * @return
	 **/
	public function getQrcodeByStr($scene_str){
		$url = "https://api.weixin.qq.com/cgi-bin/qrcode/create?access_token=".$this->accessToken;
		$data = array(
			"expire_seconds" => 3600, //二维码的有效时间
			"action_name" => "QR_STR_SCENE",
			"action_info" => array("scene" => array("scene_str" => $scene_str))
		);
		$result = $this->httpRequest($url, json_encode($data));
		return $result;
	}

	/**
	 * 换取二维码
	 * @ticket
	 * @return
	 */
	public function generateQrcode($ticket){
		return "https://mp.weixin.qq.com/cgi-bin/showqrcode?ticket=".$ticket;
	}
}

注意:不要直接复制粘贴!需要修改代码中的APPID和APPSECRET为自己的认证服务号的相关信息。

下一步,我们在前台获取用来登录的二维码。直接贴核心代码,具体细节优化靠自己了。


	header("Content-type:text/html;charset=utf-8");
	require_once('WeChat.class.php');	//加载上一步写的WeChat类文件
	$WeChat = new WeChat();
	$scene_str = "唯一的值";	//这里设置一个唯一值用于后续的登录回调判断
	$result = json_decode($WeChat->getQrcodeByStr($scene_str), true);
	$qrcode = $WeChat->generateQrcode($result['ticket']); //生成二维码
	echo "自定义参数:".$scene_str;
	echo "
$qrcode
\">"
; //$qrcode为二维码的具体链接 ?>

至此我们就能成功得到一个唯一的二维码提供给用户来扫描了。

下一步,当用户扫描了我们提供的二维码之后,公众号会向API发送一条消息。在处理公众号发送的回调消息之前,我们需要编写一个API并修改公众号后台的接口配置信息。

 <?php
    define("TOKEN", "123456");	//这里的TOKEN就是公众号后台接口的TOKEN,可以自定义
    $wechatObj = new wechatCallbackapiTest();
    $wechatObj->responseMsg();
    $wechatObj->valid();

    class wechatCallbackapiTest{
    	//响应公众号的请求
        public function valid() {
            $signature = $_GET["signature"];
            $timestamp = $_GET["timestamp"];
            $nonce = $_GET["nonce"];
            $echoStr = $_GET["echostr"];
            if($this->checkSignature($signature, $timestamp, $nonce)){
                echo $echoStr;
                exit;
            }
        }
        //签名验证方法
        private function checkSignature($signature, $timestamp, $nonce) {
            $token  = TOKEN;
            $tmpArr = array($token, $timestamp, $nonce);
            sort($tmpArr, SORT_STRING);
            $tmpStr = implode( $tmpArr );
            $tmpStr = sha1( $tmpStr );
            if($tmpStr == $signature){
                return true;
            }else{
                return false;
            }
        }
    	//获取公众号返回的信息
        public function responseMsg() {
            $postStr = file_get_contents('php://input');
            if (!empty($postStr)){
                $postObj = simplexml_load_string($postStr, 'SimpleXMLElement', LIBXML_NOCDATA);
                $postObj = json_encode($postObj);
                $postObj = json_decode($postObj);
    			//我们可以使用file_put_contents的方法输出公众号提交的内容
                file_put_contents("1.txt",json_encode($postObj));
                $fromUsername = $postObj->FromUserName;
                $toUsername = $postObj->ToUserName;
                $time = time();
    			//此处为登录验证的核心代码
    			//此处为登录验证的核心代码
    			//此处为登录验证的核心代码
    			//此处为登录验证的核心代码
    			//此处为登录验证的核心代码
                $textTpl = "
    							
    							
    							%s
    							
    							
    							0
    							";
                $msgType = "text";
    			//登录成功返回的文本
                $contentStr = "登录成功!";
                $resultStr = sprintf($textTpl, $fromUsername, $toUsername, $time, $msgType, $contentStr);
                echo $resultStr;
            }else {
                echo "";
                exit;
            }
        }
    }
    ?>

我们要对用户扫描二维码后公众号向API发送的消息进行分析。以下是经过json_encode处理过的消息。

{"ToUserName":"xxxxxxx","FromUserName":"xxxxxxxxxxx","CreateTime":"1599098138","MsgType":"event","Event":"SCAN","EventKey":"key123","Ticket":"xxxxxxxxx"}

其中ToUserName指的是公众号的账号,FromUserName指的是用户的唯一标识,Event有两个值,subscribe指首次关注,scan为扫码(即已经关注过了),EventKey即我们在前面定义的scene_str唯一值。

实现到这个步骤,总有思路如何实现登录验证的核心代码了吧!?

具体验证代码不好贴出,在这里提供一个完整思路:当用户扫描二维码时,公众号向API发送消息,API获取用户的唯一标识并在数据库中查找。如果查有则登录,查无则无法登录(查无则提示是否注册之类的)。

你可能感兴趣的:(折腾,微信)