(二)網頁受權獲取用戶基本信息

在公衆號的配置過程當中,許多開發者會在菜單中加入HTML5頁面,有時在頁面內須要訪問頁面的用戶信息,此時就須要網頁受權獲取用戶基本信息javascript

PS:本博文所闡述的微信開發基於Yii2.0框架php

 

一、設置受權回調域名:開發 ---> 接口權限html

  找到「網頁受權獲取用戶基本信息」,點擊後面對應的「修改」,在彈框響應位置填寫受權回調域名便可,此處的域名不須要加http://  (關於網頁受權回調域名的說明詳情可參考公衆平臺開發者文檔)html5

 

 

二、獲取受權java

  關於OAuth2.0博主參考的是方倍工做室的博文http://www.cnblogs.com/txw1958/p/weixin71-oauth20.html(PS:方倍是一個微信開發大神,其中的微信開發內容仍是比較詳細的,推薦參考),其中詳細剖析了微信官方文檔的相關內容,也提供了獲取受權的更詳細思路和方案。算法

  實際上,獲取用戶信息的關鍵在於獲取用戶的openid。博主想要實現用戶點擊公衆號菜單打開頁面便可自動受權,從而針對該用戶進行數據庫操做,因而有下面兩種方式: 數據庫

  (1)利用自定義菜單請求受權頁面express

    自定義菜單後面會單獨寫一篇博文,在這裏先簡述一下經過自定義菜單進行受權,該方法須要高級接口權限,且侷限於關注公衆號的用戶直接從菜單進入頁面。json

 1 $menu = '{
 2   "button":[
 3     {
 4       "type": "view",
 5       "name": "商城",
 6       "url": "https://open.weixin.qq.com/connect/oauth2/authorize?appid=xxx&redirect_uri=http://tx.heivr.com/index.php&response_type=code&scope=snsapi_base&state=1#wechat_redirect"
 7     },
 8 
 9     {
10       "name":"快遞服務",
11       "sub_button":[
12         {
13            "type":"click",
14            "name":"發快遞",
15            "key":"express"
16         },
17         {
18            "type":"click",
19            "name":"快遞查詢",
20            "key":"ww"
21         }
22       ]
23     },
24   ]
25 }';

  須要受權的view直接在url處填寫微信提供的受權請求地址,其中:api

  • appid:填寫微信公衆平臺基本配置中的AppID;
  • redirect_uri:填寫受權完成後跳轉的頁面地址,即本身的html5頁面;
  • state:跳轉至回調頁面所帶參數;
  • response_type:網頁受權的兩種scope,微信官方文檔中說明以下:
    1、以snsapi_base爲scope發起的網頁受權,是用來獲取進入頁面的用戶的openid的,而且是靜默受權並自動跳轉到回調頁的。用戶感知的就是直接進入了回調頁(每每是業務頁面)
    二、以snsapi_userinfo爲scope發起的網頁受權,是用來獲取用戶的基本信息的。但這種受權須要用戶手動贊成,而且因爲用戶贊成過,因此無須關注,就可在受權後獲取該用戶的基本信息。

    按照此方法點擊「商城」便可接收到返回的openid,繼而進行下一步用戶信息的獲取。 

 

  (2)利用JS自動請求受權頁面

    這個方法相對而言比較笨拙,步驟略複雜,但目前能解決需求尚未研究簡化方法,且因爲頁面的跳轉多數狀況下訪問頁面的時間會增長,但相比於前一個方法,該方法能夠獲取到非關注用戶的基本信息。有些程序可能涉及到頁面分享,程序沒有強制關注但其餘用戶經過分享直接進入頁面也須要記錄用戶信息,此時能夠考慮該方法。(微信開發相關的代碼博主封裝成工具類調用,這裏先貼用到的部分,之後整理完成會所有貼出來並附下載連接)

    該方法的思路爲:js請求連接獲取code ---> 利用code換取openid ---> 獲得用戶基本信息

        a. 編輯配置

        爲了方便把用到的一些微信參數單獨寫入一個類,方便修改添加及調用

 1 <?php
 2 namespace common\tools\wechat;
 3 
 4 /**
 5  * 微信請求相關配置類庫
 6  */
 7 class ConfigTool {
 8 
 9     /**
10      * 微信配置參數
11      * @return array 配置參數
12      */
13     public function setConfig() {
14 
15         // 用於驗證微信接口配置信息的Token,能夠任意填寫
16         $config['token'] = '本身的token';
17          
18         // appID
19         $config['appid'] = '本身的appid';
20          
21         // appSecret
22         $config['secret'] = '本身的secret';
23          
24         // 回調連接地址
25         $config['redirect_uri'] = 'http://tx.heivr.com/index.php?';
26          
27         // 是否以 HTTPS 安全協議訪問接口
28         $config['https_request'] = false;
29          
30         // 受權做用域,snsapi_base (不彈出受權頁面,直接跳轉,只能獲取用戶openid),
31         // snsapi_userinfo (彈出受權頁面,可經過openid拿到暱稱、性別、所在地。而且,
32         // 即便在未關注的狀況下,只要用戶受權,也能獲取其信息)
33         $config['scope'] = 'snsapi_userinfo';
34          
35         // 語言
36         $config['lang'] = 'zh_CN'; // zh_CN 簡體,zh_TW 繁體,en 英語
37          
38         // 微信公衆帳戶受權地址
39         $config['mp_authorize_url'] = 'https://api.weixin.qq.com/cgi-bin/token';
40         // 微信公衆帳戶js臨時票據地址
41         $config['jsapi_ticket_url'] = 'https://api.weixin.qq.com/cgi-bin/ticket/getticket';
42         // 受權地址
43         $config['authorize_url'] = 'https://open.weixin.qq.com/connect/oauth2/authorize';
44         // 獲取access token 的地址
45         $config['access_token_url'] = 'https://api.weixin.qq.com/sns/oauth2/access_token';
46         // 刷新 token 的地址
47         $config['refresh_token_url'] = 'https://api.weixin.qq.com/sns/oauth2/refresh_token';
48         // 獲取用戶信息地址
49         $config['userinfo_url'] = 'https://api.weixin.qq.com/sns/userinfo';
50         // 驗證access token
51         $config['valid_token_url'] = 'https://api.weixin.qq.com/sns/auth';
52         // 上傳臨時素材地址
53         $config['media_temp_upload_url'] = 'https://api.weixin.qq.com/cgi-bin/media/upload?';
54         // 上傳永久素材地址
55         $config['media_forever_upload_url'] = 'https://api.weixin.qq.com/cgi-bin/material/add_material?';
56 
57         return $config;
58         
59     }
60 }

 

            b. https請求工具

 1 <?php
 2 namespace common\tools;
 3 
 4 /**
 5  * https請求相關類庫
 6  */
 7 class HttpsTool {
 8 
 9     const TIMEOUT = 5;                        // 設置超時時間
10 
11     private $ch;                                // curl對象
12 
13     /**
14      * 發送curl請求,並獲取請求結果
15      * @param string 請求地址
16      * @param array 若是是post請求則須要傳入請求參數
17      * @param string 請求方法,get 或者 post, 默認爲get
18      * @param bool 是否以https協議請求
19      */
20     public function send_request($requests, $params = null, $method = 'get', $https = true) {
21         // 以get方式提交
22         if ($method == 'get') {
23             if($params){
24                 $request = $requests . $this->create_url($params);
25             }else{
26                 $request = $requests;
27             }
28         }else{
29             $request = $requests;
30         }
31 
32         $this->ch = curl_init($request);
33         curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);// 設置不顯示結果,儲存入變量
34         curl_setopt($this->ch, CURLOPT_TIMEOUT, self::TIMEOUT); // 設置超時限制防止死循環
35 
36         // 判斷是否以https方式訪問
37         if ($https) {
38             curl_setopt($this->ch, CURLOPT_SSL_VERIFYPEER, 0); // 對認證證書來源的檢查
39             curl_setopt($this->ch, CURLOPT_SSL_VERIFYHOST, 0); // 從證書中檢查SSL加密算法是否存在
40         }
41 
42         if ($method == 'post') {        // 以post方式提交
43             //curl_setopt($this->ch, CURLOPT_SAFE_UPLOAD, false);     //php 5.6文件上傳必加內容,5.4不須要
44             curl_setopt($this->ch, CURLOPT_POST, 1); // 發送一個常規的Post請求
45             curl_setopt($this->ch, CURLOPT_POSTFIELDS, $params); // Post提交的數據包
46             curl_setopt($this->ch, CURLOPT_RETURNTRANSFER, 1);
47         }
48         
49         $tmpInfo = curl_exec($this->ch); // 執行操做
50         if (curl_errno($this->ch)) {
51             echo 'Errno:'.curl_error($this->ch);//捕抓異常
52         }
53         curl_close($this->ch); // 關閉CURL會話
54         //var_dump($tmpInfo);exit;
55         return $tmpInfo; // 返回數據
56     }
57 
58     /**
59      * 生成url
60      */
61     public function create_url($data) {
62         $temp = '?';
63         foreach ($data as $key => $item) {
64             $temp = $temp . $key . '=' . $item . '&';
65         }
66         return substr($temp, 0, -1);
67     }
68 }
關於curl_setopt($this->ch, CURLOPT_SAFE_UPLOAD, false)會在微信圖片資源上傳博文中詳細講述它出現的心酸史,這裏暫時用不到,不作解釋

 

             c. 受權基類

 1 <?php  
 2 namespace common\tools\wechat;
 3 
 4 use common\tools\wechat\ConfigTool;
 5 use common\tools\HttpsTool;
 6 /**
 7 * Weixin_oauth 類庫
 8 */
 9 class OauthTool {
10 
11     public $conf;
12 
13     public function __construct(){
14         $re = new ConfigTool;               
15         $this->conf = $re->setConfig();
16     } 
17 
18     /**
19      * 生成用戶受權的地址
20      * @param string 自定義須要保持的信息
21      * @param sting 請求的路由
22      * @param bool 是不是經過公衆平臺方式認真
23      */
24     public function authorize_addr($route, $state='', $mp=false) {
25 
26         if ($mp) {
27             $data = [
28                 'appid' => $this->conf['appid'],
29                 'secret' => $this->conf['token'],
30                 'grant_type' => 'client_credential'
31             ];
32             $url = $this->conf['mp_authorize_url'];
33         } else {
34             $data = [
35                 'appid' => $this->conf['appid'],                                //公衆號惟一標識
36                 'redirect_uri' => urlencode($this->conf['redirect_uri'] . $route),       //受權後重定向的回調連接地址
37                 'response_type' => 'code',                                      //返回類型,此處填寫code
38                 'scope'=>$this->conf['scope'],                                  //應用受權做用域
39                 'state'=>$state,                                                //重定向後帶上state參數,開發者能夠填寫任意參數
40                 '#wechat_redirect'=>''                                          //直接在微信打開連接,可不填,作頁面302重定向時必須帶此參數
41             ];
42             $url = $this->conf['authorize_url'];
43         }
44         
45         $send = new HttpsTool;
46         //var_dump($url . $send->create_url($data));exit;
47         return  $url . $send->create_url($data);
48     }
49 
50     /**
51      * 獲取 access token
52      * @param string 用於換取access token的code,微信提供
53      */
54     public function access_token($code) {
55 
56         $data = [
57             'appid' => $this->conf['appid'],
58             'secret' => $this->conf['secret'],
59             'code' => $code,
60             'grant_type' => 'authorization_code'
61         ];
62         // 生成受權url
63         $url = $this->conf['access_token_url'];
64         
65         $send = new HttpsTool;
66         return $send->send_request($url, $data);
67     }
68 
69     /**
70      * 獲取用戶信息
71      * @param string access token
72      * @param string 用戶的open id
73      */
74     public function userinfo($token, $openid) {
75 
76         $data = [
77             'access_token' => $token,
78             'openid' => $openid,
79             'lang' => $this->conf['lang']
80         ];
81         // 生成受權url
82         $url = $this->conf['userinfo_url'];
83 
84         $send = new HttpsTool;
85         return $send->send_request($url, $data);
86     }
87 
88 }

             d. 受權基類調用及用戶數據處理(在控制器調用前,先對用戶數據存入或更新)

 1 <?php
 2 namespace wechat\controllers\classes;
 3 
 4 use common\tools\wechat\OauthTool;
 5 use common\models\User;
 6 use common\tools\EmojiTool;
 7 
 8 /**
 9  * 微信用戶基本信息獲取
10  */
11 class UserinfoClass {
12  
13     /**
14      * 用戶受權並獲取code 
15      * @return string 用戶code
16      */
17     public function getCode($route, $state){
18 
19         $re = new OauthTool;
20         $request = $re->authorize_addr($route, $state);
21         $code = isset($_GET['code']) ? $_GET['code'] : '';
22         
23         return [$request,$code];
24     }
25     
26     /**
27      * 獲取用戶信息並寫入數據庫(以後加參數傳給code)
28      */
29     public function info($code) {
30         $re = new OauthTool;
31         //獲取access token
32         $access = $re->access_token($code);
33         $token = json_decode($access,true);
34         //header("Content-type: text/html; charset=gbk"); 
35         //獲取用戶信息
36         if(count($token) != 2) {
37             $response = $re->userinfo($token['access_token'], $token['openid']);
38             $user = json_decode($response,true);
39             //用戶暱稱轉換
40             //$user['nickname'] = EmojiTool::emoji_trans($user['nickname']);
41 
42             if($model = User::findOne(['openid' => $user['openid'] ])) {            //用戶已存在更新數據
43                 $model->attributes = $user;
44                 $model->modify_time = time();
45                 $model->save(false);
46             }else{                                                                  //用戶不存在寫入
47                 $model = new User;
48                 $model->attributes = $user;
49                 $model->create_time = time();
50                 $model->save(false);
51             }
52         }
53         return isset($model->id) ? $model->id : '';
54     }
55     
56 }

             e. 控制器調用(這裏只貼其中一個方法)

 1 /**
 2      * 產品列表
 3      * @return object 全部可用產品信息
 4      */
 5     public function actionIndex(){
 6         //判斷頁面是否自動刷新
 7         if(isset($_GET['state'])) {
 8             $refresh = 0;
 9         }else{
10             $refresh = 1;
11         }
12 
13         //獲取用戶code
14         $user = new UserinfoClass;
15         $request = $user->getCode('r=store/index', 1);
16 
17         //該用戶userid
18         $userid = $user->info($request[1]);
19 
20         $model = new Product;
21         $list = $model->find()->where(['status' => 1])->all();
22 
23         return $this->render('index',['list' => $list, 'refresh' => $refresh, 'userid' => $userid, 'request' => $request]);
24     }

             程序要求用戶打開產品列表即獲取用戶信息並存入數據庫,其中設計了幾個變量做用以下:

        $refresh:判斷頁面是否刷新,因爲首次打開頁面未進行oauth驗證時才自動請求驗證,避免反覆刷新,這裏用回調的state參數做爲判斷依據且設state=1(如有特定參數須要可將state賦值爲所需值);

        $request:即爲驗證請求地址

        f. 視圖自動刷新

        只須要在視圖中添加如下js代碼便可

 1 <script type="text/javascript">
 2 
 3     //自動請求獲取code
 4     $(function(){
 5         var refresh = <?= $refresh; ?>;
 6         var request = '<?= $request[0]; ?>';
 7         if(refresh == 1){
 8             console.log(1);
 9             location = request;
10         }
11     });
12 </script>

 

特此聲明:相關文章均爲查閱資料、閱讀大神博文後結合實際開發狀況遇到的問題整理而成,能找到原博的必會署名,找不到原博而引用的內容還望原博主海涵

相關文章
相關標籤/搜索