近排在作微信接口開發,因此總結一下微信受權登陸並獲取用戶信息 這個接口的開發流程。php
1、首先你的微信公衆號要得到相應的AppID和AppSecret,申請微信登陸且經過審覈後,纔可開始接入流程。redis
2、受權流程json
一、流程說明api
(1). 第三方發起微信受權登陸請求,微信用戶容許受權第三方應用後,微信會拉起應用或重定向到第三方網站,而且帶上受權臨時票據code參數;數組
(2). 經過code參數加上AppID和AppSecret等,經過API換取access_token;緩存
(3). 經過access_token進行接口調用,獲取用戶基本數據資源或幫助用戶實現基本操做。服務器
二、獲取access_token時序圖:微信
3、開發(個人用是CI框架,其實用什麼框架都同樣,MVC模式就好了)cookie
一、請求CODEapp
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()方法,此時
//獲取受權臨時票據(code) $code = $_GET['code'];
這行也已經能獲取獲得code的值了。接着進行第二步。
二、經過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 }
這裏附上參數說明
請求參數說明:
響應返回值說明:
當返回錯誤時是這樣子的:
三、經過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 ?>
經過以上三步調用接口,就能夠獲取到用戶的微信帳號信息了。
你們能夠認真看看代碼, 裏面不少地方我都帶上了註釋,很容易理解。但願想學習的朋友能夠認真看看。
若是此博文有哪裏講得讓人難以理解的,歡迎留言交流,如文章有解釋出的地方,歡迎指出。
若是您以爲能在此博文學到新知識,請在下方爲我頂一個,如文章有解釋錯的地方,歡迎指出。
互相學習,共同進步!