您的位置:首页 > 移动开发 > 微信开发

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

2017-04-10 10:54 1461 查看
近期在做微信接口开发,所以总结一下微信授权登录并获取用户信息 这个接口的开发流程。
一、首先你的微信公众号要获得相应的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()方法,此时

 这行也已经能获取得到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 ?>


  

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

  大家可以认真看看代码, 里面很多地方我都带上了注释,很容易理解。希望想学习的朋友可以认真看看。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐