周全剖析Yii2跨域的SSO登录逻辑

简述

本文章是我对Yii2怎样完成SSO登录做一个周全的逻辑剖析。事实上,在此之前我也写过两篇文章关于SSO登录的完成体式格局以及进一步优化,包含这篇文章也都是引见Yii2的SSO登录,逐渐优化不停总结与分享,目标就是要把Yii2的SSO登录功用尽量的做到极致,从顺序开辟的灵活性角度去思考问题,把统统潜伏的范围抹杀在摇篮中。

完成步骤

1、在common\config\main.php文件设置以下:

<?php  
use kartik\mpdf\Pdf;
//动态猎取无www的域名
$host_array = explode('.', $_SERVER["HTTP_HOST"]); 
if (count($host_array) == 3) {    
     if(strpos($_SERVER["HTTP_HOST"],':')){  //推断域名是不是存在端口号
         $domain_array=explode(':', $host_array[2]);
         define('DOMAIN', $host_array[1] . '.' . $domain_array[0]);//去掉端口号,防止域名带端口号没法退出
     }else{
        define('DOMAIN', $host_array[1] . '.' . $host_array[2]);
     }  
}
//针对com.cn域名
elseif (count($host_array) == 4) {   
    if(strpos($_SERVER["HTTP_HOST"],':')){
         $domain_array=explode(':', $host_array[3]);
         define('DOMAIN', $host_array[1] . '.' . $host_array[2]. '.' . $domain_array[0]);
    }else{
        define('DOMAIN', $host_array[1] . '.' . $host_array[2]. '.' . $host_array[3]);
    }  
}else{
    //echo "本系统不支持当地接见,请设置域名";exit;
}

//将动态猎取到的无www域名,设置上www、crm...
define('DOMAIN_HOME', 'www.' . DOMAIN);
define('DOMAIN_CRM', 'crm.' . DOMAIN);
define('DOMAIN_HR', 'hr.' . DOMAIN);
define('DOMAIN_WEIXIN', 'weixin.' . DOMAIN);
define('DOMAIN_ADMIN', 'admin.' . DOMAIN);
define('DOMAIN_OA', 'oa.' . DOMAIN);
define('DOMAIN_FRONTEND', 'frontend.' . DOMAIN);
define('DOMAIN_BACKEND', 'backend.' . DOMAIN);

define('DOMAIN_API', 'api.' . DOMAIN);
define('DOMAIN_LOGIN', 'login.' . DOMAIN);

设置User 和 Session:
'components' => [
        'user' => [            
            'identityClass' => 'login\models\User',
            'enableAutoLogin' => true,
            'identityCookie' => ['name' => '_identity', 'httpOnly' => true,'domain' => '.' . DOMAIN],
            // 'returnUrl'=>'//' . DOMAIN_HOME,
        ],        
        'session' => [           
            'cookieParams' => ['domain' => '.' . DOMAIN, 'lifetime' => 0],            
            'timeout' => 24*3600*30,
        ],

2、新建一个login模块,然后翻开common\config\bootstrap.php加下这么一段代码:

Yii::setAlias('login', dirname(dirname(__DIR__)) . '/login'); //增添自定义目次构造

3、在login\config\main.php里修正 urlManager,改成下面这模样:


        'urlManager' => [
            'class' => 'common\components\MutilpleDomainUrlManager',
            'domains' => [
                'crm' => '//' . DOMAIN_CRM,
                'admin' => '//' . DOMAIN_ADMIN,
                'hr' => '//' . DOMAIN_HR,
                'oa' => '//' . DOMAIN_OA,
                'frontend' => '//' . DOMAIN_FRONTEND,
                'backend' => '//' . DOMAIN_BACKEND,
            //     'img' => '//' . DOMAIN_IMG,
                'api' => '//' . DOMAIN_API,
                'login' => '//' . DOMAIN_LOGIN,
            ],

            //'baseUrl' => 'http://'.DOMAIN_LOGIN.'?redirectURL=http://'.DOMAIN_HOME,
            'showScriptName' => false,
            'enablePrettyUrl' => true,  //美化URL
            'enableStrictParsing' => true, //设置有没有‘s’;  
            // 'suffix' => ".php",  
            'rules' => [ '' => 'site/login',
                        // 假如没有这里,则接见域名不能直接翻开默许Action (去除URL的“site/login”) 
            ]   
        ],

4、补充第3步骤缺乏的MutilpleDomainUrlManager.php文件
MutilpleDomainUrlManager.php,这个文件根据我给你们的定名空间寄存。

<?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。

5、修正login模块下的SiteController.php Login要领

    //登录
    public function actionLogin()
    {    
        //猎取当前的URL
        $URL=Yii::$app->request->getHostInfo().Yii::$app->request->url;
        $URL1='http://'.DOMAIN_CRM; 
        $redirectURL=Yii::$app->request->get('redirectURL'); 
        $redirectURL1='http://'.DOMAIN_LOGIN; 

        $model = new LoginForm();
        TagDependency::invalidate(Yii::$app->cache, ['Session:'.Yii::$app->session->id]);
 
        //考证是不是已登录,非为登录
        if (!\Yii::$app->user->isGuest) {  
           if(!empty($redirectURL)){
                $this->actionLogout();//强制性退出登录
               
                return $this->redirect($URL);

           }else{ 
                //redirectURL不存在时,提交表单推断
                if($this->siteLogin){     
                   if ($model->load(Yii::$app->request->post()) && $model->login()) { 
                       //推断该账号是不是制止登录 
                       if(empty($t_status=$model->user->attributes['t_status']) && $t_status==0){ 
                           return $this->error($redirectURL1,[Yii::t('yii','The account is prohibited from logging in, please contact the administrator!')]);
                       }else{ 
                            if(empty($redirectURL)) return $this->redirect($URL1,301); 

                            return $this->redirect($redirectURL,301);
                        }          
                    } else { 
                        return $this->renderPartial('login', [
                            'model' => $model,
                        ]);
                    }
                }else{ 
                    return $this->goHome();
                }  
           }  
        } else {

            //redirectURL存在时,提交表单推断
            if ($model->load(Yii::$app->request->post()) && $model->login()) {     
                 //推断该账号是不是制止登录
                 if(empty($t_status=$model->user->attributes['t_status']) && $t_status==0){ 
                    if(empty($redirectURL)){
                        return $this->error($redirectURL1,[Yii::t('yii','The account is prohibited from logging in, please contact the administrator!')]);
                    }
                    return $this->error($URL,[Yii::t('yii','The account is prohibited from logging in, please contact the administrator!')]);
                 }else{ 
                    if(empty($redirectURL)) return $this->redirect($URL1,301); 
               
                    return $this->redirect($redirectURL,301);
                 }        
            } else {   
                return $this->renderPartial('login', [
                    'model' => $model,
                ]);
            }
        }
    }

6、修正frontend模块下的SiteController.php Login要领

 public function actionLogin()
    {  
        //猎取上一个URL
        $URL=Yii::$app->request->getHostInfo().Yii::$app->user->getReturnUrl();  
        if (!\Yii::$app->user->isGuest) { 
            return $this->redirect('http://'.DOMAIN_LOGIN.'?redirectURL='.$URL);
        }
        $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='.$URL);
            }else{ 
                return $this->renderPartial('login', [
                                'model' => $model,
                            ]);
            }
        }
    }

7、在frontendviewsdefaultlayoutsmain.php的顶部到场下面代码

$redirectURL='http://'.DOMAIN_LOGIN.'?redirectURL='.Yii::$app->request->getHostInfo().Yii::$app->request->url;

8、末了在退出的a标签这么输出<?php echo $redirectURL; ?>。

注:在别的模块如:backend、crm等等当中仿制我这frontend的完成思绪改改,即可完成全部项目标SSO登录机制。

提示注重

1、在第1步骤中,动态猎取无www的域名,此步骤必需做域名的推断处置惩罚,比方:www.xxx.com,www.xxx.com.cn,www.xxx.com:8099等这些能够涌现的域名,以保证域名都能运用完成登录退出的机制。
2、在第5步骤和第7步骤中,运用Yii2自带的要领Yii::$app->request->getHostInfo().Yii::$app->request->url猎取当前的url,是比较轻易且高效的一种做法,能下降代码的冗余。
3、在第6步骤中的frontend模块下的SiteController.php Login要领里,用Yii2自带的要领Yii::$app->request->getHostInfo().Yii::$app->user->getReturnUrl()猎取上一个url,这里必需特别注重是猎取“上一个url”而不是当前的url,猎取当前的url就变成了login.xxx.com了,这是不对的。

相干材料

Yii: 猎取URL的一些要领:http://blog.csdn.net/iefreer/…

    原文作者:zacklee
    原文地址: https://segmentfault.com/a/1190000005669675
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞