基于用户组的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
相关产品推荐
相关产品推荐

