Правило промежуточного программного обеспечения Laravel 'except' не работает

У меня есть контроллер со следующим конструктором:

$this->middleware('guest', ['except' =>
    [
        'logout',
        'auth/facebook',
        'auth/facebook/callback',
        'auth/facebook/unlink'
    ]
]);

Правило выхода из системы (которое есть по умолчанию) работает отлично, но остальные 3 правила, которые я добавил, игнорируются. Маршруты в routes.php выглядят так:

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

    Route::auth();

    // Facebook auth
    Route::get('/auth/facebook', 'Auth\AuthController@redirectToFacebook')->name('facebook_auth');
    Route::get('/auth/facebook/callback', 'Auth\AuthController@handleFacebookCallback')->name('facebook_callback');
    Route::get('/auth/facebook/unlink', 'Auth\AuthController@handleFacebookUnlink')->name('facebook_unlink');
}

Если я посещаю auth/facebook, auth/facebook/callback или auth/facebook/unlink во время входа в систему, я получаю отказ от промежуточного программного обеспечения и возвращаюсь на домашнюю страницу.

Я попытался указать правила «кроме» при выполнении /, чтобы они точно соответствовали маршрутам в routes.php, но это не имеет значения. Есть идеи, почему эти правила игнорируются, а правило выхода из системы соблюдается?

Ваше здоровье!


person jd182    schedule 10.01.2016    source источник


Ответы (7)


Вам нужно передать имя метода вместо URI.

<?php
    
namespace App\Http\Controllers;
    
class MyController extends Controller {
    public function __construct() {
        $this->middleware('guest', ['except' => [
            'redirectToFacebook', 'handleFacebookCallback', 'handleFacebookUnlink'
        ]]);
    }
}

Начиная с Laravel 5.3, вы можете использовать свободный интерфейс для определения промежуточного программного обеспечения на контроллерах, что кажется более чистым, чем использование многомерных массивов.

<?php

$this->middleware('guest')->except('redirectToFacebook', 'handleFacebookCallback', 'handleFacebookUnlink');
person Lucas Silva    schedule 10.01.2016

Если вы пытаетесь следовать документации Laravel, предлагается альтернативное решение - добавление маршрутов в переменную $ except в файле /Http/Middleware/VerifyCsrfToken.php. В документации сказано, что нужно добавить их следующим образом:

'route/*'

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

'/route'
person Tyler Pashigian    schedule 23.06.2017

Я решил эту проблему в своем промежуточном программном обеспечении, добавив эту inExceptArray функцию. Точно так же VerifyCsrfToken обрабатывает массив except.

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;

class MyMiddleware
{
    /**
     * Routes that should skip handle.
     *
     * @var array
     */
    protected $except = [
        '/some/route',
    ];

    /**
     * Determine if the request has a URI that should pass through.
     *
     * @param Request $request
     * @return bool
     */
    protected function inExceptArray($request)
    {
        foreach ($this->except as $except) {
            if ($except !== '/') {
                $except = trim($except, '/');
            }

            if ($request->is($except)) {
                return true;
            }
        }

        return false;
    }

    /**
     * Handle an incoming request.
     *
     * @param  Request  $request
     * @param Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        // check user authed or API Key
        if (!$this->inExceptArray($request)) {
            // Process middleware checks and return if failed...
            if (true) {
              // Middleware failed, send back response
              return response()->json([
                'error' => true,
                'Message' => 'Failed Middleware check'
            ]); 
            }
        }
        // Middleware passed or in Except array
        return $next($request);
    }
}
person cmac    schedule 26.02.2020

Используйте эту функцию в своем контроллере:

public function __construct()
    {
        $this->middleware(['auth' => 'verified'])->except("page_name_1", "page_name_2", "page_name_3");
    }

* замените page_name_1 / 2/3 своим.

У меня все работает нормально.

person Daljit Singh    schedule 15.12.2020

Я решил эту проблему, и вот что я делаю. Асо, я только что понял, что это очень похоже на то, что сделал cmac в своем ответе.

api.php

Route::group(['middleware' => 'auth'], function () {
    Route::get('/user', 'Auth\UserController@me')->name('me');
    Route::post('logout', 'Auth\LoginController@logout')->name('logout');
});

LoginController.php

class LoginController extends Controller
{
    use AuthenticatesUsers, ThrottlesLogins;

    /**
     * Create a new controller instance.
     *
     * @return void
     */
    public function __construct()
    {
        $this->middleware('guest')->except('logout');
    }

    // ...

    /**
     * If the user's session is expired, the auth token is already invalidated,
     * so we just return success to the client.
     *
     * This solves the edge case where the user clicks the Logout button as their first
     * interaction in a stale session, and allows a clean redirect to the login page.
     *
     * @param \Illuminate\Http\Request $request
     * @return \Illuminate\Http\Response
     */
    public function logout(Request $request)
    {
        $user = $this->guard()->user();

        if ($user) {
            $this->guard()->logout();
            JWTAuth::invalidate();
        }

        return response()->json(['success' => 'Logged out.'], 200);
    }
}

Authenticate.php

class Authenticate extends Middleware
{
    /**
     * Exclude these routes from authentication check.
     *
     * Note: `$request->is('api/fragment*')` https://laravel.com/docs/7.x/requests
     *
     * @var array
     */
    protected $except = [
        'api/logout',
    ];

    /**
     * Ensure the user is authenticated.
     *
     * @param \Illuminate\Http\Request $request
     * @param \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        try {
            foreach ($this->except as $excluded_route) {
                if ($request->path() === $excluded_route) {
                    \Log::debug("Skipping $excluded_route from auth check...");
                    return  $next($request);
                }
            }

            // code below here requires 'auth'

        { catch ($e) {
            // ...
        }

    }

Я немного перестроил его. Сегодня мне нужно исключение только для /api/logout, но я настроил логику для быстрого добавления новых маршрутов. Если вы исследуете промежуточное программное обеспечение VerifyCsrfToken, вы увидите, что оно принимает такую ​​форму:

    protected $except = [
        'api/logout',
        'api/foobars*',
        'stripe/poop',
        'https://www.external.com/yolo',
    ];

Вот почему я поместил эту «заметку» в свой документ выше. $request->path() === $excluded_route, вероятно, не будет соответствовать api/foobars*, но $request->is('api/foobars*') должен. Кроме того, человек может использовать что-то вроде $request->url() === $excluded_route для соответствия http://www.external.com/yolo.

person agm1984    schedule 26.05.2020

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

use App\Http\Middleware\CheckAge;

Route::middleware([CheckAge::class])->group(function () {
    Route::get('/', function () {
        //
    });

    Route::get('admin/profile', function () {
        //
    })->withoutMiddleware([CheckAge::class]);
});

для получения дополнительной информации прочтите документацию по промежуточному программному обеспечению laravel

person Ozal Zarbaliyev    schedule 23.07.2020

Вы должны передать имя функции в 'except'.

Вот пример из одного из моих проектов:

$this->middleware('IsAdminOrSupport', ['except' => [
        'ProductsByShopPage'
        ]
    ]);

Это означает, что промежуточное ПО IsAdminOrSupport применяется ко всем методам этого контроллера, за исключением метода ProductByShopPage.

person hackernewbie    schedule 22.04.2021