Je construis REST API avec JWT
authentification et autorisation avec sa propre logique. Ça fonctionne parfaitement. Maintenant, je veux définir les itinéraires de manière dynamique en fonction des rôles et des autorisations. Supposons que j'ai une structure de base de données comme:
Rôle:
id | name
1 | school
2 | transport
Permissions:
id | name | controller | routes
1 | view-class-result | ApiController | getClassResult
2 | view-student-result | ApiController | studentResult
3 | download-student-result | ApiController | donwloadSchoolTemplate
Permission_role
role_id | permission_id
1 1
1 2
1 3
Maintenant, je veux créer des itinéraires en fonction des rôles et des autorisations dans la base de données.
Actuellement, mes itinéraires semblent:
//All JWT authentication API goes here
Route::group(['middleware' => 'jwt.auth'], function() {
Route::get('user', 'ApiController@getAuthUser');
Route::get('invalidate', 'ApiController@invalidate');
//All authorized API goes here
Route::group(['middleware' => 'ability:school,view-class-result,true'], function() {
Route::post('classResult', 'ApiController@getClassResult');
});
Route::group(['middleware' => 'ability:school,view-student-result,true'], function() {
Route::post('studentResult', 'ApiController@studentResult');
});
Route::group(['middleware' => 'ability:school,download-student-result,true'], function() {
Route::post('getStudentExamResult', 'ApiController@downloadSchoolTemplate');
});
});
Je ne veux pas que les itinéraires ci-dessus soient codés en dur. Comment puis-je obtenir ces routes de la base de données. Quelque chose comme ci-dessous. Mais je ne pouvais pas savoir comment faire.
Dans le fichier des routes,
$a = User:all();
foreach($a->roles as $value){
foreach($value->permission as $val){
Route::group(['middleware' => 'ability:{$value->name},{$val->name},true'], function() {
Route::post('{$val->controller}', '{$val->controller}@{$val->method}');
});
}
}
Je vous remercie.
La meilleure idée consistait à utiliser le paramètre de middleware Create Middleware call CheckPermission vous devez ensuite enregistrer ce middleware dans votre app/Http/kernel.php fichier qui ne nécessite que le contrôle ci-dessous
Votre kernel.php fichier
protected $routeMiddleware = [
'checkPermission' => \App\Http\Middleware\CheckPermission::class,
];
CheckPermission.php
<?php
namespace App\Http\Middleware;
use Closure;
use DB;
class CheckPermission
{
/**
* Handle an incoming request.
*
* @param \Illuminate\Http\Request $request
* @param \Closure $next
* @return mixed
*/
public function handle($request, Closure $next,$permission_name)
{
//first check that name in your db
$permission = DB::table('Permission')->where('name',$permission_name)->first()
if($permission){
//here you have to get logged in user role
$role_id = Auth::user()->role;
## so now check permission
$check_permission = DB::table('Permission_role')->where('role_id',$role_id)->where('permission_id',$permission->id)->first();
if($check_permission){
return $next($request);
}
//if Permission not assigned for this user role show what you need
}
// if Permission name not in table then do what you need
## Ex1 : return 'Permission not in Database';
## Ex2 : return redirect()->back();
}
}
Votre Route file
Route::group(['middleware' => 'jwt.auth'], function() {
Route::post('classResult', 'ApiController@getClassResult')->middleware('checkPermission:view-class-result');
Route::post('studentResult', 'ApiController@studentResult')->middleware('checkPermission:view-student-result');
Route::post('getStudentExamResult', 'ApiController@downloadSchoolTemplate')->middleware('checkPermission:download-student-result');
}
Dans votre routes.php
Route::group(['middleware' => 'jwt.auth'], function() {
Route::post('{uri}', 'AccessController@redirectURI');
});
Ajoutez cet itinéraire à la fin de tous vos itinéraires.
Créez maintenant un nouveau contrôleur appelé AccessController
et ajoutez-lui les constructor
et method
ci-dessous . En supposant que l'utilisateur ait une relation avec des rôles.
public function __construct(Request $request)
{
$authorised_user = User::where('id', Auth::User()->id)->whereHas('role', function($query) use ($request)
{
$query->whereHas('permission', function($query) use ($request)
{
$query->where('routes', $request->route('uri'))
});
})->firstOrFail();
if( $authorised_user )
{
$permission = Permission::where('routes', $request->route('uri'))->findOrFail();
$this->middleware([ 'ability:'.$authorised_user->role()->name.','.$permission->name.',true' ]);
}
else
{
// user is not authorised. Do what ever you want
}
}
public function redirectURI($uri)
{
$permission = Permission::where('routes', $uri)->findOrFail();
return app('App\\Http\\Controllers\\'. $permission->controller )->$permission->method();
}
Globalement, il récupère l'URL et le compare aux itinéraires disponibles dans les autorisations de l'utilisateur authentifié. Si l'utilisateur authentifié a l'autorisation à laquelle appartient la route, ajoutez ensuite le middleware approprié.
Enfin, la méthode redirectURI
appelle la méthode du contrôleur appropriée et renvoie la réponse.
N'oubliez pas de remplacer le code par un espace de noms et des relations appropriés, le cas échéant.
Bien que je doute que ce soit la meilleure approche à cela, mais dans votre façon de penser, vous pourriez essayer ce "pseudo code". J'espère que cela exprime l'idée de base. Qu'est-ce que cela implique, c'est:
api/studentResult
Route::group(['middleware' => 'jwt.auth'], function() {
Route::get('user', 'ApiController@getAuthUser');
Route::get('invalidate', 'ApiController@invalidate');
// Choose whatever pattern you like...
Route::post('api/{name}', ApiController::class);
});
class ApiController {
public function __construct() {
$permisions = $this->loadPersionForUser();
$this->middleware('ability', [$permisions->value1, 'whatever']);
}
public function __invoke($method) {
if (method_exists($this, $method)) {
return $this->$method();
}
}
}
Je ne suis pas tout à fait sûr que vous puissiez charger votre middleware dynamiquement de cette manière. Si tel est le cas, cela pourrait être une approche valable pour cela.
Donc, ce que vous pouvez faire est de donner votre nom de rôle comptables a valeur à clé dans le fichier .env et identique pour chaque nom de rôle.
Si vous souhaitez le modifier dans un proche avenir, vous pouvez le modifier manuellement dans le fichier .env ou vous pouvez apporter des modifications au fichier .env via php code writertern sur l’un de vos Fonction Laravel .