簡述
本文章是我對Yii2如何?SSO登陸做一個全面的邏輯解析。事實上,在此之前我也寫過兩篇文章關於SSO登入的實現方式以及進一步最佳化,包括這篇文章也都是介紹Yii2的SSO登入,逐步最佳化不斷總結與分享,目的就是要把Yii2的SSO登入功能儘可能的做到極致,從程式開發的靈活性角度去思考問題,把一切潛在的局限扼殺在搖籃中。
實現步驟
1、在commonconfigmain.php檔案配置如下:
[ '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模組,然後開啟commonconfigbootstrap.php加下這麼一段代碼:
Yii::setAlias('login', dirname(dirname(__DIR__)) . '/login'); //增加自訂目錄結構
3、在loginconfigmain.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,這個檔案按照我給你們的命名空間存放。
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標籤這麼輸出。
註:在其它模組如: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了,這是不對的。