Heim  >  Artikel  >  Backend-Entwicklung  >  全面解析Yii2跨域的SSO登陆逻辑

全面解析Yii2跨域的SSO登陆逻辑

WBOY
WBOYOriginal
2016-06-20 12:26:231101Durchsuche

简述

本文章是我对Yii2如何实现SSO登陆做一个全面的逻辑解析。事实上,在此之前我也写过两篇文章关于SSO登录的实现方式以及进一步优化,包括这篇文章也都是介绍Yii2的SSO登录,逐步优化不断总结与分享,目的就是要把Yii2的SSO登录功能尽可能的做到极致,从程序开发的灵活性角度去思考问题,把一切潜在的局限扼杀在摇篮中。

实现步骤

1、在commonconfigmain.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模块,然后打开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,这个文件按照我给你们的命名空间存放。

<?phpnamespace 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标签这么输出

注:在其它模块如: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了,这是不对的。

Stellungnahme:
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn