微信授权登录并获取用户信息接口开发

总结一下微信授权登录并获取用户信息 这个接口的开发流程。

一、首先你的微信公众号要获得相应的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)回调页面的URL19 */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 //获取用户的openid30 $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请求url43 redirect($this->model->wx->getOAuthUrl(baseUrl($url)));44  }45  }46 47 48  }49  }50 ?>

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和AppSecret11 $this->appId = ‘wx0000000000000000‘;12 $this->appSecret = ‘00000000000000000000000000000‘;13 $this->token = ‘00000000‘;14  }15 16 /**17  * 获取微信授权url18  * @param string 授权后跳转的URL19  * @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的值了。接着进行第二步。

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)回调页面的URL19 */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 //获取用户的openid30 $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请求url43 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_token55 $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和AppSecret11 $this->appId = ‘wx0000000000000000‘;12 $this->appSecret = ‘00000000000000000000000000000‘;13 $this->token = ‘00000000‘;14  }15 16 17 /**18  * 获取微信授权url19  * @param string 授权后跳转的URL20  * @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_token33 */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)回调页面的URL19 */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 //获取用户的openid30 $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请求url43 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_token55 $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 ?>

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 是否强制刷新 accessToken101 */102 private function _getApiToken($forceRefresh = false) {103 //先查看一下redis里是否已经缓存过access_token104 $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 ?>

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 ?>

通过以上三步调用接口,就可以获取到用户的微信账号信息了。

 

相关文章