简体   繁体   English

Yii2 SaaS认证

[英]Yii2 SaaS Authentication

I'm Developing SaaS application using Yii2 with separate DB architecture. 我正在使用具有独立数据库架构的Yii2开发SaaS应用程序。 I have a problem in login to system by using tenant database. 使用租户数据库登录系统时出现问题。

I need to get tenant database details from common db and establish tenant db connection after entering company id, username and password in login form. 我需要从公共数据库获取租户数据库详细信息,并在登录表单中输入公司ID,用户名和密码后建立租户数据库连接。

This is my index.php file. 这是我的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    
?>

From login function after post logging data, auth controller is like this 从登录功能发布日志数据后,身份验证控制器是这样的

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;
}

User Management Module called in web.php under component part as following 在组件部分下的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,
],

Each model file consist with following code 每个模型文件均包含以下代码

public static function getDb()

    {

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

    }

So now i'm able to log from tenant db. 所以现在我可以从租户数据库登录了。 But after checking i noticed User Management part, creation, role creation all these linked to common db when ever i logged in to tenant db. 但是在检查之后,我登录到租户数据库时,注意到用户管理部分,创建,角色创建都链接到公共数据库。 Is there anything I misses in here? 我有什么想念的吗?

One way to do it is having two connections. 一种方法是具有两个连接。 One connection for common details coming from common database (user details, tenant db he belongs to, et al). 来自公共数据库的公共详细信息的一种连接(用户详细信息,他所属的租户db等)。 This connection is static, so must be defined in the config (or just rename what comes with Yii Basic app to something like commonDb or use it with just db name. 此连接是静态的,因此必须在配置中定义(或仅将Yii Basic应用附带的名称重命名为commonDb或者仅将其与db名称一起使用。

Another one will be connected to the specific user tenant database. 另一个将连接到特定的用户租户数据库。 This will be dynamic and details must change. 这将是动态的,细节必须改变。 There are many ways to do it. 有很多方法可以做到这一点。 One is to defined it before app runs. 一种是在应用运行之前对其进行定义。 See this forum post for details . 有关详细信息,请参见此论坛帖子 Another would be setting it up before request using Yii Container and call it inside your models et al. 另一个方法是在请求之前使用Yii Container进行设置,然后在模型内部调用等。 There might be other ways too. 可能还有其他方法。

So the process goes like this 所以过程是这样的

  1. User logs in. Connection used is the common connection (let it be defined as Yii::$app->db). 用户登录。使用的连接是公共连接(将其定义为Yii :: $ app-> db)。
  2. Using details from (1) create the dynamic connection. 使用(1)中的详细信息创建动态连接。
  3. Use the connections where needed (in models, Active data providers or Query builders) 在需要的地方使用连接(在模型,活动数据提供者或查询构建器中)

Here is untested example 这是未经测试的示例

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

Note here that Yii::$app->user->identity will hold model class that wraps this table 注意这里Yii::$app->user->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);
        }
    },
]

Then in model class override getDb as follows 然后在模型类中重写getDb ,如下所示

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

Then user it as in: 然后按以下方式使用它:

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

UPDATE 更新

Since OP wants the data to be in tenant db, the only way is having each tenant to have special Tenant Code, and on login page you will provide inputs for Tenant Code , Username and Password . 由于OP希望数据在租户db中,所以唯一的方法是让每个租户都具有特殊的租户代码,并且在登录页面上,您将为租户代码用户名密码提供输入。 Then 1. Query the common table for the database name associated with that code 2. Change Connection details as shown above 3. Login with TenantLogin class that uses tenant connection as shown above with Data class. 然后1.在公共表中查询与该代码关联的数据库名称。2.更改连接详细信息,如上所示。3.使用TenantLogin类登录,该类使用租户连接,如上所示与Data类。

The new common table 新的通用表

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM