系统架构设计
1. 全局前置守卫 - 路由拦截器
// src/components/AuthGuard.jsx
import { useEffect } from 'react';
import { useNavigate, useLocation } from 'react-router-dom';
import { useAuth } from '../hooks/useAuth';
const AuthGuard = ({ children }) => {
const navigate = useNavigate();
const location = useLocation();
const { token, userInfo, checkPermission } = useAuth();
useEffect(() => {
// Token校验
if (!token) {
navigate('/login', { state: { from: location } });
return;
}
// 权限校验
const currentPath = location.pathname;
if (!checkPermission(currentPath)) {
navigate('/403'); // 无权限页面
return;
}
}, [token, location.pathname]);
return token ? children : null;
};
export default AuthGuard;
2. Token管理与RBAC权限控制
// src/hooks/useAuth.js
import { createContext, useContext, useState, useEffect } from 'react';
import { jwtDecode } from 'jwt-decode';
const AuthContext = createContext();
export const AuthProvider = ({ children }) => {
const [token, setToken] = useState(localStorage.getItem('token'));
const [userInfo, setUserInfo] = useState(null);
const [permissions, setPermissions] = useState([]);
const [roles, setRoles] = useState([]);
// Token校验
const validateToken = (token) => {
try {
const decoded = jwtDecode(token);
return decoded.exp > Date.now() / 1000;
} catch {
return false;
}
};
// 登录
const login = async (credentials) => {
try {
const response = await fetch('/api/login', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(credentials)
});
const data = await response.json();
if (data.success) {
setToken(data.token);
setUserInfo(data.userInfo);
setPermissions(data.permissions);
setRoles(data.roles);
localStorage.setItem('token', data.token);
return { success: true };
}
} catch (error) {
return { success: false, error: error.message };
}
};
// 权限检查
const checkPermission = (permission) => {
return permissions.includes(permission) ||
roles.some(role => role.permissions?.includes(permission));
};
// 角色检查
const hasRole = (role) => {
return roles.some(r => r.name === role);
};
useEffect(() => {
if (token && !validateToken(token)) {
logout();
}
}, [token]);
const logout = () => {
setToken(null);
setUserInfo(null);
setPermissions([]);
setRoles([]);
localStorage.removeItem('token');
};
return (
<AuthContext.Provider value={{
token, userInfo, permissions, roles,
login, logout, checkPermission, hasRole
}}>
{children}
</AuthContext.Provider>
);
};
export const useAuth = () => useContext(AuthContext);
3. 动态路由与菜单权限
// src/router/DynamicRouter.jsx
import { useMemo } from 'react';
import { Routes, Route } from 'react-router-dom';
import { useAuth } from '../hooks/useAuth';
import AuthGuard from '../components/AuthGuard';
// 路由配置
const routeConfig = [
{
path: '/dashboard',
component: () => import('../pages/Dashboard'),
permission: 'dashboard:view',
meta: { title: '仪表盘', icon: 'dashboard' }
},
{
path: '/users',
component: () => import('../pages/Users'),
permission: 'user:view',
meta: { title: '用户管理', icon: 'users' },
children: [
{
path: '/users/list',
component: () => import('../pages/Users/List'),
permission: 'user:list'
}
]
}
];
const DynamicRouter = () => {
const { checkPermission } = useAuth();
// 根据权限过滤路由
const filteredRoutes = useMemo(() => {
const filterRoutes = (routes) => {
return routes.filter(route => {
if (route.permission && !checkPermission(route.permission)) {
return false;
}
if (route.children) {
route.children = filterRoutes(route.children);
}
return true;
});
};
return filterRoutes(routeConfig);
}, [checkPermission]);
return (
<Routes>
{filteredRoutes.map(route => (
<Route
key={route.path}
path={route.path}
element={
<AuthGuard>
<route.component />
</AuthGuard>
}
/>
))}
</Routes>
);
};
export default DynamicRouter;
4. 动态菜单生成
// src/components/DynamicMenu.jsx
import { useMemo } from 'react';
import { Menu } from 'antd';
import { useAuth } from '../hooks/useAuth';
import { useNavigate } from 'react-router-dom';
const DynamicMenu = () => {
const { checkPermission } = useAuth();
const navigate = useNavigate();
const menuItems = useMemo(() => {
const buildMenuItems = (routes) => {
return routes
.filter(route => route.permission ? checkPermission(route.permission) : true)
.map(route => ({
key: route.path,
icon: route.meta?.icon,
label: route.meta?.title,
children: route.children ? buildMenuItems(route.children) : undefined
}));
};
return buildMenuItems(routeConfig);
}, [checkPermission]);
const handleMenuClick = ({ key }) => {
navigate(key);
};
return (
<Menu
mode="inline"
items={menuItems}
onClick={handleMenuClick}
/>
);
};
export default DynamicMenu;
5. 按钮级别权限控制 - 自定义指令
// src/components/PermissionButton.jsx
import { useAuth } from '../hooks/useAuth';
const PermissionButton = ({
permission,
role,
children,
fallback = null,
...props
}) => {
const { checkPermission, hasRole } = useAuth();
// 权限检查
const hasPermission = permission ? checkPermission(permission) : true;
const hasRequiredRole = role ? hasRole(role) : true;
if (!hasPermission || !hasRequiredRole) {
return fallback;
}
return children;
};
// 使用示例
const UserManagement = () => {
return (
<div>
<PermissionButton permission="user:create">
<button>新增用户</button>
</PermissionButton>
<PermissionButton permission="user:edit">
<button>编辑用户</button>
</PermissionButton>
<PermissionButton
permission="user:delete"
role="admin"
fallback={<span>无权限</span>}
>
<button>删除用户</button>
</PermissionButton>
</div>
);
};
export default PermissionButton;
6. 高阶组件权限控制
// src/hoc/withPermission.jsx
import { useAuth } from '../hooks/useAuth';
const withPermission = (permission, fallback = null) => {
return (WrappedComponent) => {
return (props) => {
const { checkPermission } = useAuth();
if (!checkPermission(permission)) {
return fallback;
}
return <WrappedComponent {...props} />;
};
};
};
// 使用示例
const AdminPanel = withPermission('admin:access')(() => {
return <div>管理员面板</div>;
});
7. 权限指令Hook
// src/hooks/usePermission.js
import { useAuth } from './useAuth';
export const usePermission = () => {
const { checkPermission, hasRole } = useAuth();
const can = (permission) => checkPermission(permission);
const cannot = (permission) => !checkPermission(permission);
const is = (role) => hasRole(role);
const isNot = (role) => !hasRole(role);
return { can, cannot, is, isNot };
};
// 使用示例
const MyComponent = () => {
const { can, is } = usePermission();
return (
<div>
{can('user:view') && <UserList />}
{is('admin') && <AdminTools />}
</div>
);
};
8. 应用入口配置
// src/App.jsx
import { BrowserRouter } from 'react-router-dom';
import { AuthProvider } from './hooks/useAuth';
import DynamicRouter from './router/DynamicRouter';
import DynamicMenu from './components/DynamicMenu';
function App() {
return (
<BrowserRouter>
<AuthProvider>
<div className="app">
<aside className="sidebar">
<DynamicMenu />
</aside>
<main className="content">
<DynamicRouter />
</main>
</div>
</AuthProvider>
</BrowserRouter>
);
}
export default App;
核心特性
- Token自动校验:全局拦截器自动检查Token有效性
- RBAC权限模型:支持角色和权限的灵活组合
- 动态路由:根据用户权限动态生成可访问路由
- 动态菜单:菜单项根据权限实时显示/隐藏
- 按钮级控制:细粒度的操作权限控制
- 多种使用方式:组件、HOC、Hook等多种权限控制方式
- 类型安全:完整的TypeScript支持(可选)
这套方案提供了完整的前端权限控制体系,可以根据实际需求进行调整和扩展。