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 App\Http\Controllers;

use App\Weixin;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use App\Http\Requests;
use App\User;
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;
}
}
?>
相關文章
相關標籤/搜索