请选择 进入手机版 | 继续访问电脑版

UESOHO

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

admin 发表于 1-20 18:19:45 | 0 条回复 | 591 次浏览

近排在做微信接口开发,所以总结一下微信授权登录并获取用户信息 这个接口的开发流程。
一、首先你的微信公众号要获得相应的AppID和AppSecret,申请微信登录且通过审核后,才可开始接入流程。
二、授权流程
1、流程说明
(1). 第三方发起微信授权登录请求,微信用户允许授权第三方应用后,微信会拉起应用或重定向到第三方网站,并且带上授权临时票据code参数;
(2). 通过code参数加上AppID和AppSecret等,通过API换取access_token;
(3). 通过access_token进行接口调用,获取用户基本数据资源或帮助用户实现基本操作。
2、获取access_token时序图:
三、开发(我的用是CI框架,其实用什么框架都一样,MVC模式就行了)
QQ截图20160120180556.png
1、请求CODE
weixin.php
  1.     class weixinController extends CI_Controller {
  2.         public $userInfo;
  3.         public $wxId;


  4.         public function __construct(){
  5.             parent::__construct();

  6.             //只要用户一访问此模块,就登录授权,获取用户信息
  7.             $this->userInfo = $this->getWxUserInfo();
  8.         }
  9.      

  10.         /**
  11.          * 确保当前用户是在微信中打开,并且获取用户信息
  12.          *
  13.          * @param string $url 获取到微信授权临时票据(code)回调页面的URL
  14.          */
  15.         private function getWxUserInfo($url = '') {
  16.             //微信标记(自己创建的)
  17.             $wxSign = $this->input->cookie('wxSign');
  18.             //先看看本地cookie里是否存在微信唯一标记,
  19.             //假如存在,可以通过$wxSign到redis里取出微信个人信息(因为在第一次取到微信个人信息,我会将其保存一份到redis服务器里缓存着)
  20.             if (!empty($wxSign)) {
  21.                 //如果存在,则从Redis里取出缓存了的数据
  22.                 $userInfo = $this->model->redisCache->getData("weixin:sign_{$wxSign}");
  23.                 if (!empty($userInfo)) {
  24.                     //获取用户的openid
  25.                     $this->wxId = $userInfo['openid'];
  26.                     //将其存在cookie里
  27.                     $this->input->set_cookie('wxId', $this->wxId, 60*60*24*7);
  28.                     return $userInfo;
  29.                 }
  30.             }
  31.             //获取授权临时票据(code)
  32.             $code = $_GET['code'];
  33.             if (empty($code)) {
  34.                 if (empty($url)) {
  35.                     $url = rtirm($_SERVER['QUERY_STRING'], '/');
  36.                     //到WxModel.php里获取到微信授权请求URL,然后redirect请求url
  37.                     redirect($this->model->wx->getOAuthUrl(baseUrl($url)));
  38.                 }
  39.             }
  40.         }
  41.     }
  42. ?>

  43. 获取code的Controller代码
复制代码
Wxmodel.php
  1.     class weixinController extends CI_Controller {
  2.         public $userInfo;
  3.         public $wxId;


  4.         public function __construct(){
  5.             parent::__construct();

  6.             //只要用户一访问此模块,就登录授权,获取用户信息
  7.             $this->userInfo = $this->getWxUserInfo();
  8.         }
  9.      

  10.         /**
  11.          * 确保当前用户是在微信中打开,并且获取用户信息
  12.          *
  13.          * @param string $url 获取到微信授权临时票据(code)回调页面的URL
  14.          */
  15.         private function getWxUserInfo($url = '') {
  16.             //微信标记(自己创建的)
  17.             $wxSign = $this->input->cookie('wxSign');
  18.             //先看看本地cookie里是否存在微信唯一标记,
  19.             //假如存在,可以通过$wxSign到redis里取出微信个人信息(因为在第一次取到微信个人信息,我会将其保存一份到redis服务器里缓存着)
  20.             if (!empty($wxSign)) {
  21.                 //如果存在,则从Redis里取出缓存了的数据
  22.                 $userInfo = $this->model->redisCache->getData("weixin:sign_{$wxSign}");
  23.                 if (!empty($userInfo)) {
  24.                     //获取用户的openid
  25.                     $this->wxId = $userInfo['openid'];
  26.                     //将其存在cookie里
  27.                     $this->input->set_cookie('wxId', $this->wxId, 60*60*24*7);
  28.                     return $userInfo;
  29.                 }
  30.             }

  31.             //获取授权临时票据(code)
  32.             $code = $_GET['code'];
  33.             if (empty($code)) {
  34.                 if (empty($url)) {
  35.                     $url = rtirm($_SERVER['QUERY_STRING'], '/');
  36.                     //到WxModel.php里获取到微信授权请求URL,然后redirect请求url
  37.                     redirect($this->model->wx->getOAuthUrl(baseUrl($url)));
  38.                 }
  39.             }


  40.         }

  41.     }
  42. ?>

  43. 获取code的Controller代码
复制代码
这里附上请求参数说明和返回值说明
请求参数说明:
QQ截图20160120181324.png
响应返回值说明:
QQ截图201601201813222247.png
 当请求成功,会redirect到请求参数中的redirect_uri的值中去,其实又回到weixin.php的$this->userInfo = $this->getWxUserInfo();这行去,然后再一次进入到getWxUserInfo()方法,此时
  1. //获取授权临时票据(code)
  2. $code = $_GET['code'];
复制代码
这行也已经能获取得到code的值了。接着进行第二步。
2、通过code获取access_token
  weixin.php
  1.     class weixinController extends CI_Controller {
  2.         public $userInfo;
  3.         public $wxId;


  4.         public function __construct(){
  5.             parent::__construct();

  6.             //只要用户一访问此模块,就登录授权,获取用户信息
  7.             $this->userInfo = $this->getWxUserInfo();
  8.         }
  9.      

  10.         /**
  11.          * 确保当前用户是在微信中打开,并且获取用户信息
  12.          *
  13.          * @param string $url 获取到微信授权临时票据(code)回调页面的URL
  14.          */
  15.         private function getWxUserInfo($url = '') {
  16.             //微信标记(自己创建的)
  17.             $wxSign = $this->input->cookie('wxSign');
  18.             //先看看本地cookie里是否存在微信唯一标记,
  19.             //假如存在,可以通过$wxSign到redis里取出微信个人信息(因为在第一次取到微信个人信息,我会将其保存一份到redis服务器里缓存着)
  20.             if (!empty($wxSign)) {
  21.                 //如果存在,则从Redis里取出缓存了的数据
  22.                 $userInfo = $this->model->redisCache->getData("weixin:sign_{$wxSign}");
  23.                 if (!empty($userInfo)) {
  24.                     //获取用户的openid
  25.                     $this->wxId = $userInfo['openid'];
  26.                     //将其存在cookie里
  27.                     $this->input->set_cookie('wxId', $this->wxId, 60*60*24*7);
  28.                     return $userInfo;
  29.                 }
  30.             }

  31.             //获取授权临时票据(code)
  32.             $code = $_GET['code'];
  33.             if (empty($code)) {
  34.                 if (empty($url)) {
  35.                     $url = rtirm($_SERVER['QUERY_STRING'], '/');
  36.                     //到WxModel.php里获取到微信授权请求URL,然后redirect请求url
  37.                     redirect($this->model->wx->getOAuthUrl(baseUrl($url)));
  38.                 }
  39.             }
  40.             /***************这里开始第二步:通过code获取access_token****************/
  41.             $result = $this->model->wx->getOauthAccessToken($code);

  42.             //如果发生错误
  43.             if (isset($result['errcode'])) {
  44.                 return array('msg'=>'授权失败,请联系客服','result'=>$result);
  45.             }

  46.             //到这一步就说明已经取到了access_token
  47.             $this->wxId = $result['openid'];
  48.             $accessToken = $result['access_token'];
  49.             $openId = $result['openid'];

  50.             //将openid和accesstoken存入cookie中
  51.             $this->input->set_cookie('wx_id', $this->wxId, 60*60*24*7);
  52.             $this->input->set_cookie('access_token', $accessToken);

  53. 获取access_token的控制器代码
复制代码
WxModel.php
  1.     class WxModel extends ModelBase{
  2.         public $appId;
  3.         public $appSecret;
  4.         public $token;

  5.         public function __construct() {
  6.             parent::__construct();

  7.             //审核通过的移动应用所给的AppID和AppSecret
  8.             $this->appId = 'wx0000000000000000';
  9.             $this->appSecret = '00000000000000000000000000000';
  10.             $this->token = '00000000';
  11.         }


  12.         /**
  13.          * 获取微信授权url
  14.          * @param string 授权后跳转的URL
  15.          * @param bool 是否只获取openid,true时,不会弹出授权页面,但只能获取用户的openid,而false时,弹出授权页面,可以通过openid获取用户信息
  16.          *   
  17.         */
  18.         public function getOAuthUrl($redirectUrl, $openIdOnly, $state = '') {
  19.             $redirectUrl = urlencode($redirectUrl);
  20.             $scope = $openIdOnly ? 'snsapi_base' : 'snsapi_userinfo';
  21.             $oAuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appId}&redirect_uri={$redirectUrl}&response_type=code&scope=$scope&state=$state#wechat_redirect";
  22.             return $oAuthUrl;
  23.         }


  24.         /**
  25.         * 获取access_token
  26.         */
  27.         public function getoAuthAccessToken($code) {
  28.             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);
  29.         }

  30. 获取access_token的Model代码
复制代码
这里附上参数说明
请求参数说明:
QQ截图20160120181637.png

当返回错误时是这样子的:
20150612103542685.png
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.         public function __construct(){
  6.             parent::__construct();

  7.             //只要用户一访问此模块,就登录授权,获取用户信息
  8.             $this->userInfo = $this->getWxUserInfo();
  9.         }
  10.      

  11.         /**
  12.          * 确保当前用户是在微信中打开,并且获取用户信息
  13.          *
  14.          * @param string $url 获取到微信授权临时票据(code)回调页面的URL
  15.          */
  16.         private function getWxUserInfo($url = '') {
  17.             //微信标记(自己创建的)
  18.             $wxSign = $this->input->cookie('wxSign');
  19.             //先看看本地cookie里是否存在微信唯一标记,
  20.             //假如存在,可以通过$wxSign到redis里取出微信个人信息(因为在第一次取到微信个人信息,我会将其保存一份到redis服务器里缓存着)
  21.             if (!empty($wxSign)) {
  22.                 //如果存在,则从Redis里取出缓存了的数据
  23.                 $userInfo = $this->model->redisCache->getData("weixin:sign_{$wxSign}");
  24.                 if (!empty($userInfo)) {
  25.                     //获取用户的openid
  26.                     $this->wxId = $userInfo['openid'];
  27.                     //将其存在cookie里
  28.                     $this->input->set_cookie('wxId', $this->wxId, 60*60*24*7);
  29.                     return $userInfo;
  30.                 }
  31.             }

  32.             //获取授权临时票据(code)
  33.             $code = $_GET['code'];
  34.             if (empty($code)) {
  35.                 if (empty($url)) {
  36.                     $url = rtirm($_SERVER['QUERY_STRING'], '/');
  37.                     //到WxModel.php里获取到微信授权请求URL,然后redirect请求url
  38.                     redirect($this->model->wx->getOAuthUrl(baseUrl($url)));
  39.                 }
  40.             }
  41.             /***************这里开始第二步:通过code获取access_token****************/
  42.             $result = $this->model->wx->getOauthAccessToken($code);

  43.             //如果发生错误
  44.             if (isset($result['errcode'])) {
  45.                 return array('msg'=>'授权失败,请联系客服','result'=>$result);
  46.             }

  47.             //到这一步就说明已经取到了access_token
  48.             $this->wxId = $result['openid'];
  49.             $accessToken = $result['access_token'];
  50.             $openId = $result['openid'];

  51.             //将openid和accesstoken存入cookie中
  52.             $this->input->set_cookie('wx_id', $this->wxId, 60*60*24*7);
  53.             $this->input->set_cookie('access_token', $accessToken);

  54.             /*******************这里开始第三步:通过access_token调用接口,取出用户信息***********************/
  55.             $this->userInfo = $this->model->wx->getUserInfo($openId, $accessToken);

  56.             //自定义微信唯一标识符
  57.             $wxSign =substr(md5($this->wxId.'k2a5dd'), 8, 16);
  58.             //将其存到cookie里
  59.             $this->input->set_cookie('wxSign', $wxSign, 60*60*24*7);
  60.             //将个人信息缓存到redis里
  61.             $this->library->redisCache->set("weixin:sign_{$wxSign}", $userInfo, 60*60*24*7);
  62.             return $userInfo;
  63.         }
  64.     }
  65. ?>

  66. 获取用户信息的Controller
复制代码
WxModel.php
  1. <?php
  2.     class WxModel extends ModelBase{
  3.         public $appId;
  4.         public $appSecret;
  5.         public $token;

  6.         public function __construct() {
  7.             parent::__construct();

  8.             //审核通过的移动应用所给的AppID和AppSecret
  9.             $this->appId = 'wx0000000000000000';
  10.             $this->appSecret = '00000000000000000000000000000';
  11.             $this->token = '00000000';
  12.         }


  13.         /**
  14.          * 获取微信授权url
  15.          * @param string 授权后跳转的URL
  16.          * @param bool 是否只获取openid,true时,不会弹出授权页面,但只能获取用户的openid,而false时,弹出授权页面,可以通过openid获取用户信息
  17.          *   
  18.         */
  19.         public function getOAuthUrl($redirectUrl, $openIdOnly, $state = '') {
  20.             $redirectUrl = urlencode($redirectUrl);
  21.             $scope = $openIdOnly ? 'snsapi_base' : 'snsapi_userinfo';
  22.             $oAuthUrl = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$this->appId}&redirect_uri={$redirectUrl}&response_type=code&scope=$scope&state=$state#wechat_redirect";
  23.             return $oAuthUrl;
  24.         }


  25.         /**
  26.         * 获取access_token
  27.         */
  28.         public function getoAuthAccessToken($code) {
  29.             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);
  30.         }

  31.         /**
  32.         * 获取用户信息  
  33.         */
  34.         public function getUserInfo($openId, $accessToken) {
  35.             $url = 'https://api.weixin.qq.com/sns/userinfo';
  36.             //获取用户微信账号信息
  37.             $userInfo = $this->callApi("$url?access_token=$accessToken&openid=$openId&lang=zh-CN");

  38.             if ($userInfo['errcode']) {
  39.                 return array('msg'=>'获取用户信息失败,请联系客服', $userInfo);
  40.             }

  41.             $userInfo['wx_id'] = $openId;

  42.             return $userInfo;
  43.         }

  44.         /**
  45.          * 发起Api请求,并获取返回结果
  46.          * @param string 请求URL
  47.          * @param mixed 请求参数 (array|string)
  48.          * @param string 请求类型 (GET|POST)
  49.          * @return array        
  50.          */
  51.         public function callApi($apiUrl, $param = array(), $method = 'GET') {
  52.             $result = curl_request_json($error, $apiUrl, $params, $method);
  53.             //假如返回的数组有错误码,或者变量$error也有值
  54.             if (!empty($result['errcode'])) {
  55.                 $errorCode = $result['errcode'];
  56.                 $errorMsg = $result['errmsg'];
  57.             } else if ($error != false) {
  58.                 $errorCode = $error['errorCode'];
  59.                 $errorMsg = $error['errorMessage'];
  60.             }

  61.             if (isset($errorCode)) {
  62.                 //将其插入日志文件
  63.                 file_put_contents("/data/error.log", "callApi:url=$apiUrl,error=[$errorCode]$errorMsg");

  64.                 if ($errorCode === 40001) {
  65.                     //尝试更正access_token后重试
  66.                     try {
  67.                         $pos = strpos(strtolower($url), 'access_token=');
  68.                         if ($pos !==false ) {
  69.                             $pos += strlen('access_token=');
  70.                             $pos2 = strpos($apiUrl, '&' ,$pos);
  71.                             $accessTokened = substr($apiUrl, $pos, $pos2 === false ? null : ($pos2 - $pos));
  72.                             return $this->callApi(str_replace($accessTokened, $this->_getApiToken(true), $apiUrl), $param, $method);
  73.                         }
  74.                     }catch (WeixinException $e) {

  75.                     }
  76.                 }
  77.                 //这里抛出异常,具有的就不详说了
  78.                 throw new WeixinException($errorMessage, $errorCode);
  79.             }
  80.             return $result;
  81.         }

  82.         /**
  83.         * 获取微信 api 的 access_token 。 不同于 OAuth 中的 access_token ,参见  http://mp.weixin.qq.com/wiki/index.php?title=%E8%8E%B7%E5%8F%96access_token
  84.         *
  85.         * @param bool 是否强制刷新 accessToken
  86.         */
  87.         private function _getApiToken($forceRefresh = false) {
  88.             //先查看一下redis里是否已经缓存过access_token
  89.             $accessToken = $this->library->redisCache->get('Weixin:AccessToken');
  90.             if($forceRefresh || empty($accessToken)) {
  91.                 $result = $this->callApi("https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid={$this->appId}&secret={$this->appSecret}");
  92.                 $accessToken = $result['access_token'];
  93.                 $expire = max(1, intval($result['expires_in']) - 60);
  94.                 //将access_token缓存到redis里去
  95.                 $this->library->redisCache->set('Weixin:AccessToken', $accessToken, $expire);
  96.             }
  97.             return $accessToken;
  98.         }

  99. ?>

  100. 获取用户信息的Model
复制代码
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.             if ($response == null) {
  20.                 $error = array('errorCode'=>-1, 'errorMessage'=>'json decode fail', 'responseText'=>$responseText);
  21.                 //将错误信息记录日志文件里
  22.                 $logText = "json decode fail : $url";
  23.                 if (!empty($param)) {
  24.                     $logText .= ", param=".json_encode($param);
  25.                 }
  26.                 $logText .= ", responseText=$responseText";
  27.                 file_put_contents("/data/error.log", $logText);
  28.             }
  29.         }
  30.         return $response;
  31.     }

  32.     /**
  33.     *  发起一个HTTP(S)请求,并返回响应文本
  34.     *   @param array 错误信息  array($errorCode, $errorMessage)
  35.     *   @param string 请求Url
  36.     *   @param array 请求参数
  37.     *   @param string 请求类型(GET|POST)
  38.     *   @param int 超时时间
  39.     *   @param array 额外配置
  40.     *   
  41.     *   @return string
  42.     */
  43.     public function curl_request_text(&$error, $url, $param = array(), $method = 'GET', $timeout = 15, $exOptions = NULL) {
  44.         //判断是否开启了curl扩展
  45.         if (!function_exists('curl_init')) exit('please open this curl extension');

  46.         //将请求方法变大写
  47.         $method = strtoupper($method);

  48.         $ch = curl_init();
  49.         curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, $timeout);
  50.         curl_setopt($ch, CURLOPT_TIMEOUT, $timeout);
  51.         curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
  52.         curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
  53.         curl_setopt($ch, CURLOPT_SSL_VERIFYHOST, false);
  54.         curl_setopt($ch, CURLOPT_HEADER, false);
  55.         if (isset($_SERVER['HTTP_USER_AGENT'])) curl_setopt($ch, CURLOPT_USERAGENT, $_SERVER['HTTP_USER_AGENT']);
  56.         if (isset($_SERVER['HTTP_REFERER'])) curl_setopt($ch, CURLOPT_REFERER, $_SERVER['HTTP_REFERER']);
  57.         curl_setopt($ch, CURLOPT_AUTOREFERER, 1);
  58.         switch ($method) {
  59.             case 'POST':
  60.                 curl_setopt($ch, CURLOPT_POST, true);
  61.                 if (!empty($param)) {
  62.                     curl_setopt($ch, CURLOPT_POSTFIELDS, (is_array($param)) ? http_build_query($param) : $param);
  63.                 }
  64.                 break;
  65.             
  66.             case 'GET':
  67.             case 'DELETE':
  68.                 if ($method == 'DELETE') {
  69.                     curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
  70.                 }
  71.                 if (!empty($param)) {
  72.                     $url = $url.(strpos($url, '?') ? '&' : '?').(is_array($param) ? http_build_query($param) : $param);
  73.                 }
  74.                 break;
  75.         }
  76.         curl_setopt($ch, CURLINFO_HEADER_OUT, true);
  77.         curl_setopt($ch, CURLOPT_URL, $url);
  78.         //设置额外配置
  79.         if (!empty($exOptions)) {
  80.             foreach ($exOptions as $k => $v) {
  81.                 curl_setopt($ch, $k, $v);
  82.             }
  83.         }
  84.         $response = curl_exec($ch);

  85.         $error = false;
  86.         //看是否有报错
  87.         $errorCode = curl_errno($ch);
  88.         if ($errorCode) {
  89.             $errorMessage = curl_error($ch);
  90.             $error = array('errorCode'=>$errorCode, 'errorMessage'=>$errorMessage);
  91.             //将报错写入日志文件里
  92.             $logText = "$method $url: [$errorCode]$errorMessage";
  93.             if (!empty($param)) $logText .= ",$param".json_encode($param);
  94.             file_put_contents('/data/error.log', $logText);
  95.         }

  96.         curl_close($ch);

  97.         return $response;

  98.     }

  99. ?>
复制代码
获取用户信息的自定义函数

通过以上三步调用接口,就可以获取到用户的微信账号信息了。
大家可以认真看看代码, 里面很多地方我都带上了注释,很容易理解。希望想学习的朋友可以认真看看。

回复 道具 举报

您需要登录后才可以回帖 登录 | 注册

UESOHO/津ICP备11001501号-4 Powered by Discuz!

top