web-dev-qa-db-ja.com

Laravel:アクセス制御リストに基づいて動的ルートを設定する

私はREST APIを構築し、JWT認証と独自のロジックによる承認を行います。完全に機能しています。次に、役割と権限に基づいて動的にルートを設定したいと思います。次のようなデータベース構造があるとします。

役割:

id  |   name
1   |  school
2   | transport

権限:

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

ここで、データベースの役割と権限に応じてルートを作成したいと思います。

現在、私のルートは次のようです:

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

上記のルートをハードコード化したくありません。データベースからこのルートを取得するにはどうすればよいですか。以下のようなもの。しかし、それを行う方法を理解できませんでした。

ルートファイルでは、

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

   }
}

ありがとうございました。

13
user254153

最高のアイデアは、ミドルウェアパラメータcreate Middleware call CheckPermissionを使用することでした。そのミドルウェアをapp/Http/kernel.phpファイルに登録する必要があります。あなただけのコードの下をチェックする必要があります

あなたのkernel.phpファイル

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

        }
    }

あなたのルートファイル

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

   }
10
Hamelraj

あなたのroutes.php

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

Route::post('{uri}', 'AccessController@redirectURI');

});

このルートをすべてのルートの最後に追加します。

次に、AccessControllerという新しいコントローラーを作成し、以下のconstructormethodを追加します。ユーザーがロールと関係を持っていると想定します。

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

全体として、URLを取得し、認証されたユーザーのアクセス許可で使用可能なルートと比較します。認証されたユーザーがルートが属する権限を持っている場合、適切なミドルウェアを追加します。

最後に、redirectURIメソッドは適切なコントローラーメソッドを呼び出し、応答を返します。

必要に応じて、コードを適切な名前空間と関係に置き換えることを忘れないでください。

0

これがこれに対する最良のアプローチだとは思いませんが、あなたの考え方では、この「疑似コード」を試すことができます。これが基本的な考え方を表しているといいのですが。それが意味することは:

  • ルートパターン。すべてのルートをルートファイルに明示的に含めないでください。すなわち。 api/studentResult
  • シングルアクションコントローラーを介してAPI呼び出しを実装する適切なメソッドにディスパッチするコントローラー( ドキュメントへのリンク
  • 承認を処理する適切なミドルウェアをロードするためのコントローラー

ルート

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

このようにミドルウェアを動的にロードできるかどうかは、完全にはわかりません。もしそうなら、これはこれのための有効なアプローチかもしれません。

0
patriziotomato

だからあなたができることはあなたのロール名をaccountants a valueからkey。envファイルに同じにすることです各ロール名ごとに。

近い将来変更したい場合は、。envファイルで手動で変更するか、。envファイルでphpコードライターLaravel関数の1つ。

0