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 (model
I'd be using a 2 pronged approach to solve this problem and I would use the first without the 2nd.
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
.
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.
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.
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);
}
}
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('router')->get('/{connection}/', function () {
return app('db')->getDefaultConnection();
});
Setup your database connection in your config.
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,
],
...
]