Laravel多认证实现咨询:6类用户分双路由登录方案
Hey there! Let's walk through exactly how to build this multi-user login system, covering both the Laravel backend and React frontend. I'll break it down into clear, actionable steps so you can implement it easily.
Laravel Backend Implementation
First, we'll focus on securing the routes, separating login flows, and preventing cross-access between customer and admin users.
1. Configure Authentication Guards & Providers
We need two distinct guards to handle customer and admin authentication. Update your config/auth.php to define separate guards and model providers:
// config/auth.php 'guards' => [ 'customer' => [ 'driver' => 'session', 'provider' => 'customers', ], 'admin' => [ 'driver' => 'session', 'provider' => 'admins', ], ], 'providers' => [ 'customers' => [ 'driver' => 'eloquent', 'model' => App\Models\Customer::class, ], 'admins' => [ 'driver' => 'eloquent', 'model' => App\Models\Admin::class, // Use this model for all 5 admin types (add a `type` column to distinguish them) ], ],
2. Update Routes & Controllers
Split your login routes into GET (form display) and POST (login processing), then add route protection with custom middleware.
Updated Routes (web.php)
// Customer login flow Route::get('/login', 'CustomerLoginController@showLoginForm')->name('customer.login'); Route::post('/login', 'CustomerLoginController@processLogin'); // Admin login flow Route::get('/system/base-admin', 'AdminLoginController@showAdminLoginForm')->name('system.admin'); Route::post('/system/base-admin', 'AdminLoginController@processAdminLogin'); // Protected customer routes (only accessible to logged-in customers) Route::middleware('auth.customer')->group(function () { Route::get('/customer/dashboard', 'CustomerDashboardController@index')->name('customer.dashboard'); Route::post('/customer/logout', 'CustomerLoginController@logout')->name('customer.logout'); }); // Protected admin routes (only accessible to logged-in admins) Route::middleware('auth.admin')->group(function () { Route::get('/system/admin/dashboard', 'AdminDashboardController@index')->name('admin.dashboard'); Route::post('/system/admin/logout', 'AdminLoginController@logout')->name('admin.logout'); });
Customer Login Controller
namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class CustomerLoginController extends Controller { public function showLoginForm() { // Redirect logged-in customers directly to their dashboard if (Auth::guard('customer')->check()) { return redirect()->route('customer.dashboard'); } return view('customer.login'); } public function processLogin(Request $request) { $credentials = $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); if (Auth::guard('customer')->attempt($credentials)) { $request->session()->regenerate(); return redirect()->intended('/customer/dashboard'); } // Redirect back to customer login with error return back()->withErrors([ 'email' => 'The provided credentials do not match our records.', ])->onlyInput('email'); } public function logout(Request $request) { Auth::guard('customer')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect()->route('customer.login'); } }
Admin Login Controller
namespace App\Http\Controllers; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use App\Models\Admin; class AdminLoginController extends Controller { public function showAdminLoginForm() { // Redirect logged-in admins directly to their dashboard if (Auth::guard('admin')->check()) { return redirect()->route('admin.dashboard'); } return view('admin.login'); } public function processAdminLogin(Request $request) { $credentials = $request->validate([ 'email' => 'required|email', 'password' => 'required', ]); // Validate the user is one of the 5 admin types $admin = Admin::where('email', $request->email)->first(); if (!$admin || !in_array($admin->type, ['admin_type_1', 'admin_type_2', 'admin_type_3', 'admin_type_4', 'admin_type_5'])) { return back()->withErrors([ 'email' => 'Invalid admin credentials.', ])->onlyInput('email'); } if (Auth::guard('admin')->attempt($credentials)) { $request->session()->regenerate(); return redirect()->intended('/system/admin/dashboard'); } // Redirect back to admin login with error return back()->withErrors([ 'email' => 'The provided credentials do not match our records.', ])->onlyInput('email'); } public function logout(Request $request) { Auth::guard('admin')->logout(); $request->session()->invalidate(); $request->session()->regenerateToken(); return redirect()->route('system.admin'); } }
3. Custom Middleware for Route Protection
Create two middleware to prevent cross-access between customer and admin routes:
CheckCustomerGuard Middleware
// app/Http/Middleware/CheckCustomerGuard.php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class CheckCustomerGuard { public function handle(Request $request, Closure $next) { // Block admins from accessing customer routes if (Auth::guard('admin')->check()) { return redirect()->route('admin.dashboard'); } // Redirect unauthenticated users to customer login if (!Auth::guard('customer')->check()) { return redirect()->route('customer.login'); } return $next($request); } }
CheckAdminGuard Middleware
// app/Http/Middleware/CheckAdminGuard.php namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; class CheckAdminGuard { public function handle(Request $request, Closure $next) { // Block customers from accessing admin routes if (Auth::guard('customer')->check()) { return redirect()->route('customer.dashboard'); } // Redirect unauthenticated users to admin login if (!Auth::guard('admin')->check()) { return redirect()->route('system.admin'); } return $next($request); } }
Register these middleware in app/Http/Kernel.php:
protected $routeMiddleware = [ // ... 'auth.customer' => \App\Http\Middleware\CheckCustomerGuard::class, 'auth.admin' => \App\Http\Middleware\CheckAdminGuard::class, ];
React Frontend Implementation
Now let's handle the frontend to match the backend flow, with separate login forms and route protection.
1. Separate Login Components
Create two distinct login components for customers and admins:
CustomerLogin.jsx
import { useState } from 'react'; import { useNavigate } from 'react-router-dom'; export default function CustomerLogin() { const [email, setEmail] = useState(''); const [password, setPassword] = useState(''); const [error, setError] = useState(''); const navigate = useNavigate(); const handleSubmit = async (e) => { e.preventDefault(); setError(''); try { const response = await fetch('/login', { method: 'POST', headers: { 'Content-Type': 'application/json', 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content }, body: JSON.stringify({ email, password }) }); if (!response.ok) { const data = await response.json(); setError(data.email || 'Login failed'); return; } navigate('/customer/dashboard'); } catch (err) { setError('An error occurred during login'); } }; return ( <div className="login-form"> <h2>Customer Login</h2> {error && <p className="error">{error}</p>} <form onSubmit={handleSubmit}> <div> <label>Email:</label> <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required /> </div> <div> <label>Password:</label> <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} required /> </div> <button type="submit">Login</button> </form> </div> ); }
AdminLogin.jsx
This is nearly identical to the customer login component, with changes to the form title, API endpoint, and redirect path:
// Replace the handleSubmit fetch URL with '/system/base-admin' // Redirect to '/system/admin/dashboard' on success
2. Protected Route Components
Create components to guard routes and prevent cross-access:
ProtectedCustomerRoute.jsx
import { useEffect, useState } from 'react'; import { Navigate, Outlet } from 'react-router-dom'; export default function ProtectedCustomerRoute() { const [isAuthenticated, setIsAuthenticated] = useState(null); const [isAdmin, setIsAdmin] = useState(false); useEffect(() => { const checkAuth = async () => { // Check if user is logged in as customer const customerRes = await fetch('/api/customer/check-auth'); if (customerRes.ok) { setIsAuthenticated(true); return; } // Check if user is logged in as admin const adminRes = await fetch('/api/admin/check-auth'); if (adminRes.ok) { setIsAdmin(true); } setIsAuthenticated(false); }; checkAuth(); }, []); if (isAuthenticated === null) return <div>Loading...</div>; if (isAdmin) return <Navigate to="/system/admin/dashboard" replace />; return isAuthenticated ? <Outlet /> : <Navigate to="/login" replace />; }
ProtectedAdminRoute.jsx
import { useEffect, useState } from 'react'; import { Navigate, Outlet } from 'react-router-dom'; export default function ProtectedAdminRoute() { const [isAuthenticated, setIsAuthenticated] = useState(null); const [isCustomer, setIsCustomer] = useState(false); useEffect(() => { const checkAuth = async () => { // Check if user is logged in as admin const adminRes = await fetch('/api/admin/check-auth'); if (adminRes.ok) { setIsAuthenticated(true); return; } // Check if user is logged in as customer const customerRes = await fetch('/api/customer/check-auth'); if (customerRes.ok) { setIsCustomer(true); } setIsAuthenticated(false); }; checkAuth(); }, []); if (isAuthenticated === null) return <div>Loading...</div>; if (isCustomer) return <Navigate to="/customer/dashboard" replace />; return isAuthenticated ? <Outlet /> : <Navigate to="/system/base-admin" replace />; }
Add the API routes for auth checks in Laravel's api.php:
Route::middleware('auth:customer')->get('/customer/check-auth', function () { return response()->json(['authenticated' => true]); }); Route::middleware('auth:admin')->get('/admin/check-auth', function () { return response()->json(['authenticated' => true]); });
3. Route Setup
Configure your React router to use the protected route components:
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import CustomerLogin from './components/CustomerLogin'; import AdminLogin from './components/AdminLogin'; import CustomerDashboard from './components/CustomerDashboard'; import AdminDashboard from './components/AdminDashboard'; import ProtectedCustomerRoute from './components/ProtectedCustomerRoute'; import ProtectedAdminRoute from './components/ProtectedAdminRoute'; function App() { return ( <Router> <Routes> {/* Public Routes */} <Route path="/login" element={<CustomerLogin />} /> <Route path="/system/base-admin" element={<AdminLogin />} /> {/* Protected Customer Routes */} <Route element={<ProtectedCustomerRoute />}> <Route path="/customer/dashboard" element={<CustomerDashboard />} /> </Route> {/* Protected Admin Routes */} <Route element={<ProtectedAdminRoute />}> <Route path="/system/admin/dashboard" element={<AdminDashboard />} /> </Route> {/* Fallback Route */} <Route path="*" element={<Navigate to="/login" replace />} /> </Routes> </Router> ); } export default App;
4. Logout Handling
Add logout functionality to each dashboard component. For example, in CustomerDashboard.jsx:
import { useNavigate } from 'react-router-dom'; export default function CustomerDashboard() { const navigate = useNavigate(); const handleLogout = async () => { try { await fetch('/customer/logout', { method: 'POST', headers: { 'X-CSRF-TOKEN': document.querySelector('meta[name="csrf-token"]').content } }); navigate('/login'); } catch (err) { console.error('Logout failed:', err); } }; return ( <div> <h2>Customer Dashboard</h2> <button onClick={handleLogout}>Logout</button> {/* Dashboard content */} </div> ); }
Repeat this for the admin dashboard, using the /system/admin/logout endpoint and redirecting to /system/base-admin.
内容的提问来源于stack exchange,提问作者Mamun




