web-dev-qa-db-fra.com

Laravel : Définition d'itinéraires dynamiques en fonction de la liste de contrôle d'accès

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.

12
user254153

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

   }
9
Hamelraj

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. 

0
Srinath Reddy Dudi

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:

  • Un modèle de route, pour ne pas inclure explicitement toutes les routes dans votre fichier de routes. c'est à dire. api/studentResult
  • Votre contrôleur à envoyer à la méthode appropriée qui implémente votre appel api via un contrôleur d’action unique ( Lien vers la documentation )
  • Votre contrôleur pour charger le middleware correct à prendre en charge lors de l'autorisation

Itinéraires

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

Manette

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.

0
patriziotomato

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 .

0
Harsh Wardhan Gaur