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

基于用户组的Django自定义权限返回401,用户显示匿名

问题描述

尝试基于用户组成员身份实现权限控制,但调用接口时返回「Request failed with status code 401」,且已授权用户的request.user输出为「AnonymousUser」。相关代码如下:

permission.py

from django.contrib.auth.models import Group
from rest_framework import permissions

def is_in_group(user, group_name):
    try:
        return Group.objects.get(name=group_name).user_set.filter(id=user.id).exists()
    except Group.DoesNotExist:
        return False

class HasGroupPermission(permissions.BasePermission):
    def has_permission(self, request, view):
        print(request.user)
        required_groups_mapping = getattr(view, "required_groups", {})
        required_groups = required_groups_mapping.get(request.method, [])
        return all([is_in_group(request.user, group_name) if group_name != "__all__" else True for group_name in required_groups]) or (request.user and request.user.is_staff)

业务视图 views.py

from .models import AppOne
from .serializers import AppOnesSerializer
from rest_framework import generics
from scripts.permission import HasGroupPermission

class AppOneView(generics.ListAPIView):
    queryset = AppOne.objects.all()
    serializer_class = AppOnesSerializer
    permission_classes = [HasGroupPermission]  
    required_groups = {
        'GET': ['group1'],
        'POST': ['group1'],
        'PUT': ['group1'],
    }

自定义用户模型

class CustomUser(AbstractUser):
    age = models.PositiveIntegerField(blank=True, null=True)

JWT 相关代码

urls.py

from django.urls import path
from .views import ObtainTokenPairWithAgeView
urlpatterns = [
    path('token/obtain/', ObtainTokenPairWithAgeView.as_view(), name='token_create'),
]

JWT 视图 views.py

from rest_framework_simplejwt.views import TokenObtainPairView
from .serializers import MyTokenObtainPairSerializer
class ObtainTokenPairWithAgeView(TokenObtainPairView):
    serializer_class = MyTokenObtainPairSerializer

JWT 序列化器 serializers.py

from rest_framework_simplejwt.serializers import TokenObtainPairSerializer
class MyTokenObtainPairSerializer(TokenObtainPairSerializer):
    @classmethod
    def get_token(cls, user):
        token = super(MyTokenObtainPairSerializer, cls).get_token(user)
        token['age'] = user.age
        return token

解决方案

核心问题是未配置JWT认证类,DRF无法识别请求中的Token,导致用户被判定为匿名用户,权限校验失败返回401,按以下步骤修复:

1. 配置JWT认证类

局部配置(仅对当前视图生效)

在AppOneView中添加认证类声明:

from rest_framework_simplejwt.authentication import JWTAuthentication

class AppOneView(generics.ListAPIView):
    queryset = AppOne.objects.all()
    serializer_class = AppOnesSerializer
    authentication_classes = [JWTAuthentication]  # 新增该行
    permission_classes = [HasGroupPermission]  
    required_groups = {
        'GET': ['group1'],
        'POST': ['group1'],
        'PUT': ['group1'],
    }

全局配置(对所有视图生效)

在项目settings.py中添加全局认证配置:

REST_FRAMEWORK = {
    'DEFAULT_AUTHENTICATION_CLASSES': (
        'rest_framework_simplejwt.authentication.JWTAuthentication',
    ),
}

2. 确保请求正确携带Token

调用接口时,必须在请求头中添加Authorization字段,格式为:

Authorization: Bearer <获取到的JWT Access Token>

其中<获取到的JWT Access Token>是调用token/obtain/接口返回的access字段值。

3. 验证用户归属群组

确认测试用户确实属于group1:

  • 通过Django admin后台查看用户的群组关联;
  • 或在Django Shell中执行验证:
from django.contrib.auth.models import Group, User
user = User.objects.get(username="你的测试用户名")
print(user.groups.filter(name="group1").exists())  # 结果应为True

4. 优化权限判断逻辑(可选)

原is_in_group方法可简化,利用用户模型的反向关联直接查询,减少数据库操作:

def is_in_group(user, group_name):
    return user.groups.filter(name=group_name).exists()

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 14:22:26