码疯窝

YII2 配置 SSO (Single Sign-on) 实现单登陆

2015/01/23 12:02:28    分类: 技术随笔    10人评论 次浏览

SSO (Single Sign-on) 顾名思义就是几个子项目共用一个登录点. 原理简单来说就是服务端session 共享, 客户端跨域cookies.
最近一个YII2的项目正好需要实现SSO, 可是在网上搜了半天没有找到一个解决方案. 于是研究了一下源代码.
其实在Yii2只需要配置 config就能实现.
在config 头加上domain信息

$host = explode('.', $_SERVER["HTTP_HOST"]);
if (count($host) > 2) {
    define('DOMAIN', $host[1] . '.' . $host[2]);
} else {
    define('DOMAIN', $host[0] . '.' . $host[1]);
}
define('DOMAIN_HOME', 'www.' . DOMAIN);
define('DOMAIN_USER_CENTER', 'man.' . DOMAIN);
define('DOMAIN_API', 'api.' . DOMAIN);
define('DOMAIN_EMAIL', 'mail.' . DOMAIN);
define('DOMAIN_LOGIN', 'login.' . DOMAIN);
define('DOMAIN_IMG', 'img.' . DOMAIN);

然后配置User 和 Session:

'user' => [
    'enableAutoLogin' => true,
    'identityCookie' => ['name' => '_identity', 'httpOnly' => true, 'domain' => '.' . DOMAIN],
],
'session' => [
    'cookieParams' => ['domain' => '.' . DOMAIN, 'lifetime' => 0],
    'timeout' => 3600,
],

这样单点登陆基本实现, 从login.xxx.com 登陆后, 去到www.xxx.com session 依然有效果.
另外, 我修改了 urlManager, 使之可以生成其它domain的URL.

'urlManager' => [
    'class' => 'common\components\MutilpleDomainUrlManager',
    'domains' => [
        'man' => '//' . DOMAIN_USER_CENTER,
        'mail' => '//' . DOMAIN_EMAIL,
        'img' => '//' . DOMAIN_IMG,
        'api' => '//' . DOMAIN_API,
        'login' => '//' . DOMAIN_LOGIN,
    ],
    'baseUrl' => '//' . DOMAIN_HOME,   # Default BaseUrl
    'showScriptName' => false,
    'enablePrettyUrl' => true,
],

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
继续查看有关 技术随笔的文章

10个访客评论

  1. 浩亮

    博主好, 有些疑问: Yii 2 获取用户信息时都会去查下数据库, 难道每个系统(对应的每个域名)都要有一个统一的用户model和同步的user表?
    这样看来, 您应该使用的 advanced-template, 用的一个数据库对吧?
    那如果是多个基于advanced-template应用呢? 您有过经验和想法吗?
    附上我找到的另外一篇参考, 跟您的做法差不多。 http://www.yiiframework.com/wiki/135/single-sign-on-across-multiple-subdomains
    ps: 编辑器不太好用, 插入链接失败

    qweqwe Reply
    • Gcaufy

      你好, 首先我没有用过advanced-template, 也不太了解这个是做什么的. 另外, 那篇文章跟我做法是一样的, 我的就是多了一个createUrl的处理. 只需要session 共用就行了, 系统是从session里面读取到用户identity的. 并非每次都会查数据库.

      qweqwe Reply
  2. 小二郎

    【在config 头加上domain信息】,这里的config头指的是/common/config/中的main.php还是指所有的呢?

    qweqwe Reply
    • Gcaufy

      /common/config/main.php

      qweqwe Reply
  3. 冯总

    good

    qweqwe Reply
  4. PHP网站开发

    确定这样可以??我试过了,就不行,,,,,,,,,,,,,,,,

    qweqwe Reply
    • Gcaufy

      很久的文章了,这个自然是我自己测试过了的。

      qweqwe Reply
      • PHP网站开发

        那还请留一个QQ号码,指教一下实现,,,实在试不出来;

        qweqwe Reply
        • Gcaufy

          QQ很少用了,加我微信:gcaufy。

          qweqwe Reply