共计 6319 个字符,预计需要花费 16 分钟才能阅读完成。
零、前言
在初学微信开发的时候由于没有经验,再加上微信的官方文档不够清晰,导致看完文档之后只剩下”抓瞎“,根本不知道微信开发是怎样一个流程,也不知道如何开始,于是不得不去查阅第三方博客。
后来终于完成了微信公众号和服务器的对接,实现了网页授权,并且,用户可以直接点击公众号下方的按钮,自动获取 OpenID 登录 ,不用再进行传统的 手动登录 了。网页授权自动登录,也就是本文需要实现的功能。
一、原理
1,什么是网页授权?
网页授权,就是用户向公众号授权,让开发者通过此用户的 唯一识别码 (OpenID)获得此用户的身份。通俗的讲,就是 用户给开发者提交一个“身份证”,让开发者知道当前正在访问的用户是谁。微信官方文档——网页授权
2,使用网页授权的优势
通常情况下,用户是 直接访问开发者的服务器 ,获取服务器返回的数据。由于 http 协议是匿名的,在这种情况下,服务器不知道当前访问的用户是谁,识别用户身份的唯一办法就是通过Cookie 和Session,然而,由于 Cookie 具有时效性,用户还是在一些情况下还是要手动登录。
直接连接开发者服务器的时序图:
(图片出自梦云智软件开发团队 ThinkPHP5.1 入门实例教程)
而微信网页授权的优势在于,可以给每一个微信账号分配一个唯一的识别码(也就是 OpenID),通过这个识别码,微信服务器就可以知道当前登录的用户是谁,然后把此用户的信息告诉开发者的服务器,这样开发者就获取了用户身份,并且可以实现把用户在网站的账号和用户的微信号绑定起来,这样,以后用户通过微信登录网站时就再也 不用手动登录 了。
通过连接微信服务器获取用户信息的时序图:
3,什么情况下可以使用网页授权?
微信的公众号有两种——订阅号和服务号,订阅号通常适用于个人(自媒体、学校的小型组织),服务号适用于企业。订阅号没有网页授权的权限,服务号只有在认证之后可以使用网页授权。微信接口权限说明
所以,只有订阅号的小伙伴可以洗洗睡了 … 可是作为开发者,如果出于学习的目的想尝试网页授权的话,可以去申请微信测试号,测试号具有所有的微信接口权限。申请接口测试号
二、操作
本文假设用户已经完成了公众号和服务器的绑定,设置好了服务器地址。
1,设置公众号的按钮
在公众号刚刚创建的时候,主页面是这样的,只有聊天框:
而我们希望是这样:
那么,怎么定义这些按钮呢?微信为我们提供了一个很好的接口测试工具,我们可以利用这个工具来定义按钮。
首先选择基础支持,获取 AccessToken(这个是公众号的全局 AccessToken 而不是网页授权的 AccessToken)
填入正确的 APPID 和 Secret 之后,下面返回了 AccessToken 有效期 7200 秒。
复制这串字符,然后把接口切换到 自定义菜单查询接口 ,把刚刚获取的 token 粘贴进去。
如果这个公众号之前设置过按钮,就会出现所以按钮的代码:
{
"menu": {
"button": [
{
"name": "学生菜单",
"sub_button": [
{
"type": "view",
"name": "学生主页",
"url": "http://awjdjsz.jincheng4917.cn/index/WxIndex/page",
"sub_button": []},
{
"type": "view",
"name": "课程查询",
"url": "http://awjdjsz.jincheng4917.cn/index/WxIndex/course",
"sub_button": []},
{
"type": "view",
"name": "成绩查询",
"url": "http://awjdjsz.jincheng4917.cn/index/WxIndex/score",
"sub_button": []},
{
"type": "view",
"name": "个人信息",
"url": "http://awjdjsz.jincheng4917.cn/index/WxIndex/info",
"sub_button": []}
]
},
{
"name": "教师菜单",
"sub_button": [
{
"type": "view",
"name": "教师主页",
"url": "http://awjdjsz.jincheng4917.cn/index/WxIndex/tpage",
"sub_button": []},
{
"type": "view",
"name": "课程管理",
"url": "http://awjdjsz.jincheng4917.cn/index/WxIndex/tcourse",
"sub_button": []},
{
"type": "view",
"name": "成绩录入",
"url": "http://awjdjsz.jincheng4917.cn/index/WxIndex/tgrade",
"sub_button": []}
]
},
{
"type": "scancode_push",
"name": "扫码进入课堂",
"key": "rselfmenu_0_1",
"sub_button": []}
]
}
}
如果是一次设置,可以把上面的代码加以改造,然后把接口改为 自定义菜单创建接口 ,然后输入改好的代码。
注意:查询结果的代码用于创建按钮时,必须把第二行和倒数第二行的 “menu”{} 删掉,不然会报错。
点击创建之后,刷新公众号,按钮已经出现了。
三、代码分析
我们还是要拿出这张时序图
1,第一阶段
实际上已经在刚才完成了,就是在公众号按钮中设置链接,让用户通过按钮访问 ThnkPHP 的某个方法。
2,第二阶段
// 你的微信公众号 appid
protected $appid='wx4b4890b3f8c0ada5';
// 你的微信公众号 secret
protected $appsecret = '7634c6e2889e0d366e4ff2e58bc520fa';
// 用户访问这个方法
public function weChatAccredit($buttonType) {
// 这个地址是回调地址
$url = 'http://'.$_SERVER['HTTP_HOST'].'/index/WxIndex/getChatInfo';
// 调用方法
accredit($url,$buttonType);
}
// 用于访问服务器的方法
public function accredit($redirect_url,$state){
// 拼接 URL
$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect_uri={$redirect_url}&response_type=code&scope=snsapi_userinfo&state={$state}#wechat_redirect";
// 重定向
$this->redirect($url);
}
到目前为止,用户重定向访问微信服务器之后,就会带着 code 回调开发者服务器,因此我们就要拿 code 继续换取 AccessToken
3,第三阶段
// 回调到这个方法
public function getChatInfo(){$we_chat = new WxController();// 实例化微信类
$code = $_GET['code']; // 获取跳转后的 code
$state = $_GET['state']; // 获取 state
$access_token = getAccessToken($code); // 根据 code 获取 token
根据 access_token 和 openid 获取到用户信息
$we_chat_user_info = getWeChatUserInfo($access_token['access_token'],$access_token['openid']);
$this->gogogo($state,$access_token["openid"]);
public function getAccessToken($code){$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appid}&secret={$this->appsecret}&code={$code}&grant_type=authorization_code";
$res = file_get_contents($url); // 获取文件内容或获取网络请求的内容
$access_token = json_decode($res,true);
return $access_token;
}
public function getWeChatUserInfo($access_token,$openid){$url = "https://api.weixin.qq.com/sns/userinfo?access_token={$access_token}&openid={$openid}&lang=zh_CN";
$output = file_get_contents($url);
$weChatUserInfo = json_decode($output,true);
return $weChatUserInfo;
}
到此,开发者服务器已经成功获取到用户信息,然后就可以自行编写 gogogo()这个方法,通过 OpenID 进行登录操作,实现自动登录,登录之后把用户请求的网页返回给用户了。
四、附上完整代码
1,appindexcontrollerWxindexController.php
<?php
namespace app\index\controller;
use app\index\controller\WxController;
use app\index\controller\StudentController;
use app\index\controller\LoginController;
use app\index\model\Student;
use app\index\model\Teacher;
use app\index\model\Term;
class WxindexController extends WxController {
public static $openIdTest = 'openIdTest';
public static $page = 'page';
public static $score = 'score';
public static $course = 'course';
public static $info = 'info';
public function page(){ // 跳转到主页
$this->weChatAccredit($this::$page);
}
public function course(){ // 跳转到课程查询
$this->weChatAccredit($this::$course);
}
public function score(){ // 跳转到成绩查询
$this->weChatAccredit($this::$score);
}
public function info(){ // 跳转到个人信息
$this->weChatAccredit($this::$info);
}
/**
* 微信按钮跳转授权
*/
public function weChatAccredit($buttonType) {$url = 'http://'.$_SERVER['HTTP_HOST'].'/index/WxIndex/getChatInfo';
$we_chat = new WxController(); // 实例化类
$we_chat->accredit($url,$buttonType); // 调用方法
}
/**
* 获取微信用户信息
*/
public function getChatInfo(){$we_chat = new WxController();// 实例化微信类
$code = $_GET['code']; // 获取跳转后的 code
$state = $_GET['state']; // 获取 state
$access_token = $we_chat->getAccessToken($code); // 根据 code 获取 token
$this->gogogo($state,$access_token["openid"]);
}
// 用于跳转到各个方法,传入 OpenId 和要跳转的方法
public function gogogo($state,$openid)
{Student::login($openid);
return 'success';
// 跳转内容请根据实际情况自己编写
}
}
2,appindexcontrollerWxController.php
<?php
namespace app\index\controller;
use think\Controller;
class WxController extends Controller{
protected $appid='xxxxxxx';
// 你的微信公众号 appid
protected $appsecret = 'xxxxxxxx';
// 你的微信公众号 secret
// 拼接 URL
public function accredit($redirect_url,$state){$url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appid}&redirect_uri={$redirect_url}&response_type=code&scope=snsapi_userinfo&state={$state}#wechat_redirect";
$this->redirect($url);
}
/**
* @param $code
* @return bool|string
*/
public function getAccessToken($code){$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->appid}&secret={$this->appsecret}&code={$code}&grant_type=authorization_code";
$res = file_get_contents($url); // 获取文件内容或获取网络请求的内容
$access_token = json_decode($res,true);
return $access_token;
}
/**
* 获取用户信息
* @param unknown $openid
* @param unknown $access_token
* @return unknown
*/
public function getWeChatUserInfo($access_token,$openid){$url = "https://api.weixin.qq.com/sns/userinfo?access_token={$access_token}&openid={$openid}&lang=zh_CN";
$output = file_get_contents($url);
$weChatUserInfo = json_decode($output,true);
return $weChatUserInfo;
}
}
五,总结
整个过程的核心,是那张时序图