wake-up-neo.com

Laravel : Festlegen dynamischer Routen basierend auf der Zugriffssteuerungsliste

Ich baue REST API mit JWT Authentifizierung und Autorisierung mit eigener Logik. Es funktioniert perfekt. Jetzt möchte ich die Routen dynamisch basierend auf Rollen und Berechtigungen festlegen. Angenommen, ich habe eine Datenbankstruktur wie:

Rolle:

id  |   name
1   |  school
2   | transport

Berechtigungen:

id  |   name                   |  controller         | routes
1   |  view-class-result       |  ApiController      | getClassResult
2   |  view-student-result     |  ApiController      | studentResult
3   |  download-student-result |  ApiController      | donwloadSchoolTemplate

Berechtigungsrolle

role_id |  permission_id
1            1
1            2
1            3

Jetzt möchte ich Routen nach Rollen und Berechtigungen in der Datenbank erstellen.

Derzeit scheinen meine Routen wie folgt zu sein:

//All JWT authentication API goes here
Route::group(['middleware' => 'jwt.auth'], function() {
   Route::get('user', '[email protected]');
   Route::get('invalidate', '[email protected]');

   //All authorized API goes here
   Route::group(['middleware' => 'ability:school,view-class-result,true'], function() {
       Route::post('classResult', '[email protected]');
   });
   Route::group(['middleware' => 'ability:school,view-student-result,true'], function() {
       Route::post('studentResult', '[email protected]');
   });
   Route::group(['middleware' => 'ability:school,download-student-result,true'], function() {
       Route::post('getStudentExamResult', '[email protected]');
   });
});

Ich möchte nicht, dass die obigen Routen hart codiert sind. Wie bekomme ich diese Routen aus der Datenbank? Etwas wie unten. Aber ich konnte keine Idee bekommen, wie es geht.

In der Routendatei

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

   }
}

Vielen Dank.

12
user254153

Die beste Idee war, den Middleware-Parameter Create Middleware call CheckPermission zu verwenden. Dann müssen Sie diese Middleware in Ihrer app/Http/kernel.php -Datei registrieren

Ihre kernel.php datei

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

        }
    }

Ihre Route Datei

 Route::group(['middleware' => 'jwt.auth'], function() {
        Route::post('classResult', '[email protected]')->middleware('checkPermission:view-class-result');
        Route::post('studentResult', '[email protected]')->middleware('checkPermission:view-student-result');
        Route::post('getStudentExamResult', '[email protected]')->middleware('checkPermission:download-student-result');

   }
9
Hamelraj

In Ihrem routes.php

Route::group(['middleware' => 'jwt.auth'], function() {

Route::post('{uri}', '[email protected]');

});

Fügen Sie diese Route am Ende aller Routen hinzu.

Erstellen Sie nun einen neuen Controller mit dem Namen AccessController und fügen Sie ihm die folgenden constructor und method hinzu Angenommen, der Benutzer hat eine Beziehung zu Rollen.

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

Im Allgemeinen wird die URL abgerufen und mit den verfügbaren Routen in den Berechtigungen des authentifizierten Benutzers verglichen. Wenn der authentifizierte Benutzer die Berechtigung besitzt, zu der die Route gehört, fügen Sie die entsprechende Middleware hinzu.

Schließlich ruft die Methode redirectURI die entsprechende Controller-Methode auf und gibt die Antwort zurück.

Denken Sie daran, den Code bei Bedarf durch geeignete Namensräume und Beziehungen zu ersetzen. 

0

Ich bezweifle zwar, dass dies der beste Ansatz ist, aber in Ihrer Denkweise könnten Sie diesen "Pseudo-Code" ausprobieren. Ich hoffe, das drückt die Grundidee aus. Was das bedeutet, ist:

  • Ein Routenmuster, das nicht alle Routen explizit in Ihre Routendatei einbezieht. dh. api/studentResult
  • Ihr Controller soll an die richtige Methode weiterleiten, die Ihren API-Aufruf über einen einzigen Aktionscontroller implementiert ( Link zur Dokumentation )
  • Ihr Controller lädt die richtige Middleware, um sich um die Autorisierung zu kümmern

Routen

Route::group(['middleware' => 'jwt.auth'], function() {
    Route::get('user', '[email protected]');
    Route::get('invalidate', '[email protected]');

    // Choose whatever pattern you like...
    Route::post('api/{name}', ApiController::class);
});

Regler

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

Ich bin mir nicht ganz sicher, ob Sie Ihre Middleware auf diese Weise dynamisch laden können. Wenn ja, könnte dies ein gültiger Ansatz sein.

0
patriziotomato

Sie können also Ihren Rollennamen accountants a value to key in der Datei .env angeben und für jeden Rollennamen gleich sein.

Falls Sie es in naher Zukunft ändern möchten, können Sie es manuell in der Datei .env ändern oder Änderungen in der Datei .env über php code writtern an einem Ihrer Browser vornehmen Laravel Funktion .

0