Search code examples
laravelloopshttp-redirectadmin

How to resolve a redirect loop issue with Laravel routes and middleware?


if (!Auth::guard('admin')->check() && !$request->routeIs('admin.login')) {return redirect()->route('admin.login');}

Tried to plug it into ChatGPT, and changed some stuff in web.php:

Route::get('/admin/login', [AdminController::class, 'showLoginForm'])->name('admin.login');
Route::post('/admin/login', [AdminController::class, 'login'])->name('admin.login.post');

Route::middleware([RedirectIfAdminExists::class])->group(function () {
    Route::get('/admin/login', [AdminController::class, 'showLoginForm'])->name('admin.login')->withoutMiddleware([RedirectIfAdminExists::class]);
    Route::get('/admin', [AdminController::class, 'index'])->name('admin.index');
    Route::get('/admin/create', [AdminController::class, 'create'])->name('admin.create');
    Route::post('/admin', [AdminController::class, 'store'])->name('admin.store');
    Route::get('/admin/{admin}', [AdminController::class, 'show'])->name('admin.show');
    Route::get('/admin/{admin}/edit', [AdminController::class, 'edit'])->name('admin.edit');
    Route::put('/admin/{admin}', [AdminController::class, 'update'])->name('admin.update');
    Route::delete('/admin/{admin}', [AdminController::class, 'destroy'])->name('admin.destroy');
});

The RedirectIfAdminExists middleware is intended to redirect to the admin login page if the user is not logged in as an admin and is trying to access admin-specific routes. However, this setup is causing a redirect loop, particularly on the admin login page itself.

I've attempted to resolve the issue by excluding the RedirectIfAdminExists middleware from the admin login route within the middleware group, as shown above. While this adjustment seems to prevent the redirect loop, I'm unsure if it's the correct approach or if there's a better solution.

<?php

namespace App\Http\Middleware;

use Closure;
use Auth;
use Illuminate\Http\Request;

class RedirectIfAdminExists
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle(Request $request, Closure $next)
    {
        // Check if the user is not logged in as an admin and the current route is not 'admin.login'
        if (!Auth::guard('admin')->check() && !$request->routeIs('admin.login')) {
            return redirect()->route('admin.login');
        }

        return $next($request);
    }

}

My AdminController functions:

public function index()
    {
        $admins = Admin::all();
        $users = User::all();
        $images = Image::all();
        $products = Product::all();
        $sellers = Seller::all();
        $orders = Order::all();
        $orderItems = OrderItem::all();
        $carts = Cart::all();
        $cartItems = CartItem::all();
        $reviews = Review::all();
        $categories = Category::all();

        return view('admin.index', compact('admins', 'users', 'images', 'products', 'sellers', 'orders', 'orderItems', 'carts', 'cartItems', 'reviews', 'categories'));
    }

    public function create()
    {
        return view('admin.create');
    }

    public function store(Request $request)
    {
        $request->validate([
            'name' => 'required',
            'password' => ['required', 'min:8', 'regex:/^[A-Z]{2}\d{4}---$/'],
        ], [
            'password.regex' => 'Password creation does not meet criteria',
        ]);

        Admin::create([
            'name' => $request->name,
            'password' => Hash::make($request->password),
        ]);

        return redirect()->route('admin.index')->with('success', 'Admin created successfully.');
    }

    public function show($id)
    {
        $admin = Admin::findOrFail($id);
        return view('admin.show', compact('admin'));
    }

    public function showLoginForm()
    {
        return view('admin.login');
    }

    public function login(Request $request)
    {
        $credentials = $request->only('name', 'password');

        if (Auth::guard('admin')->attempt($credentials)) {
            return redirect()->route('admin.index');
        } else {
            return back()->withErrors([
                'name' => 'The provided credentials do not match our records.',
            ]);
        }
    }

Solution

  • You have the "admin.login" route defined twice. One without any middleware an one inside your RedirectIfAdminExists grouped routes. Just delete the one inside the group and you got what you want.

    If you only have one middleware in the route group, then simply set the route that this middleware should not have outside the group