ReactJs/Laravel路由保护咨询:登录用户及角色权限控制实现
React + Laravel 实现路由保护与基于角色的身份验证
一、Laravel 后端实现
1. 配置 API 身份认证(以 JWT 为例)
先安装并配置 tymon/jwt-auth 包,这是 API 场景下常用的身份验证方案:
composer require tymon/jwt-auth php artisan vendor:publish --provider="Tymon\JWTAuth\Providers\LaravelServiceProvider" php artisan jwt:secret
修改用户模型,实现 JWTSubject 接口,让 JWT 能携带用户角色信息:
use Tymon\JWTAuth\Contracts\JWTSubject; class User extends Authenticatable implements JWTSubject { // 原有代码保持不变 public function getJWTIdentifier() { return $this->getKey(); } public function getJWTCustomClaims() { return [ 'role' => $this->role // 假设用户表包含 `role` 字段,值如 'admin'/'user' ]; } }
2. 编写角色验证中间件
创建专门校验用户角色的中间件:
php artisan make:middleware CheckRole
在 app/Http/Middleware/CheckRole.php 中编写逻辑:
namespace App\Http\Middleware; use Closure; use Illuminate\Http\Request; use Tymon\JWTAuth\Facades\JWTAuth; class CheckRole { public function handle(Request $request, Closure $next, ...$roles) { try { $user = JWTAuth::parseToken()->authenticate(); } catch (\Exception $e) { return response()->json(['message' => '未授权'], 401); } if (!in_array($user->role, $roles)) { return response()->json(['message' => '权限不足'], 403); } return $next($request); } }
在 app/Http/Kernel.php 中注册中间件:
protected $routeMiddleware = [ // 原有中间件保持不变 'jwt.auth' => \Tymon\JWTAuth\Http\Middleware\Authenticate::class, 'role' => \App\Http\Middleware\CheckRole::class, ];
3. 保护 API 路由
在 routes/api.php 中划分路由权限:
// 公开路由:登录、注册 Route::post('/login', [AuthController::class, 'login']); Route::post('/register', [AuthController::class, 'register']); // 需要登录才能访问的路由组 Route::middleware('jwt.auth')->group(function () { Route::get('/dashboard', [DashboardController::class, 'index']); // 需要 admin 角色才能访问的路由组 Route::middleware('role:admin')->group(function () { Route::get('/admin/users', [AdminController::class, 'getUsers']); }); });
登录接口示例(AuthController):
public function login(Request $request) { $credentials = $request->only('email', 'password'); if (!$token = auth('api')->attempt($credentials)) { return response()->json(['error' => '用户名或密码错误'], 401); } return $this->respondWithToken($token); } protected function respondWithToken($token) { return response()->json([ 'access_token' => $token, 'token_type' => 'bearer', 'expires_in' => auth('api')->factory()->getTTL() * 60, 'user' => auth('api')->user() ]); }
二、React 前端实现
1. 封装身份验证工具类
创建 src/utils/auth.js,管理 token 和用户信息:
// 存储 token export const setToken = (token) => localStorage.setItem('token', token); // 获取 token export const getToken = () => localStorage.getItem('token'); // 退出登录,清除本地数据 export const logout = () => { localStorage.removeItem('token'); localStorage.removeItem('user'); }; // 存储用户信息 export const setUser = (user) => localStorage.setItem('user', JSON.stringify(user)); // 获取用户信息 export const getUser = () => JSON.parse(localStorage.getItem('user')); // 判断是否已登录 export const isAuthenticated = () => !!getToken(); // 判断用户是否拥有指定角色 export const hasRole = (role) => { const user = getUser(); return user && user.role === role; };
2. 编写路由守卫组件
创建通用登录守卫 src/components/ProtectedRoute.jsx:
import { Navigate, Outlet } from 'react-router-dom'; import { isAuthenticated } from '../utils/auth'; const ProtectedRoute = () => { if (!isAuthenticated()) { return <Navigate to="/login" replace />; } return <Outlet />; }; export default ProtectedRoute;
创建 admin 角色专属守卫 src/components/AdminRoute.jsx:
import { Navigate, Outlet } from 'react-router-dom'; import { isAuthenticated, hasRole } from '../utils/auth'; const AdminRoute = () => { if (!isAuthenticated()) { return <Navigate to="/login" replace />; } if (!hasRole('admin')) { return <Navigate to="/403" replace />; } return <Outlet />; }; export default AdminRoute;
3. 配置 React 路由
在 App.jsx 中设置路由规则:
import { BrowserRouter as Router, Routes, Route, Navigate } from 'react-router-dom'; import Login from './pages/Login'; import Dashboard from './pages/Dashboard'; import AdminPanel from './pages/AdminPanel'; import Forbidden from './pages/Forbidden'; import NotFound from './pages/NotFound'; import ProtectedRoute from './components/ProtectedRoute'; import AdminRoute from './components/AdminRoute'; function App() { return ( <Router> <Routes> {/* 公开路由 */} <Route path="/login" element={<Login />} /> <Route path="/403" element={<Forbidden />} /> <Route path="/404" element={<NotFound />} /> {/* 需要登录的路由组 */} <Route element={<ProtectedRoute />}> <Route path="/dashboard" element={<Dashboard />} /> {/* 需要 admin 角色的路由组 */} <Route element={<AdminRoute />}> <Route path="/admin" element={<AdminPanel />} /> </Route> </Route> {/* 默认跳转规则 */} <Route path="/" element={<Navigate to="/dashboard" replace />} /> <Route path="*" element={<Navigate to="/404" replace />} /> </Routes> </Router> ); } export default App;
4. 配置 API 请求拦截器
创建 src/utils/axios.js,自动携带 token 并处理未授权情况:
import axios from 'axios'; import { getToken, logout } from './auth'; const api = axios.create({ baseURL: 'http://你的LaravelAPI地址/api', }); // 请求拦截:自动添加 token 到请求头 api.interceptors.request.use( (config) => { const token = getToken(); if (token) { config.headers.Authorization = `Bearer ${token}`; } return config; }, (error) => Promise.reject(error) ); // 响应拦截:处理 token 过期或未授权 api.interceptors.response.use( (response) => response, (error) => { if (error.response.status === 401) { logout(); window.location.href = '/login'; } return Promise.reject(error); } ); export default api;
内容的提问来源于stack exchange,提问作者WILBERT JOSH ALFORNON
相关产品推荐
相关产品推荐

