连接到多个数据库的Laravel API

连接到多个数据库的Laravel API,api,laravel-5,multiple-databases,connection,lumen,Api,Laravel 5,Multiple Databases,Connection,Lumen,我正在用Laravel(Lumen)构建一个restapi。这个API为多个食品订购网站提供了后端。它们共享相同的后端逻辑(模型、控制器等)。这样每个网站只需要它自己的前端应用程序,我计划使用Angular。每个网站都有自己的数据(产品、页面等),这些数据必须存储在不同的数据库中 出于测试目的,我在config/databases.php中定义了多个连接。现在我可以在查询相应的数据库之前动态设置连接,如下所示: class ProductController extends Controller

我正在用Laravel(Lumen)构建一个restapi。这个API为多个食品订购网站提供了后端。它们共享相同的后端逻辑(模型、控制器等)。这样每个网站只需要它自己的前端应用程序,我计划使用Angular。每个网站都有自己的数据(产品、页面等),这些数据必须存储在不同的数据库中

出于测试目的,我在
config/databases.php
中定义了多个连接。现在我可以在查询相应的数据库之前动态设置连接,如下所示:

class ProductController extends Controller
{
    /**
     * Display a listing of the resource.
     *
     * @return Response
     */
    public function index()
    {   
        $products = new Product;
        $products->setConnection('customer_two'); // <--
        $products = $products->get();

        return response()->json($products);
    }
}
类ProductController扩展控制器
{
/**
*显示资源的列表。
*
*@返回响应
*/
公共职能指数()
{   
$products=新产品;
$products->setConnection('customer_two');//get();
return response()->json($products);
}
}
例如,缓存也可以做到这一点


让API知道哪个客户的网站提出了请求的最佳方式是什么?我需要指向正确的数据库。此外,这种方法在性能方面会导致任何问题吗?

我会使用双管齐下的方法来解决这个问题,我会使用第一种方法,而不使用第二种方法

第一种是基于您使用请求api的路由。例如,您可以使用前缀定义路由,如
/api/{site}
。这样,所有api端点都将基于请求的站点变量。例如,
/api/site1/login
将使用数据库
site1
/api/site2/login
将使用数据库
site2

第二部分是像上面提到的那样使用JWT进行身份验证,并在每个请求中使用中间件检查经过身份验证的用户是否确实是该特定站点用户的一部分。这只适用于经过身份验证的路由,但仍然会导致未经身份验证的路由被滥用,但是,如果您的站点上有合法用户,并且您的站点正在从api请求数据,则您应该返回正确的
站点
数据,并且任何恶意访问都将获取公共数据

还有第三种选择。使用JWT,您可以创建自定义声明。这些自定义声明可用于存储正在使用的站点以及要访问的数据库。我自己没有这样做,但一直在考虑做一些类似的事情,根据我的API对客户端进行身份验证,以及在此基础上进行基于用户的身份验证。这意味着每个端点至少都要经过客户端身份验证,其他端点也要经过用户身份验证和客户端身份验证

使用中间件在运行时轻松更改数据库连接

中间件:app/Http/Middleware/DatabaseConnectionChooser.php

<?php namespace App\Http\Middleware;

use Closure;
use Illuminate\Routing\Route;

class DatabaseConnectionChooser
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        /** @var Route $route */
        $route = app('router')->getRoutes()->match($request);

        $connection = $route->getParameter('connection');

        app('db')->setDefaultConnection($connection);

        return $next($request);
    }
}
创建路由以指定站点,即数据库连接

app/Http/routes.php

app('router')->get('/{connection}/', function () {
    return app('db')->getDefaultConnection();
});
在配置中设置数据库连接

config/database.php

'connections' => [
    ...

    'site1' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge1'),
        'username'  => env('DB_USERNAME', 'forge1'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
    ],

    'site2' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge2'),
        'username'  => env('DB_USERNAME', 'forge2'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
    ],

    ...
]

您的API上有身份验证吗?或者你不需要它?是的,我将使用JWT()让管理员登录和管理他们的站点。但并非所有路由都需要令牌来检索数据。谢谢您的回答。然而,未经验证的路由仍然会被滥用,如果您的站点上有合法用户,并且您的站点正在从api请求数据,那么您应该返回正确的站点数据,并且任何恶意访问都只会获取公共数据。我应该想到哪种滥用?此外,客户端身份验证和用户身份验证之间的区别对我来说也不是很清楚。我知道angular会自动发送带有请求的“X-CSRF-TOKEN”,laravel会在POST请求中进行检查。这种滥用不是来自您自己的网站本身,而是来自其他来源的外部恶意攻击。由于您有open GET请求,因此可以从任何地方访问这些请求,例如用于DDOS攻击,等等。对于客户端与用户身份验证,区别在于:基于身份验证使用用户名/电子邮件和密码来验证用户,而基于客户端的身份验证使用某种标识符或证书/令牌来验证应用程序,例如,客户端可以是angular应用程序或移动应用程序。这里的诀窍是在不泄露密钥/令牌的情况下对应用程序(客户端)进行身份验证。希望这有帮助。你知道在Laravel中动态设置连接(正如我在帖子中所展示的)是否有任何缺点吗?因为Laravel需要不断地(重新)连接到不同的数据库?我想你的方法可能会出错,因为数据库连接是在控制器中设置的,所以如果你在一条路由中错过了一个连接,它将无法按预期工作。我的建议是使用一种中间件方法,该方法设置为在每个请求上全局运行——这样,您就可以在点击控制器之前将连接设置到正确的数据库。为新答案添加代码。
'connections' => [
    ...

    'site1' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge1'),
        'username'  => env('DB_USERNAME', 'forge1'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
    ],

    'site2' => [
        'driver'    => 'mysql',
        'host'      => env('DB_HOST', 'localhost'),
        'database'  => env('DB_DATABASE', 'forge2'),
        'username'  => env('DB_USERNAME', 'forge2'),
        'password'  => env('DB_PASSWORD', ''),
        'charset'   => 'utf8',
        'collation' => 'utf8_unicode_ci',
        'prefix'    => '',
        'strict'    => false,
    ],

    ...
]