如何在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
相关产品推荐
相关产品推荐

