本文将深入讲解前端权限控制中的接口权限管理,并提供完整的接口拦截器实现示例。
接口权限是指前端应用对后端API接口的访问控制,确保用户只能访问其有权限的接口资源。
// axios-instance.js
import axios from 'axios';
import { message } from 'antd';
import router from './router';
// 创建axios实例
const instance = axios.create({
baseURL: process.env.REACT_APP_API_BASE_URL,
timeout: 10000,
headers: {
'Content-Type': 'application/json',
},
});
// 请求拦截器
instance.interceptors.request.use(
(config) => {
// 从本地存储获取token
const token = localStorage.getItem('access_token');
if (token) {
config.headers.Authorization = `Bearer ${token}`;
}
// 添加请求时间戳
config.headers['X-Timestamp'] = Date.now();
return config;
},
(error) => {
return Promise.reject(error);
}
);
// 响应拦截器
instance.interceptors.response.use(
(response) => {
// 处理成功响应
return response.data;
},
(error) => {
// 处理错误响应
return handleResponseError(error);
}
);
// 错误处理函数
const handleResponseError = (error) => {
if (!error.response) {
// 网络错误
message.error('网络连接失败,请检查网络设置');
return Promise.reject(error);
}
const { status, data } = error.response;
switch (status) {
case 401:
// 未授权,跳转到登录页
handleUnauthorized();
break;
case 403:
// 权限不足
handleForbidden();
break;
case 404:
message.error('请求的资源不存在');
break;
case 500:
message.error('服务器内部错误');
break;
default:
message.error(data.message || '请求失败');
}
return Promise.reject(error);
};
// 处理未授权
const handleUnauthorized = () => {
localStorage.removeItem('access_token');
localStorage.removeItem('user_info');
message.error('登录已过期,请重新登录');
router.navigate('/login');
};
// 处理禁止访问
const handleForbidden = () => {
message.error('您没有权限执行此操作');
// 可以跳转到无权限页面
// router.navigate('/403');
};
export default instance;
// permission-interceptor.js
import axios from './axios-instance';
import store from './store';
import { getPermissionCodes } from './utils/permission';
// 需要权限验证的接口映射
const permissionMap = {
'/api/users': ['user:read', 'user:write'],
'/api/roles': ['role:manage'],
'/api/admin': ['admin:all'],
};
// 权限验证请求拦截器
axios.interceptors.request.use(
(config) => {
// 检查当前请求是否需要权限验证
const requiresPermission = checkPermissionRequired(config.url, config.method);
if (requiresPermission) {
// 获取用户权限列表
const userPermissions = getCurrentUserPermissions();
// 验证权限
const hasPermission = verifyPermission(
config.url,
config.method,
userPermissions
);
if (!hasPermission) {
// 如果没有权限,直接抛出错误
return Promise.reject({
response: {
status: 403,
data: { message: '没有访问权限' }
}
});
}
}
return config;
},
(error) => Promise.reject(error)
);
// 检查接口是否需要权限验证
function checkPermissionRequired(url, method) {
// 排除白名单接口(如登录、注册等公共接口)
const whiteList = [
'/api/auth/login',
'/api/auth/register',
'/api/public',
];
if (whiteList.some(whiteUrl => url.includes(whiteUrl))) {
return false;
}
// 检查权限映射表
for (const [apiPath, permissions] of Object.entries(permissionMap)) {
if (url.includes(apiPath)) {
return true;
}
}
return false;
}
// 获取当前用户权限
function getCurrentUserPermissions() {
// 从Redux store或本地存储获取
const user = store.getState().user;
if (user && user.permissions) {
return user.permissions;
}
// 或从本地存储获取
const userInfo = JSON.parse(localStorage.getItem('user_info') || '{}');
return userInfo.permissions || [];
}
// 验证权限
function verifyPermission(url, method, userPermissions) {
// 查找对应的权限码
for (const [apiPath, requiredPermissions] of Object.entries(permissionMap)) {
if (url.includes(apiPath)) {
// 检查用户是否拥有所需权限
const hasAllPermissions = requiredPermissions.every(permission =>
userPermissions.includes(permission)
);
return hasAllPermissions;
}
}
// 如果没有在权限映射表中找到,默认需要验证
return userPermissions.length > 0;
}
export default axios;
// utils/permission.js
class PermissionManager {
constructor() {
this.permissionCache = new Map();
}
// 初始化权限
initPermissions(permissions) {
localStorage.setItem('user_permissions', JSON.stringify(permissions));
this.permissionCache.clear();
}
// 获取权限列表
getPermissions() {
const cached = this.permissionCache.get('all');
if (cached) return cached;
const permissions = JSON.parse(localStorage.getItem('user_permissions') || '[]');
this.permissionCache.set('all', permissions);
return permissions;
}
// 检查是否有某个权限
hasPermission(permissionCode) {
const permissions = this.getPermissions();
return permissions.includes(permissionCode);
}
// 检查是否有任意一个权限
hasAnyPermission(permissionCodes) {
const permissions = this.getPermissions();
return permissionCodes.some(code => permissions.includes(code));
}
// 检查是否有所有权限
hasAllPermissions(permissionCodes) {
const permissions = this.getPermissions();
return permissionCodes.every(code => permissions.includes(code));
}
// 清除权限
clearPermissions() {
localStorage.removeItem('user_permissions');
this.permissionCache.clear();
}
}
// 权限码常量
export const PERMISSIONS = {
USER_READ: 'user:read',
USER_WRITE: 'user:write',
USER_DELETE: 'user:delete',
ROLE_MANAGE: 'role:manage',
ADMIN_ALL: 'admin:all',
};
export const permissionManager = new PermissionManager();
// components/withPermission.jsx
import React from 'react';
import { Navigate } from 'react-router-dom';
import { permissionManager } from '../utils/permission';
/**
* 权限高阶组件
* @param {Array|string} requiredPermissions 需要的权限
* @param {ReactNode} fallback 没有权限时显示的内容
*/
const withPermission = (requiredPermissions, fallback = null) => (WrappedComponent) => {
const PermissionWrapper = (props) => {
// 转换权限参数为数组
const permissions = Array.isArray(requiredPermissions)
? requiredPermissions
: [requiredPermissions];
// 检查权限
const hasPermission = permissionManager.hasAllPermissions(permissions);
if (!hasPermission) {
if (fallback) {
return fallback;
}
// 默认跳转到403页面
return <Navigate to="/403" replace />;
}
return <WrappedComponent {...props} />;
};
PermissionWrapper.displayName = `WithPermission(${
WrappedComponent.displayName || WrappedComponent.name || 'Component'
})`;
return PermissionWrapper;
};
export default withPermission;
// App.jsx
import React, { useEffect } from 'react';
import { BrowserRouter, Routes, Route, Navigate } from 'react-router-dom';
import { ConfigProvider, message } from 'antd';
import axios from './api/axios-instance';
import { permissionManager, PERMISSIONS } from './utils/permission';
import withPermission from './components/withPermission';
// 页面组件
import Login from './pages/Login';
import Dashboard from './pages/Dashboard';
import UserManagement from './pages/UserManagement';
import AdminPanel from './pages/AdminPanel';
import NoPermission from './pages/403';
// 带权限的用户管理页面
const UserManagementWithPermission = withPermission(
[PERMISSIONS.USER_READ, PERMISSIONS.USER_WRITE]
)(UserManagement);
// 带权限的管理员面板
const AdminPanelWithPermission = withPermission(
PERMISSIONS.ADMIN_ALL
)(AdminPanel);
function App() {
useEffect(() => {
// 检查登录状态
const token = localStorage.getItem('access_token');
if (token) {
// 获取用户权限
fetchUserPermissions();
}
}, []);
const fetchUserPermissions = async () => {
try {
const response = await axios.get('/api/user/permissions');
permissionManager.initPermissions(response.data);
} catch (error) {
console.error('获取权限失败:', error);
}
};
return (
<ConfigProvider>
<BrowserRouter>
<Routes>
<Route path="/login" element={<Login />} />
<Route path="/" element={<Dashboard />} />
<Route path="/users" element={<UserManagementWithPermission />} />
<Route path="/admin" element={<AdminPanelWithPermission />} />
<Route path="/403" element={<NoPermission />} />
<Route path="*" element={<Navigate to="/" replace />} />
</Routes>
</BrowserRouter>
</ConfigProvider>
);
}
export default App;
// 后端返回的权限数据结构
const backendPermissions = {
apiPermissions: {
'/api/users': {
GET: ['user:read'],
POST: ['user:write'],
PUT: ['user:write'],
DELETE: ['user:delete']
},
'/api/roles': {
GET: ['role:read'],
POST: ['role:write'],
DELETE: ['role:delete']
}
},
userPermissions: ['user:read', 'user:write']
};
// 动态权限拦截器
axios.interceptors.request.use(
async (config) => {
// 获取动态权限配置
const apiPermissions = JSON.parse(
localStorage.getItem('api_permissions') || '{}'
);
const url = config.url;
const method = config.method.toUpperCase();
// 查找对应的权限要求
let requiredPermissions = [];
for (const [apiPath, methods] of Object.entries(apiPermissions)) {
if (url.includes(apiPath) && methods[method]) {
requiredPermissions = methods[method];
break;
}
}
if (requiredPermissions.length > 0) {
const userPermissions = permissionManager.getPermissions();
const hasPermission = requiredPermissions.every(perm =>
userPermissions.includes(perm)
);
if (!hasPermission) {
return Promise.reject(new Error('权限不足'));
}
}
return config;
}
);
前端接口权限控制是提升系统安全性和用户体验的重要手段。通过合理的拦截器设计和权限管理机制,可以有效控制用户对API的访问。记住,前端权限控制只是辅助手段,真正的安全验证必须在服务端实现。
根据实际项目需求,可以选择合适的权限模型和实现方案,建议结合路由权限和按钮级权限,构建完整的前端权限体系。