如何在 Laravel 中根据客户端请求动态设置数据库

Posted

技术标签:

【中文标题】如何在 Laravel 中根据客户端请求动态设置数据库【英文标题】:How to set database dynamically based on client request in Laravel 【发布时间】:2022-01-17 03:15:55 【问题描述】:

我使用 Laravel 应用程序作为后端,并希望通过 axios 请求动态设置数据库连接(并保持它直到页面刷新),该请求将包含要使用的数据库和凭据。

为此,我将接收到的数据库配置存储在会话中,并在我尝试使用的任何控制器的构造函数中设置环境变量。

以下是 .env 中的默认数据库设置:

DB_DATABASE=database1
DB_USERNAME=username1
DB_PASSWORD=password1

但是,问题似乎是会话没有保持活动状态,因为每个发送的请求都包含不同的会话 ID,因此每当我尝试与数据库交互时都会返回访问被拒绝错误,因为会话变量未定义。

以下是客户端发送请求的方式:

axios
.post("https://data-test.io/api/Setconnection", 
  database: "database2",
  username: "username2",
  password: "password2",
)
.then((result) => 
  // console.log(result);
  // do stuff here
);

这就是我在会话中存储数据库连接的方式:

    class RootController extends Controller

    public function setConnection(Request $request)
        session(['database' => $request->database]);
        session(['username' => $request->username]);
        session(['password' => $request->password]);    
        return $request->session()->all(); // this returns the correct values
    

我在 api.php 中设置了这样的路由:

    Route::post('/Setconnection',[RootController::class, 'setConnection']);

然后,在所有后续请求中,我以这种方式在构造函数中设置连接:

 public function __construct() 
            Artisan::call('config:cache');
            Config::set('database', session('database'));
            Config::set('username', session('username'));
            Config::set('password', session('password'));    


public function getConfig()
           return [session('database'),session('username'),session('password')]; 
           // this returns an array of undefined elements.

我在这里犯了一个错误,或者这不是我应该如何动态设置数据库连接?如果没有,那么最好的方法是什么?

【问题讨论】:

当你使用 Laravel 作为后端时,它基本上是一个 API,API 应该是“无状态的”;每次访问时都很新鲜。您的setConnection 逻辑需要针对每个请求运行,例如通过中间件。这基本上就是“登录”到 API 的工作原理;登录,获取令牌,将该令牌与 每个 后续请求一起发送以验证登录/身份。您可以为此使用相同的逻辑,但您需要重新考虑您的方法。 @TimLewis 在这种情况下,鉴于我不想在身份验证过程中使用数据库,哪种方法可以完成这项工作?阅读 Laravel Docs 我看到 Laravel Sanctum 需要建立一个数据库。所以也许发行 JWT 令牌可以在不需要数据库的情况下完成? 如果您不想使用数据库,这在技术上是可以的,但是您需要一些方法来确定要使用的数据库。如果您有一组预定义的连接,那么您可以简单地使用connection: 1(或其他东西)向您的axois 请求添加一个全局标题,并验证在每个请求上调用setConnection 时等等等等。 请使用租赁套餐。哪个会为您做到这一点 tenancy.dev 【参考方案1】:

正如蒂姆刘易斯所说,API 应该是“无状态”的,没有以前存储的数据可以在每个事务/请求中使用。如果您不想使用数据库来存储动态数据库凭据,则需要在客户端保存动态数据库凭据并在每个请求中发送它们。

但如果你真的想创建可以在 API 中使用会话的“有状态”,你可以关注these instructions。

然后要更改数据库配置,您应该使用Config::set('database.connections.dbdrivername.configname','configvalue'),不需要Artisan::call('config:cache')

一个例子:

Config::set('database.connections.mysql.database', session('database'));
Config::set('database.connections.mysql.username', session('username'));
Config::set('database.connections.mysql.password', session('password'));

您应该真正知道自己在做什么,因为它可能存在很大的安全漏洞。

【讨论】:

以上是关于如何在 Laravel 中根据客户端请求动态设置数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何在 laravel 8 中动态设置速率限制器

如何设置servlet中并发请求数的限制?

如何根据请求域动态设置 SSL 证书?

如何根据输入请求规则在 laravel 刀片中显示错误消息

如何在 Spring Framework 4.2/Boot 1.3 中根据 Origin HTTP 请求标头设置动态 Access-Control-Allow-Origin?

在 laravel 中动态设置菜单项的活动类