欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  后端开发

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

程序员文章站 2022-06-05 13:54:43
...

简述

本文章是我对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了,这是不对的。