Laravel API 连接多个数据库 [英] Laravel API connecting to multiple databases

查看:43
本文介绍了Laravel API 连接多个数据库的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

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

I'm building a REST API with Laravel (Lumen). The idea is that this API provides the back-end for multiple food-ordering websites. They share the same back-end logic (models, controllers etc.). This way each website only needs it's own front-end application, I'm planning to use Angular for this. Each website will have it's own data (products, pages etc.), which has to be stored in different databases.

为了测试目的,我在 config/databases.php 中定义了多个连接.现在我可以在查询对应的数据库之前动态设置连接,像这样:

I've defined multiple connections within config/databases.php for testing purposes. Now I can dynamically set the connection before querying the corresponding database, like this:

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

例如,缓存也可以做到这一点.

The same can be done with caching, for instance.

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

What's the best way to let the API know which customer's website made the request? I need to point to the right database. Also, could this approach cause any problems performance-wise?

推荐答案

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

I'd be using a 2 pronged approach to solve this problem and I would use the first without the 2nd.

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

The first would be based on the route that you use the request the api. For instance you could define your routes with the prefix like /api/{site}. This way all your api endpoints would be based on the site variable requested. E.g. /api/site1/login would use the database site1 and /api/site2/login would use the database site2.

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

The second part to this is using JWT to authenticate like you mentioned above and on each request use a Middleware to check if the authenticated user is actually part of the users for that particular site. This is only really good for the authenticated routes however and still leaves your unauthenticated routes open to abuse, however if a legitimate user is on your site and your site is requesting the data from the api you should have the correct site data being returned and any malicious access will just be getting public data anyway.

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

There is potentially a third option too. with JWT you can create custom claims. These custom claims could be used to store the site being used and which database to access. I have not done this myself but have been thinking about doing something similar to authenticate the client against my apis as well as user based authentication on top of that. This would mean every endpoint would at least be client authenticated and others would be also user authenticated as well as client authenticated.

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

Using middleware to easily change the database connection at runtime.

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

Middleware: 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/Kernel.php 类的 $middleware 属性中.

Add this middleware to the app/Http/Kernel.php class to the $middleware property.

protected $middleware = [
    ...        
    \App\Http\Middleware\DatabaseConnectionChooser::class,
];

创建路由以指定站点,也就是数据库连接.

Create your routes to specify the site, aka the database connection.

app/Http/routes.php

app/Http/routes.php

app('router')->get('/{connection}/', function () {
    return app('db')->getDefaultConnection();
});

在您的配置中设置您的数据库连接.

Setup your database connection in your config.

config/database.php

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,
    ],

    ...
]

这篇关于Laravel API 连接多个数据库的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆