微信授權登錄並獲取用戶信息接口開發

  近排在做微信接口開發,所以總結一下微信授權登錄並獲取用戶信息 這個接口的開發流程。

一、首先你的微信公衆號要獲得相應的AppID和AppSecret,申請微信登錄且通過審覈後,纔可開始接入流程。

二、授權流程

1、流程說明

 

(1). 第三方發起微信授權登錄請求,微信用戶允許授權第三方應用後,微信會拉起應用或重定向到第三方網站,並且帶上授權臨時票據code參數;

 

 

(2). 通過code參數加上AppID和AppSecret等,通過API換取access_token;

 

(3). 通過access_token進行接口調用,獲取用戶基本數據資源或幫助用戶實現基本操作。

2、獲取access_token時序圖:

三、開發(我的用是CI框架,其實用什麼框架都一樣,MVC模式就行了)

1、請求CODE

  weixin.php

複製代碼
 1 <?php
 2     class weixinController extends CI_Controller {
 3         public $userInfo;
 4         public $wxId;
 5 
 6 
 7         public function __construct(){
 8             parent::__construct();
 9 
10             //只要用戶一訪問此模塊,就登錄授權,獲取用戶信息
11             $this->userInfo = $this->getWxUserInfo();
12         }
13     
14 
15         /**
16          * 確保當前用戶是在微信中打開,並且獲取用戶信息
17          *
18          * @param string $url 獲取到微信授權臨時票據(code)回調頁面的URL
19          */
20         private function getWxUserInfo($url = '') {
21             //微信標記(自己創建的)
22             $wxSign = $this->input->cookie('wxSign');
23             //先看看本地cookie裏是否存在微信唯一標記,
24             //假如存在,可以通過$wxSign到redis裏取出微信個人信息(因爲在第一次取到微信個人信息,我會將其保存一份到redis服務器裏緩存着)
25             if (!empty($wxSign)) {
26                 //如果存在,則從Redis裏取出緩存了的數據
27                 $userInfo = $this->model->redisCache->getData("weixin:sign_{$wxSign}");
28                 if (!empty($userInfo)) {
29                     //獲取用戶的openid
30                     $this->wxId = $userInfo['openid'];
31                     //將其存在cookie裏
32                     $this->input->set_cookie('wxId', $this->wxId, 60*60*24*7);
33                     return $userInfo;
34                 }
35             }
36 
37             //獲取授權臨時票據(code)
38             $code = $_GET['code'];
39             if (empty($code)) {
40                 if (empty($url)) {
41                     $url = rtirm($_SERVER['QUERY_STRING'], '/');
42                     //到WxModel.php裏獲取到微信授權請求URL,然後redirect請求url
43                     redirect($this->model->wx->getOAuthUrl(baseUrl($url)));
44                 }
45             }
46 
47 
48         }
49 
50 
51 
52 
53 
54 
55 
56 
57 
58 
59 
60 
61     }
62 ?>
複製代碼

   Wxmodel.php

複製代碼
 1 <?php
 2     class WxModel extends ModelBase{
 3         public $appId;
 4         public $appSecret;
 5         public $token;
 6 
 7         public function __construct() {
 8             parent::__construct();
 9 
10             //審覈通過的移動應用所給的AppID和AppSecret
11             $this->appId = 'wx0000000000000000';
12             $this->appSecret = '00000000000000000000000000000';
13             $this->token = '00000000';
14         }
15 
16         /**
17          * 獲取微信授權url
18          * @param string 授權後跳轉的URL
19          * @param bool 是否只獲取openid,true時,不會彈出授權頁面,但只能獲取用戶的openid,而false時,彈出授權頁面,可以通過openid獲取用戶信息
20          *   
21         */
22        public function getOAuthUrl($redirectUrl, $openIdOnly, $state = '') {
23         $redirectUrl = urlencode($redirectUrl);
24         $scope = $openIdOnly ? 'snsapi_base' : 'snsapi_userinfo';
25         $oAuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appId}&redirect_uri={$redirectUrl}&response_type=code&scope=$scope&state=$state";
26         return $oAuthUrl;
27        }
複製代碼

 

這裏附上請求參數說明和返回值說明

  請求參數說明:

 

  響應返回值說明:

 

  當請求成功,會redirect到請求參數中的redirect_uri的值中去,其實又回到weixin.php的$this->userInfo = $this->getWxUserInfo();這行去,然後再一次進入到getWxUserInfo()方法,此時

1
2
//獲取授權臨時票據(code)
$code $_GET['code'];

 這行也已經能獲取得到code的值了。接着進行第二步。

 

2、通過code獲取access_token

  weixin.php

複製代碼
 1 <?php
 2     class weixinController extends CI_Controller {
 3         public $userInfo;
 4         public $wxId;
 5 
 6 
 7         public function __construct(){
 8             parent::__construct();
 9 
10             //只要用戶一訪問此模塊,就登錄授權,獲取用戶信息
11             $this->userInfo = $this->getWxUserInfo();
12         }
13     
14 
15         /**
16          * 確保當前用戶是在微信中打開,並且獲取用戶信息
17          *
18          * @param string $url 獲取到微信授權臨時票據(code)回調頁面的URL
19          */
20         private function getWxUserInfo($url = '') {
21             //微信標記(自己創建的)
22             $wxSign = $this->input->cookie('wxSign');
23             //先看看本地cookie裏是否存在微信唯一標記,
24             //假如存在,可以通過$wxSign到redis裏取出微信個人信息(因爲在第一次取到微信個人信息,我會將其保存一份到redis服務器裏緩存着)
25             if (!empty($wxSign)) {
26                 //如果存在,則從Redis裏取出緩存了的數據
27                 $userInfo = $this->model->redisCache->getData("weixin:sign_{$wxSign}");
28                 if (!empty($userInfo)) {
29                     //獲取用戶的openid
30                     $this->wxId = $userInfo['openid'];
31                     //將其存在cookie裏
32                     $this->input->set_cookie('wxId', $this->wxId, 60*60*24*7);
33                     return $userInfo;
34                 }
35             }
36 
37             //獲取授權臨時票據(code)
38             $code = $_GET['code'];
39             if (empty($code)) {
40                 if (empty($url)) {
41                     $url = rtirm($_SERVER['QUERY_STRING'], '/');
42                     //到WxModel.php裏獲取到微信授權請求URL,然後redirect請求url
43                     redirect($this->model->wx->getOAuthUrl(baseUrl($url)));
44                 }
45             }
46             /***************這裏開始第二步:通過code獲取access_token****************/
47             $result = $this->model->wx->getOauthAccessToken($code);
48 
49             //如果發生錯誤
50             if (isset($result['errcode'])) {
51                 return array('msg'=>'授權失敗,請聯繫客服','result'=>$result);
52             }
53 
54             //到這一步就說明已經取到了access_token
55             $this->wxId = $result['openid'];
56             $accessToken = $result['access_token'];
57             $openId = $result['openid'];
58 
59             //將openid和accesstoken存入cookie中
60             $this->input->set_cookie('wx_id', $this->wxId, 60*60*24*7);
61             $this->input->set_cookie('access_token', $accessToken);
複製代碼

  WxModel.php

複製代碼
 1 <?php
 2     class WxModel extends ModelBase{
 3         public $appId;
 4         public $appSecret;
 5         public $token;
 6 
 7         public function __construct() {
 8             parent::__construct();
 9 
10             //審覈通過的移動應用所給的AppID和AppSecret
11             $this->appId = 'wx0000000000000000';
12             $this->appSecret = '00000000000000000000000000000';
13             $this->token = '00000000';
14         }
15 
16 
17         /**
18          * 獲取微信授權url
19          * @param string 授權後跳轉的URL
20          * @param bool 是否只獲取openid,true時,不會彈出授權頁面,但只能獲取用戶的openid,而false時,彈出授權頁面,可以通過openid獲取用戶信息
21          *   
22         */
23         public function getOAuthUrl($redirectUrl, $openIdOnly, $state = '') {
24             $redirectUrl = urlencode($redirectUrl);
25             $scope = $openIdOnly ? 'snsapi_base' : 'snsapi_userinfo';
26             $oAuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appId}&redirect_uri={$redirectUrl}&response_type=code&scope=$scope&state=$state#wechat_redirect";
27             return $oAuthUrl;
28         }
29 
30 
31         /**
32         * 獲取access_token
33         */
34         public function getoAuthAccessToken($code) {
35             return json_decode(file_get_contents("https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->AppId}&secret={$this->AppSecret}&code={$authCode}&grant_type=authorization_code",true);
36         }
複製代碼

這裏附上參數說明

  請求參數說明:

 

  響應返回值說明:

  當返回錯誤時是這樣子的:

 

3、通過access_token調用接口(獲取用戶信息)
  獲取access_token後,進行接口調用,有以下前提:

  (1)access_tokec有效且未超時;

  (2)微信用戶已授權給第三方應用賬號相應的接口作用域(scope)。

  

  以下是獲取用戶信息的代碼

  weixin.php

複製代碼
 1 <?php
 2     class weixinController extends CI_Controller {
 3         public $userInfo;
 4         public $wxId;
 5 
 6 
 7         public function __construct(){
 8             parent::__construct();
 9 
10             //只要用戶一訪問此模塊,就登錄授權,獲取用戶信息
11             $this->userInfo = $this->getWxUserInfo();
12         }
13     
14 
15         /**
16          * 確保當前用戶是在微信中打開,並且獲取用戶信息
17          *
18          * @param string $url 獲取到微信授權臨時票據(code)回調頁面的URL
19          */
20         private function getWxUserInfo($url = '') {
21             //微信標記(自己創建的)
22             $wxSign = $this->input->cookie('wxSign');
23             //先看看本地cookie裏是否存在微信唯一標記,
24             //假如存在,可以通過$wxSign到redis裏取出微信個人信息(因爲在第一次取到微信個人信息,我會將其保存一份到redis服務器裏緩存着)
25             if (!empty($wxSign)) {
26                 //如果存在,則從Redis裏取出緩存了的數據
27                 $userInfo = $this->model->redisCache->getData("weixin:sign_{$wxSign}");
28                 if (!empty($userInfo)) {
29                     //獲取用戶的openid
30                     $this->wxId = $userInfo['openid'];
31                     //將其存在cookie裏
32                     $this->input->set_cookie('wxId', $this->wxId, 60*60*24*7);
33                     return $userInfo;
34                 }
35             }
36 
37             //獲取授權臨時票據(code)
38             $code = $_GET['code'];
39             if (empty($code)) {
40                 if (empty($url)) {
41                     $url = rtirm($_SERVER['QUERY_STRING'], '/');
42                     //到WxModel.php裏獲取到微信授權請求URL,然後redirect請求url
43                     redirect($this->model->wx->getOAuthUrl(baseUrl($url)));
44                 }
45             }
46             /***************這裏開始第二步:通過code獲取access_token****************/
47             $result = $this->model->wx->getOauthAccessToken($code);
48 
49             //如果發生錯誤
50             if (isset($result['errcode'])) {
51                 return array('msg'=>'授權失敗,請聯繫客服','result'=>$result);
52             }
53 
54             //到這一步就說明已經取到了access_token
55             $this->wxId = $result['openid'];
56             $accessToken = $result['access_token'];
57             $openId = $result['openid'];
58 
59             //將openid和accesstoken存入cookie中
60             $this->input->set_cookie('wx_id', $this->wxId, 60*60*24*7);
61             $this->input->set_cookie('access_token', $accessToken);
62 
63             /*******************這裏開始第三步:通過access_token調用接口,取出用戶信息***********************/
64             $this->userInfo = $this->model->wx->getUserInfo($openId, $accessToken);
65 
66             //自定義微信唯一標識符
67             $wxSign =substr(md5($this->wxId.'k2a5dd'), 8, 16);
68             //將其存到cookie裏
69             $this->input->set_cookie('wxSign', $wxSign, 60*60*24*7);
70             //將個人信息緩存到redis裏
71             $this->library->redisCache->set("weixin:sign_{$wxSign}", $userInfo, 60*60*24*7);
72             return $userInfo;
73         }
74 
75 
76 
77 
78 
79 
80 
81 
82 
83 
84 
85 
86     }
87 ?>
複製代碼

  WxModel.php

複製代碼
  1 <?php
  2     class WxModel extends ModelBase{
  3         public $appId;
  4         public $appSecret;
  5         public $token;
  6 
  7         public function __construct() {
  8             parent::__construct();
  9 
 10             //審覈通過的移動應用所給的AppID和AppSecret
 11             $this->appId = 'wx0000000000000000';
 12             $this->appSecret = '00000000000000000000000000000';
 13             $this->token = '00000000';
 14         }
 15 
 16 
 17         /**
 18          * 獲取微信授權url
 19          * @param string 授權後跳轉的URL
 20          * @param bool 是否只獲取openid,true時,不會彈出授權頁面,但只能獲取用戶的openid,而false時,彈出授權頁面,可以通過openid獲取用戶信息
 21          *   
 22         */
 23         public function getOAuthUrl($redirectUrl, $openIdOnly, $state = '') {
 24             $redirectUrl = urlencode($redirectUrl);
 25             $scope = $openIdOnly ? 'snsapi_base' : 'snsapi_userinfo';
 26             $oAuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appId}&redirect_uri={$redirectUrl}&response_type=code&scope=$scope&state=$state#wechat_redirect";
 27             return $oAuthUrl;
 28         }
 29 
 30 
 31         /**
 32         * 獲取access_token
 33         */
 34         public function getoAuthAccessToken($code) {
 35             return json_decode(file_get_contents("https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->AppId}&secret={$this->AppSecret}&code={$authCode}&grant_type=authorization_code",true);
 36         }
 37 
 38         /**
 39         * 獲取用戶信息  
 40         */
 41         public function getUserInfo($openId, $accessToken) {
 42             $url = 'https://api.weixin.qq.com/sns/userinfo';
 43             //獲取用戶微信賬號信息
 44             $userInfo = $this->callApi("$url?access_token=$accessToken&openid=$openId&lang=zh-CN");
 45 
 46             if ($userInfo['errcode']) {
 47                 return array('msg'=>'獲取用戶信息失敗,請聯繫客服', $userInfo);
 48             }
 49 
 50             $userInfo['wx_id'] = $openId;
 51 
 52             return $userInfo;
 53         }
 54 
 55         /**
 56          * 發起Api請求,並獲取返回結果
 57          * @param string 請求URL
 58          * @param mixed 請求參數 (array|string)
 59          * @param string 請求類型 (GET|POST)
 60          * @return array        
 61          */
 62         public function callApi($apiUrl, $param = array(), $method = 'GET') {
 63             $result = curl_request_json($error, $apiUrl, $params, $method);
 64             //假如返回的數組有錯誤碼,或者變量$error也有值
 65             if (!empty($result['errcode'])) {
 66                 $errorCode = $result['errcode'];
 67                 $errorMsg = $result['errmsg'];
 68             } else if ($error != false) {
 69                 $errorCode = $error['errorCode'];
 70                 $errorMsg = $error['errorMessage'];
 71             }
 72 
 73             if (isset($errorCode)) {
 74                 //將其插入日誌文件
 75                 file_put_contents("/data/error.log", "callApi:url=$apiUrl,error=[$errorCode]$errorMsg");
 76 
 77                 if ($errorCode === 40001) {
 78                     //嘗試更正access_token後重試
 79                     try {
 80                         $pos = strpos(strtolower($url), 'access_token=');
 81                         if ($pos !==false ) {
 82                             $pos += strlen('access_token=');
 83                             $pos2 = strpos($apiUrl, '&' ,$pos);
 84                             $accessTokened = substr($apiUrl, $pos, $pos2 === false ? null : ($pos2 - $pos));
 85                             return $this->callApi(str_replace($accessTokened, $this->_getApiToken(true), $apiUrl), $param, $method);
 86                         }
 87                     }catch (WeixinException $e) { 
 88 
 89                     }
 90                 }
 91                 //這裏拋出異常,具有的就不詳說了
 92                 throw new WeixinException($errorMessage, $errorCode);
 93             }
 94             return $result;
 95         }
 96 
 97         /**
 98         * 獲取微信 api 的 access_token 。 不同於 OAuth 中的 access_token ,參見  http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token
 99         *
100         * @param bool 是否強制刷新 accessToken
101         */
102         private function _getApiToken($forceRefresh = false) {
103             //先查看一下redis裏是否已經緩存過access_token
104             $accessToken = $this->library->redisCache->get('Weixin:AccessToken');
105             if($forceRefresh || empty($accessToken)) {
106                 $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}");
107                 $accessToken = $result['access_token'];
108                 $expire = max(1, intval($result['expires_in']) - 60);
109                 //將access_token緩存到redis裏去
110                 $this->library->redisCache->set('Weixin:AccessToken', $accessToken, $expire);
111             }
112             return $accessToken;
113         }
114 
115 
116 
117 
118 
119 
120 
121 ?>
複製代碼

  Common.php

複製代碼
  1 <?php
  2     /**
  3      *   發起一個HTTP(S)請求,並返回json格式的響應數據
  4      *   @param array 錯誤信息  array($errorCode, $errorMessage)
  5      *   @param string 請求Url
  6      *   @param array 請求參數
  7      *   @param string 請求類型(GET|POST)
  8      *   @param int 超時時間
  9      *   @param array 額外配置
 10      *   
 11      *   @return array
 12      */ 
 13     public function curl_request_json(&$error, $url, $param = array(), $method = 'GET', $timeout = 10, $exOptions = null) {
 14         $error = false;
 15         $responseText = curl_request_text($error, $url, $param, $method, $timeout, $exOptions);
 16         $response = null;
 17         if ($error == false && $responseText > 0) {
 18             $response = json_decode($responseText, true);
 19 
 20             if ($response == null) {
 21                 $error = array('errorCode'=>-1, 'errorMessage'=>'json decode fail', 'responseText'=>$responseText);
 22                 //將錯誤信息記錄日誌文件裏
 23                 $logText = "json decode fail : $url";
 24                 if (!empty($param)) {
 25                     $logText .= ", param=".json_encode($param);
 26                 }
 27                 $logText .= ", responseText=$responseText";
 28                 file_put_contents("/data/error.log", $logText);
 29             }
 30         }
 31         return $response;
 32     }
 33 
 34     /**
 35     *  發起一個HTTP(S)請求,並返回響應文本
 36     *   @param array 錯誤信息  array($errorCode, $errorMessage)
 37     *   @param string 請求Url
 38     *   @param array 請求參數
 39     *   @param string 請求類型(GET|POST)
 40     *   @param int 超時時間
 41     *   @param array 額外配置
 42     *   
 43     *   @return string
 44     */
 45     public function curl_request_text(&$error, $url, $param = array(), $method = 'GET', $timeout = 15, $exOptions = NULL) {
 46         //判斷是否開啓了curl擴展
 47         if (!function_exists('curl_init')) exit('please open this curl extension');
 48 
 49         //將請求方法變大寫
 50         $method = strtoupper($method);
 51 
 52         $ch = curl_init();
 53         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
 54         curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
 55         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
 56         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
 57         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
 58         curl_setopt($ch, CURLOPT_HEADER, false);
 59         if (isset($_SERVER['HTTP_USER_AGENT'])) curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
 60         if (isset($_SERVER['HTTP_REFERER'])) curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER']);
 61         curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
 62         switch ($method) {
 63             case 'POST':
 64                 curl_setopt($ch, CURLOPT_POST, true);
 65                 if (!empty($param)) {
 66                     curl_setopt($ch, CURLOPT_POSTFIELDS, (is_array($param)) ? http_build_query($param) : $param);
 67                 }
 68                 break;
 69             
 70             case 'GET':
 71             case 'DELETE':
 72                 if ($method == 'DELETE') {
 73                     curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
 74                 }
 75                 if (!empty($param)) {
 76                     $url = $url.(strpos($url, '?') ? '&' : '?').(is_array($param) ? http_build_query($param) : $param);
 77                 }
 78                 break;
 79         }
 80         curl_setopt($ch, CURLINFO_HEADER_OUT, true);
 81         curl_setopt($ch, CURLOPT_URL, $url);
 82         //設置額外配置
 83         if (!empty($exOptions)) {
 84             foreach ($exOptions as $k => $v) {
 85                 curl_setopt($ch, $k, $v);
 86             }
 87         }
 88         $response = curl_exec($ch);
 89 
 90         $error = false;
 91         //看是否有報錯
 92         $errorCode = curl_errno($ch);
 93         if ($errorCode) {
 94             $errorMessage = curl_error($ch);
 95             $error = array('errorCode'=>$errorCode, 'errorMessage'=>$errorMessage);
 96             //將報錯寫入日誌文件裏
 97             $logText = "$method $url: [$errorCode]$errorMessage";
 98             if (!empty($param)) $logText .= ",$param".json_encode($param);
 99             file_put_contents('/data/error.log', $logText);
100         }
101 
102         curl_close($ch);
103 
104         return $response;
105 
106 
107 
108     }
109 
110 
111 
112 
113 
114 
115 
116 
117 
118 
119 
120 
121 
122 ?>
複製代碼

  

  通過以上三步調用接口,就可以獲取到用戶的微信賬號信息了。

  大家可以認真看看代碼, 裏面很多地方我都帶上了註釋,很容易理解。希望想學習的朋友可以認真看看。

  

 

  如果此博文有哪裏講得讓人難以理解的,歡迎留言交流,如文章有解釋出的地方,歡迎指出。

  

  如果您覺得能在此博文學到新知識,請在下方爲我頂一個,如文章有解釋錯的地方,歡迎指出。

   互相學習,共同進步!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章