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

如何在Graphene/Django中基于用户类型限制模型字段读写权限?

在Graphene中基于用户权限控制GraphQL字段的读写访问

刚好在Graphene里落地过类似的字段权限控制需求,给你分享一个可扩展的实现方案——核心是把权限判断逻辑和业务解析器解耦,方便后续迭代更多权限规则。

1. 先确保解析器能获取当前请求用户

在Graphene中,请求上下文(info.context)会携带已登录的用户信息(前提是你已经配置了身份验证,比如Django的Session Auth或者JWT)。所以在任何解析器里,你都可以通过info.context.user拿到当前操作的用户。

2. 定义可复用的权限判断逻辑

为了避免重复写权限判断代码,我们可以把权限规则抽成单独的类(比函数更易扩展):

class BasePermission:
    def has_permission(self, user):
        raise NotImplementedError("必须实现has_permission方法,定义具体权限规则")

class SalaryViewPermission(BasePermission):
    def has_permission(self, user):
        # 示例规则:用户属于"薪资查看组"
        return user.groups.filter(name='Salary Viewers').exists()

class SalaryEditPermission(BasePermission):
    def has_permission(self, user):
        # 示例规则:用户属于"薪资编辑组"
        return user.groups.filter(name='Salary Editors').exists()

后续要加新权限,只需要继承BasePermission实现新的规则即可。

3. 控制字段的读取权限

对于salary这种需要权限才能读取的字段,我们给它自定义解析器,在里面做权限校验:

import graphene
from graphene_django import DjangoObjectType
from .models import Employee
from .permissions import SalaryViewPermission
from graphql import GraphQLError

class EmployeeType(DjangoObjectType):
    class Meta:
        model = Employee
        fields = ("id", "first_name", "last_name", "salary")

    # 自定义salary字段的解析器
    def resolve_salary(self, info):
        user = info.context.user
        # 校验查看权限
        if not SalaryViewPermission().has_permission(user):
            # 两种处理方式:返回None隐藏字段,或者抛出明确的权限错误
            # return None
            raise GraphQLError("你没有权限查看薪资信息")
        return self.salary

这样普通用户访问first_name和last_name完全不受影响,只有符合权限的用户才能拿到salary的值。

4. 控制字段的写入/更新权限

对于修改salary的Mutation操作,我们在执行更新前先校验用户的编辑权限:

class UpdateEmployeeSalary(graphene.Mutation):
    class Arguments:
        employee_id = graphene.Int(required=True)
        salary = graphene.Float(required=True)

    employee = graphene.Field(EmployeeType)

    def mutate(self, info, employee_id, salary):
        user = info.context.user
        # 校验编辑权限
        if not SalaryEditPermission().has_permission(user):
            raise GraphQLError("你没有权限修改薪资信息")
        
        # 执行更新逻辑
        try:
            employee = Employee.objects.get(id=employee_id)
            employee.salary = salary
            employee.save()
            return UpdateEmployeeSalary(employee=employee)
        except Employee.DoesNotExist:
            raise GraphQLError("目标员工不存在")

没有权限的用户发起更新请求时,会直接被拦截并返回错误,不会执行数据库操作。

5. 进阶优化:用装饰器简化权限校验

如果有很多字段或Mutation需要权限校验,可以把权限检查封装成装饰器,减少重复代码:

from functools import wraps
from graphql import GraphQLError

def permission_required(permission_class):
    def decorator(resolver):
        @wraps(resolver)
        def wrapper(self, info, *args, **kwargs):
            user = info.context.user
            if not permission_class().has_permission(user):
                raise GraphQLError("权限不足,无法执行此操作")
            return resolver(self, info, *args, **kwargs)
        return wrapper
    return decorator

之后在解析器或Mutation里直接用装饰器即可:

# 字段解析器用装饰器
@permission_required(SalaryViewPermission)
def resolve_salary(self, info):
    return self.salary

# Mutation的mutate方法用装饰器
@permission_required(SalaryEditPermission)
def mutate(self, info, employee_id, salary):
    # 省略更新逻辑

这个方案的优势在于权限逻辑和业务逻辑完全分离,后续要调整权限规则或者新增权限,只需要修改或新增Permission类即可,不需要改动业务解析器,扩展性拉满。

内容的提问来源于stack exchange,提问作者Berry

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 07:09:07