PHP开发网站之微信登录、绑定


PHP开发网站引入第三方登录之微信登录绑定
案例www.spaceyun.com

写在前面的话
如果在做此项功能之前有去了解OAuth2.0协议那么接下来一切都很容易理解如果没有了解OAuth2.0协议
也不影响完成此项功能不过应该是很难领会其原理

准备工作
微信登录时在微信开放平台open.weixin.qq.com上面
注册登录之后*认证开发者资质*不认证是无法开放网页登录授权的),在管理中心添加网站应用相关信息准备齐全
通过*审核*之后可以获取到APPID和APPSECERT然后在应用详情里面查看微信登录接口状态如果为已获得表示可以正常开发了
需要注意的是网站授权回调域和官网地址是没有http或者https例如我的网站授权回调域是www.spaceyun.com
我的官网地址也是www.spaceyun.com),
数据表用户表里面有openid字段新建一个微信表用来存储微信的openidnickname,headimgurlsex,city,province,country等信息

流程
1用户同意授权获取code
2通过code获取网页授权access_token
3)刷新access_token(如果需要)
4拉去用户信息需要scope为snsapi_userinfo

正式开发
我的开发是在laravel5.2框架里面的所以代码会按照框架的模式不过并没有使用laravel的扩展包纯手工代码
应该有参考价值
登录和绑定其实是一套流程就算绑定也是操作的snsapi_login的scope接口就是说登录是点击扫码获取openid登录
绑定也是点击扫码获取openid绑定
先以微信登录为例
路由
Route::get('wxLogin', 'WeixinController@wxLogin');//点击微信登录跳转到的url路由
Route::get('wxGetCode', 'WeixinController@wxGetCode');//用户扫码之后跳转到的url路由
控制器
先单个方法分析后面补上完整代码
1.
//login
public function wxLogin(){
$appid = $this->appid;
$redirect_uri = urlencode($this->redirect_uri);
$scope = "snsapi_login";
$state = "wxLogin";
$url = "https://open.weixin.qq.com/connect/qrconnect?appid=".$appid."&redirect_uri=".$redirect_uri."&response_type=code&scope=".$scope."&state=".$state."#wechat_redirect";
return redirect($url);
}
这个方法用来做微信登录请求触发就是用户点击微信登录提示的链接是跳转到上面的$url,
其中的appid是在开放平台创建应用后获取的
redirect_uri是用户扫码之后的回调地址因为会拼接在下面的url里面需要用urlencode处理
scope这里必须是"snsapi_login"
state是会提供给回调地址的参数类似于一个场景值的设定可以任意设置用来区分从网站的不同位置发起的请求建议使用有意义的英文单词
url是微信开放平台固定的里面的参数替换成我们上面的参数
最后做一个跳转我使用的是框架自带的方法可根据实际情况更改
这个操作会出现一个展示微信登录二维码的页面这个页面也是微信的页面跟我们本地的服务器没有任何关系
2.
//reback url-->wxGetCode
public function wxGetCode(){
$code = $_GET['code'];
$state = $_GET['state'];

if($state === 'wxLogin'){
$this->loginWeixin($code);
}elseif($state === 'wxBind'){
$this->bindWeixin($code);
}else{
return redirect("http://www.spaceyun.com");
}
}
这是用户扫码之后从微信的二维码页面会跳转到我们服务器的处理页面用户扫码登录成功之后
会携带code和state参数提交到我们服务器的服务器的地址
我们接收code和state根据state场景值判断做什么处理上面我们是wxLogin会到loginWeixin方法继续处理code
3.
//loginWeixin
private function loginWeixin($code){
$appid = $this->appid;
$appsecert = $this->appsecert;
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$appid."&secret=".$appsecert."&code=".$code."&grant_type=authorization_code";

//curl模拟get请求,获取结果
$res = $this->http_curl($url);
//转化为数组
$return_data = json_decode($res,true);
$openid = $return_data['openid'];

//openid存在,直接登录,openid不存在,先注册再登录
$result = User::where('wx_openid',$openid)->first();
if($result){
//login
Auth::loginUsingId($result->id,true);

$jump_url = 'http://www.spaceyun.com/accountSettings';
echo "<script>window.location.href='".$jump_url."'</script>";
return redirect('http://www.spaceyun.com/accountSettings');
}else{
$access_token = $return_data['access_token'];
//获取用户基本信息
$getInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
$userInfo = $this->http_curl($getInfoUrl);
$weixins = json_decode($userInfo);

//判断weixins表里面是否存在该条数据
$weixins_result = Weixin::where('openid',$openid)->first();
if(empty($weixins_result)){
//插入数据
Weixin::create([
'openid'=>$weixins->openid,
'nickname'=>$weixins->nickname,
'sex'=>$weixins->sex,
'city'=>$weixins->city,
'province'=>$weixins->province,
'country'=>$weixins->country,
'headimgurl'=>$weixins->headimgurl,
]);
}

//Register and login
$user = new User();
$arr['name'] = $weixins->nickname;
$arr['email'] = $openid."@fake.com";
$arr['password'] = "passwd";
$arr['phone'] = substr($openid,8);
$arr['wx_openid'] = $openid;
$insertId = $user->insertGetId($arr);
Auth::loginUsingId($insertId,true);
$jump_url = 'http://www.spaceyun.com/accountSettings';
echo "<script>window.location.href='".$jump_url."'</script>";
return redirect('http://www.spaceyun.com/accountSettings');
}

}
在这个方法里面根据appidappsecert这两个都是开放平台获取的还有回调返回的code拼接成url
然后用curl模拟get请求抓取返回数据我将返回的数据res转化成数组获取到用户的openid和access_token,
这时在我们的用户表里面一定要有一个叫做微信的openid的字段我的字段名是wx_openid因为我还会有qq_openid和sina_openid,
我们去用户表查询我们获取到的微信用户openid在不在我们的用户表里面
如果存在说明用户是一个老用户直接登录我用的laravel的Auth::loginUsingId($result->id,true)方法完成登录做跳转
我跳转到了账号设置页
如果不存在说明这是一个新用户新用户需要注册到用户表并且获取相关信息新增到微信表
获取用户基本信息需要access_token和openid在上面已经获取到获取到信息判断微信表里面是否存在此条数据
不存在就插入到微信表这些数据是微信开放给第三方应用的一些相关信息包括openidnickname,headimgurl
sex,city,province,country等信息
然后继续在用户表里面插入一条数据因为有一些非空字段我就自定义生成了一些数据
最后给这条最新添加的用户做登录登陆之后跳转

关于我的跳转多说一句因为用这个框架十来天之前也只开发了一个邮箱相关的功能所以没能明白redirect的原理
准备系统研究laravel时再考虑这个我要是只用window.location.href或者只用return redirect都无法实现跳转
把两个都写在这个就可以应该是有问题的不过不是错误先这样吧


这样登录功能就开发完了绑定功能是相同的流程只是绑定要在登录状态下操作也不用插入用户表只需要改用户表中wx_openid字段
需要注意的是一些逻辑上的问题比如说微信号已经绑定过一个账号根据自己应用需求判断允不允许绑定多个等等

<?php
namespace AppHttpControllers;

use AppWeixin;
use IlluminateHttpRequest;
use IlluminateSupportFacadesAuth;
use AppHttpRequests;
use AppUser;
use Cookie;

class WeixinController extends Controller{
//attribute------开放平台获取
private $appid = "your APPID";
private $appsecert = "your APPSECERT";
//redirect_uri,需要是跳到具体的页面处理,并且要在开放平台创建应用的授权回调域下面
private $redirect_uri = "http://www.spaceyun.com/wxGetCode";

//login
public function wxLogin(){
$appid = $this->appid;
$redirect_uri = urlencode($this->redirect_uri);
$scope = "snsapi_login";
$state = "wxLogin";
$url = "https://open.weixin.qq.com/connect/qrconnect?appid=".$appid."&redirect_uri=".$redirect_uri."&response_type=code&scope=".$scope."&state=".$state."#wechat_redirect";
return redirect($url);
}

//bind
public function wxBind(){
$appid = $this->appid;
$redirect_uri = urlencode($this->redirect_uri);
$scope = "snsapi_login";
$state = "wxBind";
$url = "https://open.weixin.qq.com/connect/qrconnect?appid=".$appid."&redirect_uri=".$redirect_uri."&response_type=code&scope=".$scope."&state=".$state."#wechat_redirect";
return redirect($url);
}

//reback url-->wxGetCode
public function wxGetCode(){
$code = $_GET['code'];
$state = $_GET['state'];

if($state === 'wxLogin'){
$this->loginWeixin($code);
}elseif($state === 'wxBind'){
$this->bindWeixin($code);
}else{
return redirect("http://www.spaceyun.com");
}
}

//loginWeixin
private function loginWeixin($code){
$appid = $this->appid;
$appsecert = $this->appsecert;
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$appid."&secret=".$appsecert."&code=".$code."&grant_type=authorization_code";

//curl模拟get请求,获取结果
$res = $this->http_curl($url);

//转化为数组
$return_data = json_decode($res,true);
$openid = $return_data['openid'];

//openid存在,直接登录,openid不存在,先注册再登录
$result = User::where('wx_openid',$openid)->first();
if($result){
//login
Auth::loginUsingId($result->id,true);

$jump_url = 'http://www.spaceyun.com/accountSettings';
echo "<script>window.location.href='".$jump_url."'</script>";
return redirect('http://www.spaceyun.com/accountSettings');
}else{
//转化为数组
$access_token = $return_data['access_token'];

//获取用户基本信息
$getInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";
$userInfo = $this->http_curl($getInfoUrl);
$weixins = json_decode($userInfo);

//判断weixins表里面是否存在该条数据
$weixins_result = Weixin::where('openid',$openid)->first();
if(empty($weixins_result)){
//插入数据
Weixin::create([
'openid'=>$weixins->openid,
'nickname'=>$weixins->nickname,
'sex'=>$weixins->sex,
'city'=>$weixins->city,
'province'=>$weixins->province,
'country'=>$weixins->country,
'headimgurl'=>$weixins->headimgurl,
]);
}

//Register and login
$user = new User();
$arr['name'] = $weixins->nickname;
$arr['email'] = $openid."@fake.com";
$arr['password'] = "passwd";
$arr['phone'] = substr($openid,8);
$arr['wx_openid'] = $openid;
$insertId = $user->insertGetId($arr);
Auth::loginUsingId($insertId,true);
$jump_url = 'http://www.spaceyun.com/accountSettings';
echo "<script>window.location.href='".$jump_url."'</script>";
return redirect('http://www.spaceyun.com/accountSettings');
}

}


//bindWeixin
private function bindWeixin($code){
$appid = $this->appid;
$appsecert = $this->appsecert;
$url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid=".$appid."&secret=".$appsecert."&code=".$code."&grant_type=authorization_code";

//curl模拟get请求,获取结果
$res = $this->http_curl($url);

//转化为数组
$return_data = json_decode($res, true);
$access_token = $return_data['access_token'];
$openid = $return_data['openid'];

//openid存在,提示需要解绑其他账号,openid不存在,先补充信息到weixins表再绑定
$result = User::where('wx_openid',$openid)->first();
if($result){
$jump_url = 'http://www.spaceyun.com/wxBindError';
echo "<script>window.location.href='".$jump_url."'</script>";
return redirect('http://www.spaceyun.com/wxBindError');

}else{
$user_id = Auth::id();
$user = User::find($user_id);
$user->wx_openid = $openid;
$user->save();

//判断weixins表里面是否存在该条数据
$weixins_result = Weixin::where('openid',$openid)->first();
if(empty($weixins_result)){
//获取用户基本信息
$getInfoUrl = "https://api.weixin.qq.com/sns/userinfo?access_token=".$access_token."&openid=".$openid."&lang=zh_CN";

$userInfo = $this->http_curl($getInfoUrl);
$weixins = json_decode($userInfo);
Weixin::create([
'openid'=>$weixins->openid,
'nickname'=>$weixins->nickname,
'sex'=>$weixins->sex,
'city'=>$weixins->city,
'province'=>$weixins->province,
'country'=>$weixins->country,
'headimgurl'=>$weixins->headimgurl,
]);
}
}
$jump_url = 'http://www.spaceyun.com/accountSettings';
echo "<script>window.location.href='".$jump_url."'</script>";
return redirect('http://www.spaceyun.com/accountSettings');
}

//wxBindError
public function wxBindError(){
$wxBindError = '该微信号已被绑定云享客账号,如需更改请到之前账号解除绑定';
return view("weixin.wxBindError",['information'=>$wxBindError]);
}

//解绑
public function wxUnbind(){
//users表里面wx_openid字段清空
$user_id = Auth::id();
$user = User::find($user_id);
if(!preg_match("/^1[34578]{1}d{9}$/",$user->phone)){
$wxBindError = '请认证手机号之后再解除绑定微信';
return view("weixin.wxBindError",['information'=>$wxBindError]);
}else{
$user->wx_openid = '0';
$user->save();

return redirect('/accountSettings');
}

}

//curl模拟get请求
private function http_curl($url){
$curlobj = curl_init();
curl_setopt($curlobj, CURLOPT_URL, $url);
curl_setopt($curlobj, CURLOPT_RETURNTRANSFER, 1);
curl_setopt($curlobj, CURLOPT_SSL_VERIFYPEER, FALSE);
curl_setopt($curlobj, CURLOPT_SSL_VERIFYHOST, FALSE);

$output = curl_exec($curlobj);
curl_close($curlobj);

return $output;
}
}
?>



原文地址:https://www.cnblogs.com/eis13/p/5889495.html