Django Rest Framework不同用户类型自定义权限及React侧处理指南
Django后端自定义权限实现步骤
1. 给业务模型添加自定义权限
首先在你需要控制权限的3个业务模型的Meta类中声明自定义权限,示例如下(假设你要求普通用户仅能创建Comment模型,moderator仅能编辑Post模型的review_status字段,可根据实际业务替换对应模型和字段):
from django.db import models class Post(models.Model): title = models.CharField(max_length=100) content = models.TextField() review_status = models.BooleanField(default=False) class Meta: permissions = [ ("can_edit_review_status", "可以编辑审核状态"), # 给moderator的专属权限 ] class Comment(models.Model): content = models.TextField() post = models.ForeignKey(Post, on_delete=models.CASCADE) class Report(models.Model): # 第三个业务模型示例 reason = models.TextField()
2. 自定义DRF权限校验类
基于Django REST Framework的BasePermission实现自定义权限规则,全局优先判断admin身份,再匹配其他角色的权限:
from rest_framework.permissions import BasePermission, SAFE_METHODS class CustomRolePermission(BasePermission): def has_permission(self, request, view): # admin拥有所有权限,直接放行 if request.user.is_admin: return True # 普通用户权限:仅能创建指定的Comment模型 if request.user.is_normal_user: return ( request.method == "POST" and view.get_queryset().model == Comment ) # moderator权限 if request.user.is_moderator: # 允许所有安全请求(GET/OPTIONS/HEAD) if request.method in SAFE_METHODS: return True # 仅允许编辑Post模型的专属字段权限 if request.method in ["PUT", "PATCH"] and view.get_queryset().model == Post: return request.user.has_perm("your_app_name.can_edit_review_status") return False
3. 实现字段级权限控制
在对应模型的序列化器中控制字段的可编辑权限,避免moderator修改Post模型除review_status外的其他字段:
from rest_framework import serializers class PostSerializer(serializers.ModelSerializer): class Meta: model = Post fields = ["id", "title", "content", "review_status"] def __init__(self, *args, **kwargs): super().__init__(*args, **kwargs) request = self.context.get("request") if not request: return # 如果是moderator,仅保留review_status字段可编辑 if request.user.is_moderator and not request.user.is_admin: for field_name in self.fields: if field_name != "review_status": self.fields[field_name].read_only = True
4. 注册权限&提供权限查询接口
- 把自定义权限类配置到对应的视图/视图集的
permission_classes属性中,也可以在settings.py中配置为全局默认权限类 - 新增一个用户信息接口,登录后返回当前用户的角色标识和权限列表,供前端使用:
# 视图示例 from rest_framework.decorators import api_view, permission_classes from rest_framework.permissions import IsAuthenticated from rest_framework.response import Response @api_view(["GET"]) @permission_classes([IsAuthenticated]) def get_user_perms(request): return Response({ "is_admin": request.user.is_admin, "is_moderator": request.user.is_moderator, "is_normal_user": request.user.is_normal_user, "perms": list(request.user.get_all_permissions()) })
React端权限对接步骤
1. 全局存储用户权限信息
登录成功后调用上面的用户权限接口,把返回的权限信息存在全局状态中(可选用Zustand、Redux、React Context等方案,以下用Zustand示例):
// store/useUserStore.js import { create } from 'zustand' const useUserStore = create((set) => ({ userInfo: null, setUserInfo: (info) => set({ userInfo: info }), })) export default useUserStore
2. 路由级权限控制
封装私有路由组件,根据用户角色限制可访问的路由,示例基于React Router v6:
// components/PrivateRoute.js import { Navigate } from 'react-router-dom' import useUserStore from '../store/useUserStore' const PrivateRoute = ({ children, requiredRole }) => { const { userInfo } = useUserStore() if (!userInfo) return <Navigate to="/login" /> // 权限判断 const hasPermission = userInfo.is_admin || (requiredRole === 'moderator' && userInfo.is_moderator) || (requiredRole === 'normal' && userInfo.is_normal_user) return hasPermission ? children : <Navigate to="/403" /> } // 路由中使用 <Route path="/admin/dashboard" element={ <PrivateRoute requiredRole="admin"> <AdminDashboard /> </PrivateRoute> } />
3. 页面元素级权限控制
封装通用权限容器组件,控制按钮、输入框等元素的显示/禁用:
// components/PermissionWrapper.js import useUserStore from '../store/useUserStore' const PermissionWrapper = ({ children, requiredRole, requiredPerm, showDisabled = false }) => { const { userInfo } = useUserStore() if (!userInfo) return null const hasRole = userInfo.is_admin || (requiredRole === 'moderator' && userInfo.is_moderator) || (requiredRole === 'normal' && userInfo.is_normal_user) const hasPerm = requiredPerm ? userInfo.perms.includes(requiredPerm) : true if (!hasRole || !hasPerm) { // 传showDisabled参数时不符合权限会禁用元素而非隐藏 return showDisabled ? <div style={{opacity:0.5, pointerEvents:"none"}}>{children}</div> : null } return children } // 页面中使用:只有moderator和admin能看到审核状态编辑按钮 <PermissionWrapper requiredRole="moderator"> <button onClick={handleReview}>修改审核状态</button> </PermissionWrapper>
4. 请求层前置校验
在axios请求拦截器中加权限校验,不符合权限的请求直接拦截提示,减少无效的后端请求:
axios.interceptors.request.use((config) => { const { userInfo } = useUserStore.getState() // 比如普通用户调用Post创建接口直接拦截 if (userInfo?.is_normal_user && config.url === '/api/posts/' && config.method === 'post') { return Promise.reject(new Error('您没有创建该内容的权限')) } return config })
注意:前端所有权限控制仅用于优化用户体验,绝对不能作为安全依据,所有敏感操作必须在后端做完整的权限校验。
内容的提问来源于stack exchange,提问作者Menna Magdy
相关产品推荐
相关产品推荐

