【问题标题】:Yii2 SaaS AuthenticationYii2 SaaS 认证
【发布时间】:2019-09-18 07:03:14
【问题描述】:

我正在使用带有独立数据库架构的 Yii2 开发 SaaS 应用程序。我在使用租户数据库登录系统时遇到问题。

在登录表单中输入公司ID、用户名和密码后,我需要从公共数据库获取租户数据库详细信息并建立租户数据库连接。

这是我的 index.php 文件。

    <?php
       defined('YII_DEBUG') or define('YII_DEBUG', true);
       defined('YII_ENV') or define('YII_ENV', 'dev');
       require(__DIR__ . '/_protected/vendor/autoload.php');
       require(__DIR__ . '/_protected/vendor/yiisoft/yii2/Yii.php');
       $config = require(__DIR__ . '/_protected/config/web.php');

(new yii\web\Application($config));
if (Yii::$app->session->get('company')) :

    $appConnection = \app\models\Userdbconnections::find()->where(['company_id' => Yii::$app->session->get('company')])->one();
    \Yii::$app->dbDynamic->dsn = "mysql:host=localhost;dbname=$appConnection->dns";

    \Yii::$app->dbDynamic->username = $appConnection->user;

    \Yii::$app->dbDynamic->password = $appConnection->password;

    \Yii::$app->dbDynamic->charset = 'utf8';    
endif;
Yii::$app->run(); // this will run the application    
?>

从日志记录数据后的登录功能来看,身份验证控制器是这样的

if ( Yii::$app->request->post() ){
   $connection = \app\models\Userdbconnections::find()->where(['company_id'=>Yii::$app->request->post('LoginForm')['company']])->one();
                $_SESSION["dsn"] = $connection->dns;
                $_SESSION["user"] = $connection->user;
                $_SESSION["pass"] = $connection->password;
                $_SESSION["company_id"] = $connection->company_id;

               // Yii::$app->db()->close();

                Yii::$app->set('db', [
       'class' => '\yii\db\Connection',
       'dsn' => "mysql:host=localhost;dbname={$connection->dns}",
       'username' => $connection->user,
       'password' =>  $connection->password,
   ]);

                  $model_db = new LoginForm();
                  $model_db->load(Yii::$app->request->post());
                  $model_db->login();


                  $_SESSION["login_user"] = $model_db->username;
}

组件部分下web.php中调用的用户管理模块如下

'user' => [
        'class' => 'webvimark\modules\UserManagement\components\UserConfig',

        // Comment this if you don't want to record user logins
        'on afterLogin' => function($event) {

\webvimark\modules\UserManagement\models\UserVisitLog::newVisitor($event->identity->id);
        },
            'enableSession' =>true,
],

每个模型文件都包含以下代码

public static function getDb()

    {

        return Yii::$app->get('dbDynamic');

    }

所以现在我可以从租户数据库登录了。但是在检查后,我注意到当我登录到租户数据库时,用户管理部分、创建、角色创建所有这些都链接到公共数据库。这里有什么我想念的吗?

【问题讨论】:

    标签: database authentication yii2 saas


    【解决方案1】:

    一种方法是建立两个连接。来自通用数据库的通用详细信息的一个连接(用户详细信息、他所属的租户数据库等)。此连接是静态的,因此必须在配置中定义(或者只是将 Yii Basic 应用程序附带的内容重命名为 commonDb 或仅使用 db 名称。

    另一个将连接到特定的用户租户数据库。这将是动态的,细节必须改变。有很多方法可以做到这一点。一种是在应用程序运行之前定义它。 See this forum post for details。另一个是在请求之前使用 Yii Container 设置它并在你的模型等中调用它。可能还有其他方法。

    所以流程是这样的

    1. 用户登录。使用的连接是普通连接(定义为 Yii::$app->db)。
    2. 使用 (1) 中的详细信息创建动态连接。
    3. 在需要的地方使用连接(在模型、活动数据提供者或查询构建器中)

    这是未经测试的示例

    //common database with user login
    ----------------------------------
    | id   | name   | tenant_database |
    ----------------------------------
    |  1    | Stef  | company_a       |
    ----------------------------------
    

    请注意,Yii::$app-&gt;user-&gt;identity 将保存包装此表的模型类

    //config/web.php
    return [
        'components' =>[
            'db' => [
                'class' => 'yii\db\Connection',
                'dsn' => 'mysql:host=localhost;dbname=common_db',
                'username' => 'username',
                'password' => 'password',
                'charset' => 'utf8',
            ]
    
            'userDb' => [
                'class' => 'yii\db\Connection',
                'dsn' => 'mysql:host=localhost;dbname=${database}',
                'username' => 'username',
                'password' => 'password',
                'charset' => 'utf8',
            ]
        ]
        //set it up before request
        'on beforeRequest' => function ($event) {
            if(Yii::$app->user->isGuest)
            {
                // redirect user to Login page
            }
            else
            {
                $currentDSN = Yii::$app->userDb->dsn;
                $tenantDB = Yii::$app->user->identity->tenant_database;
                Yii::$app->userDb->dsn = str_replace('${database}', $tenantDB, $currentDSN);
            }
        },
    ]
    

    然后在模型类中覆盖getDb如下

    class Data extends \yii\db\ActiveRecord
    {
        public static function getDb()
        {
            return Yii::$app->userDb;
        }
    }
    

    然后按如下方式使用它:

    $data = Data::find()->all();
    $data = Yii::$app->userDb->createCommand('SELECT * FROM data')->queryAll();
    

    更新

    由于 OP 希望数据在租户数据库中,唯一的方法是让每个租户都有特殊的租户代码,并且在登录页面上,您将为 租户代码用户名提供输入密码。然后 1. 查询与该代码关联的数据库名称的公用表 2.如上图更改连接详情 3. 使用TenantLogin 类登录,该类使用租户连接,如上所示,使用Data 类。

    新的公用表

    ----------------------------
    | code   | tenant_database |
    ----------------------------
    | 12333  | company_a       |
    ----------------------------
    

    【讨论】:

    • 嗨,我想在登录前更改数据库连接,因为租户用户详细信息在租户数据库中
    • 那是错误的设计。所有用户都必须针对相同的公共数据库进行身份验证,成功后应检索数据库。如果您坚持自己的设计,请检查更新
    • 如果租户创建他们的用户,他们就在他们的数据库中。 bcoz 在创建用户时连接到他们的数据库
    • 嗨,我可以在登录前更改数据库。但是用户身份详细信息是从以前的连接中设置的。我该如何解决?
    • 你能解释一下你是怎么做到的吗?您是否遵循任何建议或您自己的建议?当我不知道你走哪条路时,我很难提供帮助
    猜你喜欢
    • 2010-09-20
    • 1970-01-01
    • 2014-08-05
    • 1970-01-01
    • 2016-02-01
    • 1970-01-01
    • 2015-10-18
    • 2016-06-13
    • 1970-01-01
    相关资源
    最近更新 更多