關於Yii2如何實現跨域的SSO登陸的解析

序言

近年來網絡發展很快,參與網購的人愈來愈多,可是你們在網購的時候不知到有沒有注意到不管是淘寶仍是京東,他們用的都是二級域名,登陸一個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...

全文完,若有不足或者更好的方式方法,歡迎你們踊躍提出,咱們一塊兒相互交流學習。

相關文章
相關標籤/搜索