-
近年来网络发展很快,参与网购的人越来越多,但是大家在网购的时候不知到有没有注意到无论是淘宝还是京东,他们用的都是二级域名,登录一个URL,登录成功后又是一个URL,作为一个开发者反正我是注意到了。
-
例如,淘宝登录的URL:https://login.taobao.com/memb…,登录成功的URL:https://www.taobao.com/?spm=a…。
-
或许大家可能觉得是多余,我一个URL就能搞定,为什么要整那么多个呢?麻烦。。。
-
大家可以想象一下,要是不把这两个模块分离的话,要是几千人,几万人,甚至上亿人同时登录的话,你就这么个服务器那不得崩了。所以思考如何实现这种跨域的SSO登录就显得尤为重要了。
需求分析
- 进入登录页面的URL地址:login.XXX.com
- 登录成功后跳转的URL地址:www.XXX.com 下面我主要是以Yii2框架为例解说一下我是怎么实现这种跨越的SSO登录的。
代码分析
结合需求,分布实施:
1、新建一个名为login的模块
把backend拷贝一份出来,改文件夹的名称为login,文件夹的名称改了大家可别忘了也把里边的文件的命名空间改一下,要不会找不到命名空间。对于多余的文件就把他删除了,省得占内存。至于删除啥保留啥的,就不详述了,因为这不是本文的重点,我这么跟你说吧,你需要用的就保留,不需要的通通删除。
复制时更改命名空间,environments下index.php等配置文件,common/config/bootstap.phpt添加下面代码
Yii::setAlias('@login', dirname(dirname(__DIR__)) . '/login');
2、写入配置信息
在common/config/main.php顶部加上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加下这么一段代码:
Yii::setAlias('login', dirname(dirname(__DIR__)) . '/login'); //增加自定义目录结构
在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”)
]
],
// 或者
'urlManager' => [
'class' => 'common\components\MutilpleDomainUrlManager',
'domains' => [
'backend' => '//' . DOMAIN_BACKEND,
// 'frontend' => '//' . DOMAIN_HOME,
'img' => '//' . DOMAIN_IMG,
'api' => '//' . DOMAIN_API,
'login' => '//' . DOMAIN_LOGIN,
],
// 'baseUrl' => '//' . DOMAIN_HOME, # Default BaseUrl 公用头部时,其他链接点击会是/site/index 为主域名下的DOMAIN_HOME/site/index
'showScriptName' => false,
'enablePrettyUrl' => true, //美化URL
'enableStrictParsing' => true, //设置有无‘s’;
// 'suffix' => ".php",
'rules' => ['' => 'site/login', // 如果没有这里,则访问域名不能直接打开默认Action (去除URL的“site/login”)
//此处设置默认登录login.bj.com的默认方法指向到site/login登录方法
'<controller:\w+>/<action:\w+>' => '<controller>/<action>',
]
],
3、新建一个MutilpleDomainUrlManager.php文件
MutilpleDomainUrlManager.php,这个文件按照我给你们的命名空间存放。
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
4、修改SiteController.php的Login方法
login模块
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,
]);
}
}
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,
]);
}
}
}
//或者
public function actionLogin()
{
return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_HOME);
}
/**
* Logs out the current user.
*
* @return mixed
*/
public function actionLogout()
{
return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_HOME);
}
到此,主要部分已经大致完成,login域名登录,共享session。