Примените промежуточное ПО ко всем маршрутам, кроме `setup / *` в Laravel 5.4

Я экспериментирую с промежуточным программным обеспечением в своем приложении Laravel. В настоящее время я настроил его для работы на каждом маршруте для аутентифицированного пользователя, однако я хочу, чтобы он игнорировал любые запросы, начинающиеся с setup URI.

Вот как выглядит мой CheckOnboarding метод промежуточного программного обеспечения:

public function handle($request, Closure $next)
{
    /** 
    * Check to see if the user has completed the onboarding, if not redirect.
    * Also checks that the requested URI isn't the setup route to ensure there isn't a redirect loop.
    */
    if ($request->user()->onboarding_complete == false && $request->path() != 'setup') {
        return redirect('setup');
    } else {
        return $next($request);
    }
}

Это используется в моих маршрутах следующим образом:

Route::group(['middleware' => ['auth','checkOnboarding']], function () {
    Route::get('/home', 'HomeController@index');
    Route::get('/account', 'AccountController@index');

    Route::group(['prefix' => 'setup'], function () {
        Route::get('/', 'OnboardingController@index')->name('setup');
        Route::post('/settings', 'SettingsController@store');
    }); 
});

Теперь, если я перейду к /home или /account, я буду перенаправлен на /setup, как и следовало ожидать. Первоначально это вызвало ошибку цикла перенаправления, поэтому & $request->path() != 'setup' находится в промежуточном программном обеспечении.

Мне кажется, что это действительно неуклюжий способ сделать это, и очевидно, что он не соответствует чему-либо после setup, например, setup/settings маршрут, который я создал.

Есть ли лучший способ запустить это промежуточное ПО на всех маршрутах для пользователя, но также установить определенные маршруты, которые должны быть исключены из этой проверки?


person Andy Holmes    schedule 31.03.2017    source источник


Ответы (5)


Нет ничего плохого в том, что вы делаете, однако я бы предложил вместо этого разделить группы маршрутов, а именно:

Route::group(['middleware' => ['auth', 'checkOnboarding']], function () {
    Route::get('/home', 'HomeController@index');
    Route::get('/account', 'AccountController@index');
});

Route::group(['prefix' => 'setup', 'middleware' => 'auth'], function () {
    Route::get('/', 'OnboardingController@index')->name('setup');
    Route::post('/settings', 'SettingsController@store');
});

В качестве альтернативы создайте родительскую группу для вашей авторизации:

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

    Route::group(['middleware' => 'checkOnboarding'], function () {
        Route::get('/home', 'HomeController@index');
        Route::get('/account', 'AccountController@index');
    });

    Route::group(['prefix' => 'setup'], function () {
        Route::get('/', 'OnboardingController@index')->name('setup');
        Route::post('/settings', 'SettingsController@store');
    });
});

Это также будет означать, что вы можете удалить дополнительное условие в промежуточном программном обеспечении:

/**
 * Check to see if the user has completed the onboarding, if not redirect.
 * Also checks that the requested URI isn't the setup route to ensure there isn't a redirect loop.
 */
return $request->user()->onboarding_complete ? $next($request) : redirect('setup');

Надеюсь это поможет!

person Rwd    schedule 31.03.2017

Вы можете использовать для этого класс Controller с довольно впечатляющими результатами.

Если вы создаете функцию __construct внутри HTTP / Controllers / Controller.php, вы можете объявить промежуточное ПО для запуска при каждом действии контроллера и даже объявить исключения по мере необходимости.

class Controller extends BaseController
{
  use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
  public function __construct(){
    $this->middleware('auth',['except' => ['login','setup','setupSomethingElse']]);
  }
}

Будьте осторожны, не помещайте в исключение какие-либо стандартные функции index, store, update, destroy, иначе вы откроете потенциальные проблемы с безопасностью.

person bstory    schedule 21.06.2017
comment
Для меня это более понятно и декларативно, чем использование routes. Конечно, это вопрос личного вкуса и опыта, но я голосую за это. - person realtebo; 02.08.2018

Начиная с Laravel 7.7 вы можете использовать excluded_middleware следующим образом:

Route::group(['middleware' => ['auth','checkOnboarding']], function () {
    Route::get('/home', 'HomeController@index');
    Route::get('/account', 'AccountController@index');

    Route::group([
      'prefix' => 'setup',
      'excluded_middleware' => ['checkOnboarding'],
], function () {
        Route::get('/', 'OnboardingController@index')->name('setup');
        Route::post('/settings', 'SettingsController@store');
    }); 
});
person GetoX    schedule 11.08.2020

Есть 2 способа решить эту проблему

  1. Попробуйте просмотреть свои маршруты в файле маршрутов web.php or api.php
  2. пропустить маршруты в middleware

В случае глобального промежуточного программного обеспечения (промежуточного программного обеспечения, которое вы хотите запускать перед всеми маршрутами) вы должны пропустить маршруты в промежуточном программном обеспечении.

Например:

//add an array of routes to skip santize check
protected $openRoutes = [
    'setup/*',
];

/**
 * Handle an incoming request.
 *
 * @param  \Illuminate\Http\Request  $request
 * @param  \Closure  $next
 * @return mixed
 */
public function handle($request, Closure $next)
{
    if(!in_array($request->path(), $this->openRoutes)){
       //middleware code or call of function
    }       

    return $next($request);
}

Для другого промежуточного программного обеспечения вы можете легко пропустить файл маршрутов и группировать маршруты на основе вашего промежуточного программного обеспечения.

Например:

Route::group(['middleware' => 'checkOnboarding'], function () {
        Route::get('/home', 'HomeController@index');
        Route::get('/account', 'AccountController@index');
    });

Route::group(['prefix' => 'setup'], function () {
    Route::get('/', 'OnboardingController@index')->name('setup');
    Route::post('/settings', 'SettingsController@store');
});
person Ankit Jindal    schedule 06.07.2020

Маршруты, на которых вы не хотите, чтобы промежуточное ПО запускалось, просто поместите их вне функции:

//here register routes on which you dont want the middleware: checkOnboarding
Route::group(['middleware' => ['auth','checkOnboarding']], function () {
     //routes on which you want the middleware
});
person Learner    schedule 31.03.2017