在初學微信開發的時候因爲沒有經驗,再加上微信的官方文檔不夠清晰,致使看完文檔以後只剩下」抓瞎「,根本不知道微信開發是怎樣一個流程,也不知道如何開始,因而不得不去查閱第三方博客。
後來終於完成了微信公衆號和服務器的對接,實現了網頁受權,而且,用戶能夠直接點擊公衆號下方的按鈕,自動獲取OpenID登陸,不用再進行傳統的手動登陸了。網頁受權自動登陸,也就是本文須要實現的功能。php
網頁受權,就是用戶向公衆號受權,讓開發者經過此用戶的惟一識別碼(OpenID)得到此用戶的身份。通俗的講,就是用戶給開發者提交一個「身份證」,讓開發者知道當前正在訪問的用戶是誰。微信官方文檔——網頁受權html
一般狀況下,用戶是直接訪問開發者的服務器,獲取服務器返回的數據。因爲http協議是匿名的,在這種狀況下,服務器不知道當前訪問的用戶是誰,識別用戶身份的惟一辦法就是經過Cookie和Session,然而,因爲Cookie具備時效性,用戶仍是在一些狀況下仍是要手動登陸。
直接鏈接開發者服務器的時序圖:
(圖片出自夢雲智軟件開發團隊ThinkPHP5.1入門實例教程)web
而微信網頁受權的優點在於,能夠給每個微信帳號分配一個惟一的識別碼(也就是OpenID),經過這個識別碼,微信服務器就能夠知道當前登陸的用戶是誰,而後把此用戶的信息告訴開發者的服務器,這樣開發者就獲取了用戶身份,而且能夠實現把用戶在網站的帳號和用戶的微信號綁定起來,這樣,之後用戶經過微信登陸網站時就再也不用手動登陸了。
經過鏈接微信服務器獲取用戶信息的時序圖:
thinkphp
微信的公衆號有兩種——訂閱號和服務號,訂閱號一般適用於我的(自媒體、學校的小型組織),服務號適用於企業。訂閱號沒有網頁受權的權限,服務號只有在認證以後可使用網頁受權。微信接口權限說明
json
因此,只有訂閱號的小夥伴能夠洗洗睡了...但是做爲開發者,若是出於學習的目的想嘗試網頁受權的話,能夠去申請微信測試號,測試號具備全部的微信接口權限。申請接口測試號api
本文假設用戶已經完成了公衆號和服務器的綁定,設置好了服務器地址。
服務器
在公衆號剛剛建立的時候,主頁面是這樣的,只有聊天框:
而咱們但願是這樣:
微信
那麼,怎麼定義這些按鈕呢?微信爲咱們提供了一個很好的接口測試工具,咱們能夠利用這個工具來定義按鈕。
首先選擇基礎支持,獲取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"{}刪掉,否則會報錯。
點擊建立以後,刷新公衆號,按鈕已經出現了。
微信開發
咱們仍是要拿出這張時序圖
實際上已經在剛纔完成了,就是在公衆號按鈕中設置連接,讓用戶經過按鈕訪問ThnkPHP的某個方法。
//你的微信公衆號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
//回調到這個方法 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進行登陸操做,實現自動登陸,登陸以後把用戶請求的網頁返回給用戶了。
<?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'; //跳轉內容請根據實際狀況本身編寫 } }
<?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; } }
整個過程的核心,是那張時序圖