You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.10.02 13:45:03