近年来网络发展很快,参与网购的人愈来愈多,可是你们在网购的时候不知到有没有注意到不管是淘宝仍是京东,他们用的都是二级域名,登陆一个URL,登陆成功后又是一个URL,做为一个开发者反正我是注意到了。php
例如,淘宝登陆的URL:https://login.taobao.com/memb...,登陆成功的URL:https://www.taobao.com/?spm=a...。html
或许你们可能以为是多余,我一个URL就能搞定,为何要整那么多个呢?麻烦。。。web
你们能够想象一下,要是不把这两个模块分离的话,要是几千人,几万人,甚至上亿人同时登陆的话,你就这么个服务器那不得崩了。因此思考如何实现这种跨域的SSO登陆就显得尤其重要了。bootstrap
一、进入登陆页面的URL地址:login.XXX.com
二、登陆成功后跳转的URL地址:www.XXX.com
下面我主要是以Yii2框架为例解说一下我是怎么实现这种跨越的SSO登陆的。segmentfault
结合需求,分布实施:api
一、新建一个名为login的模块
把backend拷贝一份出来,改文件夹的名称为login,文件夹的名称改了你们可别忘了也把里边的文件的命名空间改一下,要不会找不到命名空间。对于多余的文件就把他删除了,免得占内存。至于删除啥保留啥的,就不详述了,由于这不是本文的重点,我这么跟你说吧,你须要用的就保留,不须要的统统删除。跨域
二、写入配置信息
2.一、在commonconfig顶部加上domain信息,配置如下代码:浏览器
$host_array = explode('.', $_SERVER["HTTP_HOST"]); if (count($host_array) == 3) { define('DOMAIN', $host_array[1] . '.' . $host_array[2]); } //针对com.cn域名 elseif (count($host_array) == 4) { define('DOMAIN', $host_array[1] . '.' . $host_array[2]. '.' . $host_array[3]); }else{ //echo "本系统不支持本地访问,请配置域名";exit; } // echo 'www.' . DOMAIN;exit; define('DOMAIN_HOME', 'www.' . DOMAIN); // define('DOMAIN_API', 'api.' . DOMAIN); define('DOMAIN_LOGIN', 'login.' . DOMAIN); // define('DOMAIN_IMG', 'img.' . DOMAIN);
而后在components里配置User 和 Session:服务器
'user' => [ 'identityClass' => 'login\models\User', 'enableAutoLogin' => true, 'identityCookie' => ['name' => '_identity', 'httpOnly' => true,'domain' => '.' . DOMAIN], // 'returnUrl'=>'//' . DOMAIN_HOME, ], 'session' => [ 'cookieParams' => ['domain' => '.' . DOMAIN, 'lifetime' => 0], 'timeout' => 3600, ],
以上配置完了以后,打开commonconfigbootstrap.php加下这么一段代码:cookie
Yii::setAlias('login', dirname(dirname(__DIR__)) . '/login'); //增长自定义目录结构
2.二、在loginconfig里修改 urlManager,改为下面这样子:
'urlManager' => [ 'class' => 'common\components\MutilpleDomainUrlManager', 'domains' => [ 'backend' => '//' . DOMAIN_BACKEND, // 'mail' => '//' . DOMAIN_EMAIL, // 'img' => '//' . DOMAIN_IMG, // 'api' => '//' . DOMAIN_API, 'login' => '//' . DOMAIN_LOGIN, ], // 'baseUrl' => '//' . DOMAIN_HOME, # Default BaseUrl 'showScriptName' => false, 'enablePrettyUrl' => true, //美化URL 'enableStrictParsing' => true, //设置有无‘s’; // 'suffix' => ".php", 'rules' => [ '' => 'site/login', // 若是没有这里,则访问域名不能直接打开默认Action (去除URL的“site/login”) ] ],
三、新建一个MutilpleDomainUrlManager.php文件
MutilpleDomainUrlManager.php,这个文件按照我给大家的命名空间存放。
namespace common\components; use Yii; class MutilpleDomainUrlManager extends \yii\web\UrlManager { public $domains = array(); public function createUrl($domain, $params = array()) { if (func_num_args() === 1) { $params = $domain; $domain = false; } $bak = $this->getBaseUrl(); if ($domain) { if (!isset($this->domains[$domain])) { throw new \yii\base\InvalidConfigException('Please configure UrlManager of domain "' . $domain . '".'); } $this->setBaseUrl($this->domains[$domain]); } $url = parent::createUrl($params); $this->setBaseUrl($bak); return $url; } }
附:这样咱们可使用如下代码生成其它domain url
Yii::$app->urlManager->createUrl('site/index'), # www.xxx.com/site/index Yii::$app->urlManager->createUrl('login', 'site/login'), # login.xxx.com/site/login Yii::$app->urlManager->createUrl('article/list'), # login.xxx.com/article/list Yii::$app->urlManager->createUrl('man', 'user/view'), # man.xxx.com/user/view
四、修改SiteController.php的Login方法
4.一、login模块
login\controllers\SiteController.php public function actionLogin() { $URL=Yii::$app->request->get('redirectURL'); $model = new LoginForm(); //判断是否已登陆,非为登录 if (!\Yii::$app->user->isGuest) { $this->actionLogout();//强制性退出 return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_HOME); } if ($model->load(Yii::$app->request->post()) && $model->login()) { if(empty($URL)){ return $this->redirect('http://'.DOMAIN_HOME,301); }else{ return $this->redirect($URL,301); } // return $this->goBack(); } else { return $this->renderPartial('login', [ 'model' => $model, ]); } }
4.二、frontend模块
frontend\controllers\SiteController.php public function actionLogin() { $URL=Yii::$app->request->get('redirectURL'); //判断是否已登陆,非为登录 if (!\Yii::$app->user->isGuest) { // return $this->goHome(); $this->actionLogout();//强制性退出 return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_HOME); } $model = new LoginForm(); if ($model->load(Yii::$app->request->post()) && $model->login()) { return $this->goBack(); } else { if(empty($URL)){ return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_HOME); }else{ return $this->renderPartial('login', [ 'model' => $model, ]); } } }
五、视图渲染
5.1在frontendviewslayoutsmain.php的顶部加入红框的代码
5.二、最后在退出的a标签这么输出<?php echo $redirectURL; ?>。
OK,到这里就所有完成了,这时候你们能够测试一下,你会惊奇的发现Yii2跨域的SSO登陆已经实现了。哈哈。。。
一、手动输入login.XXX.com进入登陆页面成功了,关闭浏览器后,再从新打开,地址栏输入www.XXX.com仍是登陆状态。
解决方式:
在login的方法里边的验证是否已登陆调用“ $this->actionLogout()”退出方法,而后给他个重定向的URL,如:return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_ADMIN),这样就能防止你在地址栏输入login.XXX.com进入到登陆页面了还退出不成功的问题。
参考代码: //判断是否已登陆,非为登录 if (!\Yii::$app->user->isGuest) { $this->actionLogout();//强制性退出 return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_ADMIN); }
二、使用Yii::$app->urlManager->createUrl('login', 'site/login')这种方式生成
domain url在视图没法生成的问题,缘由是这种方式只能在控制器里面使用。
Yii2 配置 跨域登陆实例:http://www.kuitao8.com/201505...
Yii2 如何利用redirect让页面自动跳转到外站?:https://segmentfault.com/q/10...
全文完,若有不足或者更好的方式方法,欢迎你们踊跃提出,咱们一块儿相互交流学习。