将中间件应用于除 setup/* 之外的所有路由 Laravel 5.4
Apply Middleware to all routes except `setup/*` in 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
路由一样。
有没有更好的方法让这个中间件 运行 出现在用户的所有路由上,同时设置某些路由应该免于此检查?
不希望中间件到达的路由 运行 ,只需将它们放在函数之外即可:
//here register routes on which you dont want the middleware: checkOnboarding
Route::group(['middleware' => ['auth','checkOnboarding']], function () {
//routes on which you want the middleware
});
您所做的没有任何问题,但是,我建议您将路线组分开,即:
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');
希望对您有所帮助!
您可以为此使用控制器 class,并获得非常惊人的效果。
如果您在 HTTP/Controllers/Controller.php 中创建一个 __construct 函数,那么您可以在每个控制器操作上向 运行 声明中间件,甚至可以根据需要声明异常。
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct(){
$this->middleware('auth',['except' => ['login','setup','setupSomethingElse']]);
}
}
注意不要将任何标准索引、存储、更新、销毁函数置于异常中,否则您将打开潜在的安全问题。
有两种方法可以解决这个问题
- 尝试在路线文件中筛选路线
web.php or api.php
- 跳过
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');
});
因为 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');
});
});
在Laravel 8.x中你也可以使用withoutMiddleware()
方法排除一个或多个路由到组中间件
Route::middleware('auth')->group(function () {
Route::get('/edit/{id}',[ProgramController::class, 'edit'])->name('edit');
Route::get('/public', [ProgramController::class, 'public'])
->name('public')->withoutMiddleware(['auth']);
});
同时查看官方文档:Here
我正在 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
路由一样。
有没有更好的方法让这个中间件 运行 出现在用户的所有路由上,同时设置某些路由应该免于此检查?
不希望中间件到达的路由 运行 ,只需将它们放在函数之外即可:
//here register routes on which you dont want the middleware: checkOnboarding
Route::group(['middleware' => ['auth','checkOnboarding']], function () {
//routes on which you want the middleware
});
您所做的没有任何问题,但是,我建议您将路线组分开,即:
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');
希望对您有所帮助!
您可以为此使用控制器 class,并获得非常惊人的效果。
如果您在 HTTP/Controllers/Controller.php 中创建一个 __construct 函数,那么您可以在每个控制器操作上向 运行 声明中间件,甚至可以根据需要声明异常。
class Controller extends BaseController
{
use AuthorizesRequests, DispatchesJobs, ValidatesRequests;
public function __construct(){
$this->middleware('auth',['except' => ['login','setup','setupSomethingElse']]);
}
}
注意不要将任何标准索引、存储、更新、销毁函数置于异常中,否则您将打开潜在的安全问题。
有两种方法可以解决这个问题
- 尝试在路线文件中筛选路线
web.php or api.php
- 跳过
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');
});
因为 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');
});
});
在Laravel 8.x中你也可以使用withoutMiddleware()
方法排除一个或多个路由到组中间件
Route::middleware('auth')->group(function () {
Route::get('/edit/{id}',[ProgramController::class, 'edit'])->name('edit');
Route::get('/public', [ProgramController::class, 'public'])
->name('public')->withoutMiddleware(['auth']);
});
同时查看官方文档:Here