3자 로그인의 전체적인 아이디어는 제3자로부터 openid를 얻은 다음 이를 사용자와 연결(데이터베이스에 저장)하고 로그인하는 것입니다. 이 글은 주로 QQ, WeChat, Weibo 웹사이트 액세스를 위한 제3자 로그인에 대한 자세한 설명을 공유합니다. 모두에게 도움이 되기를 바랍니다.
현재 요구 사항은 maxiye.cn
및 yexima.com
과 같은 2개 이상의 1차 도메인 이름이며, 각 도메인 이름에는 여러 개의 2차 도메인 이름이 있습니다. 수준 도메인 이름. app.maxiye.cn, new.maxiye.cn, old.maxiye.cn, app.yexima.com, new.yexima.com, old.yexima.com... 등이 있지만 이러한 도메인 이름은 동일한 코드(예, 조끼)를 사용하고 데이터베이스와 세션을 공유합니다. 동시에 각 도메인 이름에는 PC, iOS 및 Android 터미널이 포함됩니다. 모든 타사 로그인에 액세스하는 방법은 무엇입니까? <code>maxiye.cn
和yexima.com
,同时每个域名下有多个二级域名分布,如:app.maxiye.cn,new.maxiye.cn,old.maxiye.cn,app.yexima.com,new.yexima.com,old.yexima.com
...等,但是这些域名下使用了同一份代码(对,就是马甲),共享数据库和session。同时旗下每个域名均包含pc,ios,Android端,如何全部接入第三方登陆?
qq,微信,微博接入要点:
1.申请入口:QQ是QQ互联,微信是微信开放平台,微博是微博开放平台;
2.回调域设置:QQ可以设置一级域名且可以有多个,必须http://
开头,;
结束,如http://maxiye.cn;http://yexima.com;
;微信只能设置到二级域名且只能一个,格式为:app.maxiye.cn
;
微博也可以设置一级域名且是一个:maxiye.cn
;
3.unionid获取:多个app(同一开发者账号下
)共享数据库,故需要使用unionid确认身份。QQ获取uuid需要额外申请权限,具体参考相同开发者账号下的不同appid应用如何打通;微信已有unionid获取接口;微博则uid即unionid;
坑:
1.QQ接口返回的结果好多是jsonp格式,需要手动剥离callback()
;
2.微博获取获取access_token竟然必须使用post
,惊了;
3.微信不支持回调地址填写一级域名,所以需要使用统一域名(代理)作为回调地址,然后内部再重定向到发申请的域名;
下边是一个写好的工具类:
<?php /* PHP SDK 第三方登录授权验证 * @version 1.0.0 * @author zyl * @copyright */ namespace app\helpers; use yii\helpers\Url; use Yii; class OauthLogin { public $server = '';//接入第三方的域名 public $proxy = 'app.maxiye.cn';//微信登录代理中转站点 private $type = '';//第三方类型:qq,weixin,weibo private $app_id = '';//分配给网站的appid。 private $app_secret = '';//分配给网站的appkey。 private $state = '';//client端的状态值。用于第三方应用防止CSRF攻击,成功授权后回调时会原样带回。请务必严格按照流程检查用户与state参数状态的绑定。 private $code = '';//用户成功登录并授权,则会跳转到指定的回调地址,并在URL中带上Authorization Code。 private $access_token; private $config = [//配置多个网站的appid&appkey 'maxiye.cn' => [ 'qq' => [ 'app_id' => '100000000', 'app_secret' => 'f9038c3d07c*******7884edf3e31708', ], 'weixin' => [ 'app_id' => 'wxee7c90a7744c2002', 'app_secret' => '13e649627894*******7a85a0e2f50e7', ], 'weibo' => [ 'app_id' => '1200000000', 'app_secret' => 'e074de8*******d3818d0df9ca28c459', ], ], 'yexima.com' => [ 'qq' => [ 'app_id' => '101111244', 'app_secret' => '6ca59c6a1b1*******77e636a10ac334', ], 'weixin' => [ 'app_id' => 'wx0b822222ea9ee323', 'app_secret' => '7f9cbd*******f37ce7b4c267bdde029', ], 'weibo' => [ 'app_id' => '911111998', 'app_secret' => '5b21c452f88e2982*******1722d8fcd', ], ], ]; function __construct($params = []) { $this->type = $params['type']; $this->server = $_SERVER['SERVER_NAME']; foreach ($this->config as $k => $v) { if (stristr($this->server, $k) && isset($v[$this->type])) { $this->app_id = $v[$this->type]['app_id']; $this->app_secret = $v[$this->type]['app_secret']; } } if (isset($params['code'])) { $this->code = $params['code']; } } /** * 获取用户授权验证的链接 * @return string */ public function getOauthUrl() { $this->state = md5(uniqid(rand(), TRUE)); Yii::$app->session->setFlash('oauth_state', $this->state); $redirect_uri = urlencode(Url::to(['login-by-openid', 'type' => $this->type, true)); if ($this->type == 'weixin' && $this->server != $this->proxy) {//微信回调多域名代理处理 $redirect_uri = str_replace($this->server, $this->proxy, $redirect_uri) . '%26redirect%3D' . $this->server; } $url = ''; switch ($this->type) { case 'qq'://qq回调域填写一级域名并以“;”结束:http://maxiye.cn;http://yexima.com; $url = "https://graph.qq.com/oauth/show?which=Login&display=pc&response_type=code&client_id={$this->app_id}&state={$this->state}&display=web&redirect_uri={$redirect_uri}"; break; case 'weixin'://app.maxiye.cn不支持只填写二级域名 $url = "https://open.weixin.qq.com/connect/qrconnect?response_type=code&appid={$this->app_id}&state={$this->state}&scope=snsapi_login&redirect_uri={$redirect_uri}#wechat_redirect"; break; case 'weibo'://微博设置安全域名:maxiye.cn $url = "https://api.weibo.com/oauth2/authorize?response_type=code&client_id={$this->app_id}&state={$this->state}&display=web&redirect_uri={$redirect_uri}"; break; default: break; } return $url; } /** * 获取针对开发者账号的惟一uuid * @return string unionid或uid */ public function getUuid() { $openid = ''; if ($this->type == 'qq') { $this->getAccessToken(); } else { $openid = $this->getOpenid(); } $access_token = $this->access_token; $uuid = ''; if ($access_token) { switch ($this->type) { case 'qq': $url = "https://graph.qq.com/oauth2.0/me?access_token={$access_token}&unionid=1"; // 返回示例... /*callback({ "client_id":"YOUR_APPID", "openid":"YOUR_OPENID", "unionid":"YOUR_UNIONID" });*/ $result = $this->get_contents($url); if (strpos($result, "callback") !== false) { $lpos = strpos($result, "("); $rpos = strrpos($result, ")"); $result = json_decode(substr($result, $lpos + 1, $rpos - $lpos - 1), true); $uuid = isset($result['unionid']) ? $result['unionid'] : ''; } return $uuid; // return $openid; break; case 'weixin': $url = "https://api.weixin.qq.com/sns/userinfo?access_token={$access_token}&openid={$openid}"; // 返回示例 /*{ "openid":"OPENID", "nickname":"NICKNAME", "sex":1, "province":"PROVINCE", "city":"CITY", "country":"COUNTRY", "headimgurl": "http://wx.qlogo.cn/mmopen/g3MonUZtNHkdmzicIlibx6iaFqAc56vxLSUfpb6n5WKSYVY0ChQKkiaJSgQ1dZuTOgvLLrhJbERQQ4eMsv84eavHiaiceqxibJxCfHe/0", "privilege":[ "PRIVILEGE1", "PRIVILEGE2" ], "unionid": " o6_bmasdasdsad6_2sgVt7hMZOPfL" }*/ $result = json_decode($this->get_contents($url), true); return isset($result['unionid']) ? $result['unionid'] : ''; break; case 'weibo': return $openid; break; default: break; } } return $uuid; } /** * 获取access_token * @param boolean $true false表示获取原始结果,true获取真正的access_token * @return string json包|string */ public function getAccessToken($true = true) { //验证state if (Yii::$app->request->get('state', '') != Yii::$app->session->getFlash('oauth_state')) { return ''; } $redirect_uri = urlencode(Url::to(['login-by-openid', 'type' => $this->type], true)); $url = ''; switch ($this->type) { case 'qq': $url = "https://graph.qq.com/oauth2.0/token?grant_type=authorization_code&code={$this->code}&client_id={$this->app_id}&client_secret={$this->app_secret}&redirect_uri={$redirect_uri}"; //返回示例... //access_token=15C0CE01C0311240F9091A7DB6828E62&expires_in=7776000&refresh_token=7BFCE2E5B773D4F5531561A10E1C2B2D break; case 'weixin': $url = "https://api.weixin.qq.com/sns/oauth2/access_token?appid={$this->app_id}&secret={$this->app_secret}&code={$this->code}&grant_type=authorization_code"; //返回示例 /*{ "access_token":"ACCESS_TOKEN", "expires_in":7200, "refresh_token":"REFRESH_TOKEN", "openid":"OPENID", "scope":"SCOPE" }*/ break; case 'weibo': $url = "https://api.weibo.com/oauth2/access_token?client_id={$this->app_id}&client_secret={$this->app_secret}&grant_type=authorization_code&redirect_uri={$redirect_uri}&code={$this->code}";//新浪微博 $post_data = []; return $this->post($url, $post_data);//撒币制杖 //返回示例 /*{ "access_token": "SlAV32hkKG", "remind_in": 3600, "expires_in": 3600, "uid":"12341234" }*/ break; default: break; } if ($true) { $res_access_token = $this->get_contents($url); if ($this->type == 'qq' && strpos($res_access_token, "access_token") !== false) { $token_result = ['access_token' => explode('=', explode('&', $res_access_token)[0])[1]]; } else { $token_result = json_decode($res_access_token ?: '{}', true); } $access_token = !empty($token_result['access_token']) ? $token_result['access_token'] : ''; $this->access_token = $access_token; return $access_token; } else { return $this->get_contents($url); } } /** * post * post方式请求资源 * @param string $url 基于的baseUrl * @param array $keysArr 请求的参数列表 * @param int $flag 标志位 * @return string 返回的资源内容 */ public function post($url, $keysArr, $flag = 0) { $ch = curl_init(); if (!$flag) curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_POST, TRUE); curl_setopt($ch, CURLOPT_POSTFIELDS, $keysArr); curl_setopt($ch, CURLOPT_URL, $url); $ret = curl_exec($ch); curl_close($ch); return $ret; } /** * get_contents * 服务器通过get请求获得内容 * @param string $url 请求的url,拼接后的 * @return string 请求返回的内容 */ public function get_contents($url) { $ch = curl_init(); curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, FALSE); curl_setopt($ch, CURLOPT_RETURNTRANSFER, TRUE); curl_setopt($ch, CURLOPT_URL, $url); $response = curl_exec($ch); curl_close($ch); //-------请求为空 if (empty($response)) { return '{}'; } return $response; } /** * 获取openid * @return string openid */ public function getOpenid() { $res_access_token = $this->getAccessToken(false); if ($this->type == 'qq' && strpos($res_access_token, "access_token") !== false) { $access_token = ['access_token' => explode('=', explode('&', $res_access_token)[0])[1]]; } else { $access_token = json_decode($res_access_token ?: '{}', true); } $openid = ''; if (isset($access_token['access_token'])) { $this->access_token = $access_token['access_token']; switch ($this->type) { case 'qq': $url = "https://graph.qq.com/oauth2.0/me?access_token={$access_token['access_token']}"; // 返回示例... // callback( {"client_id":"101406183","openid":"6C611CBE0C72F765572AE2472C9B59A4"} ); $result = $this->get_contents($url); if (strpos($result, "callback") !== false) { $lpos = strpos($result, "("); $rpos = strrpos($result, ")"); $result = json_decode(substr($result, $lpos + 1, $rpos - $lpos - 1), true); $openid = isset($result['openid']) ? $result['openid'] : ''; } break; case 'weixin': return $access_token['openid']; break; case 'weibo': return $access_token['uid']; /*$url = "https://api.weibo.com/oauth2/get_token_info?access_token={$access_token['access_token']}"; //返回示例 { "uid": 1073880650, "appkey": 1352222456, "scope": null, "create_at": 1352267591, "expire_in": 157679471 } $result = $this->get_contents($url); $openid = isset($result['uid'])?$result['uid']:'';*/ break; default: break; } } return $openid; } }
使用方法如下:
//第三方登录界面处理 public function actionLoginByOpenid(){ Yii::$app->response->format= Response::FORMAT_HTML; $params = Yii::$app->request->get(); $oauth = new OauthLogin($params); if(empty($params['code'])){ $url = $oauth->getOauthUrl(); return $this->redirect($url); }else{ //微信代理跳转处理 if(isset($params['redirect']) && $params['redirect'] != $oauth->server){ $proxy = $oauth->proxy; $server = $params['redirect']; return $this->redirect(str_replace($proxy, $server, Url::current(['redirect'=>null], 'http'))); } $openid = $oauth->getUuid(); if (!$openid) { //失败处理TODO } else { //成功处理TODO } } }
具体流程(qq为例)如下:
1.用户点击QQ登陆图标,访问链接http://app.maxiye.cn/site/login-by-openid?type=qq
;
2.服务器处理获取QQ的授权链接,重定向;
3.QQ在回调地址中添加code参数(Authorization Code),回调http://app.maxiye.cn/site/login-by-openid?type=qq&state=4a78***&code=1CA8DF***
QQ, WeChat, Weibo 액세스 포인트:
신청 입구
: QQ는 QQ 인터넷, WeChat은 WeChat 개방형 플랫폼, Weibo는 Weibo 개방형 플랫폼2.콜백 도메인 설정: QQ는 먼저 설정할 수 있습니다. 수준 도메인 이름은 여러 개가 있을 수 있으며 http://
로 시작하고 ;
로 끝나야 합니다(예: http://maxiye.cn;http). ://yexima.com;
; WeChat은 2차 도메인 이름으로만 설정할 수 있으며 형식은 app.maxiye.cn
; 1차 도메인 이름도 설정할 수 있으며 maxiye.cn
중 하나입니다.
unionid 획득: 여러 앱(동일한 개발자 계정에
Pit: 1. QQ 인터페이스에서 반환되는 결과 중 상당수는
jsonp 형식에서 callback()
을 수동으로 제거해야 합니다.
2. Weibo 획득
post
를 사용해야 합니다. 🎜3. WeChat에서는 지원하지 않습니다. 콜백 주소는 1차 도메인 이름을 입력하므로 🎜통합 도메인 이름(에이전트)🎜을 콜백 주소로 사용한 다음 내부적으로 도메인 이름으로 리디렉션해야 합니다. 🎜🎜다음은 작성된 도구 클래스입니다. 🎜rrreee🎜사용 방법은 다음과 같습니다. 🎜rrreee🎜구체적인 프로세스(예: qq)는 다음과 같습니다. 🎜1. QQ 로그인 아이콘을 클릭하고 http://app.maxiye.cn/site/login-by-openid?type=qq
링크에 액세스합니다. 🎜2. 서버는 QQ의 인증 링크를 획득하고 리디렉션하는 과정을 수행합니다. 🎜3. QQ는 콜백 주소에 코드 매개변수(인증 코드)를 추가하고, 콜백 http://app.maxiye.cn/site/login-by-openid?type=qq&state=4a78***&code를 추가합니다. =1CA8DF***
; 🎜4. 서버는 code 매개변수에 따라 상태를 확인하고 access_token을 얻은 다음 Unionid(uid)를 얻은 후 결과를 처리합니다. 🎜🎜관련 권장사항: 🎜🎜🎜웹사이트에 제3자 로그인 PHP 버전 추가🎜🎜🎜🎜php QQ 제3자 로그인 SDK 프로그램 code_PHP 튜토리얼🎜🎜🎜🎜Sina Weibo 제3자 로그인🎜🎜🎜🎜🎜