Search code examples
phplaravelauthenticationmiddleware

Laravel routes: Breaking when hitting a route in auth middleware


I am writing the logic in which the user accepts Terms and Conditions in a separate page and here is the workflow.

  1. The user is logged in
  2. If they have not accepted the latest Terms and Conditions, show them the /welcome page.
  3. If they accept them, then there is a link redirecting them to /accept

I have got the following routes set up:

Auth::routes();

// Temp
Route::get('/', function () {
    return redirect('/login');
});

Route::get('/logout', 'Auth\LoginController@logout');

Route::post('password/reset/{token}', 'Auth\ResetPasswordController@postReset')->name('password.request');

// Auth middleware
Route::group(['middleware' => ['auth']], function () {
    // Temp
    Route::get('/discovery', function () {
        return view('pages.discovery');
    });

    // Temp
    Route::get('/welcome', function () {
        return view('pages.welcome');
    });

    Route::get('/accept', 'Auth\LoginController@accept');
});

Issue is that when a user is logged in, redirected to the /welcome page instead of them clicking on the Accept button to be redirected to the /accept route then it breaks with the common message Sorry, the page you are looking for could not be found.

I am guessing it's related to middleware. Any ideas?

Update

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

    Route::get('/accept', 'Auth\LoginController@accept')->name('terms.accept');
    Route::get('/welcome', function () {
        return view('pages.welcome');
    });
    Route::group(['middleware' => ['terms']], function () {
        Route::get('/discovery', function () {
            return view('pages.discovery');
        });

    });
});

and this is the middleware:

class TermsMiddleware
{
    /**
     * @var UserService
     */
    protected $userService;

    /**
     * TermsMiddleware constructor.
     * @param UserService $userService
     */
    public function __construct(UserService $userService)
    {
        $this->userService = $userService;
    }

    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request $request
     * @param  \Closure $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        if (!$this->userService->hasAcceptedTerms()) {
            return redirect('/welcome');
        }

        return $next($request);
    }
}

Solution

  • Auth::routes();
    
    Route::get('/', function () {
        return redirect('/login');
    });
    
    Route::get('/logout', 'Auth\LoginController@logout');
    Route::post('password/reset/{token}', 'Auth\ResetPasswordController@postReset')->name('password.request');
    
    Route::group(['middleware' => ['auth']], function () {
        Route::get('/accept', 'Auth\LoginController@accept')->name('get.accept');
        Route::group(['middleware' => ['terms']], function () {
            Route::get('/discovery', function () {
                return view('pages.discovery');
            });
            Route::get('/welcome', function () {
                return view('pages.welcome');
            });
        });
    });
    

    php artisan make:middlware Terms

    <?php
    
    namespace YourNamespace;
    
    use Closure;
    
    class Terms
    {
    
        public function handle( $request, Closure $next, $guard = null )
        {
            if( ! $request->user()->accepts_terms ) {
                return redirect( route( 'get.accept' ) );
            }
            return $next( $request );
        }
    }
    

    add to your HTTP kernel routeMiddleware, 'terms' => YourNewTermsMiddleware::class