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

如何通过Token限制Django REST API的用户访问权限?

问题描述

参考William Vincent所著《REST API’s with Django》搭建REST API,已完成书中配置,但遇到两个核心问题:

  1. 在UserList类中添加authentication_classes = [TokenAuthentication]后,携带Token的用户无法正常访问API;移除该配置后,所有用户都能无限制访问,不符合"仅持有Token的用户可访问API"的需求。
  2. 希望进一步通过Token限制用户仅能查看API中的特定信息(例如仅能查看自身的用户信息)。
相关代码

api/views.py

from django.contrib.auth import get_user_model

from rest_framework import generics, permissions
from rest_framework.authentication import TokenAuthentication
from .serializers import UserSerializer

# Display List View - User
class UserList(generics.ListAPIView):
    queryset = get_user_model().objects.all()
    serializer_class = UserSerializer
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = [TokenAuthentication]

api/serializers.py

from django.contrib.auth import get_user_model
from rest_framework import serializers

class UserSerializer(serializers.ModelSerializer):
    class Meta:
        model = get_user_model()
        fields =('id', 'username', 'email',)

api/urls.py

from django.urls import path
from .views import  (UserList)

urlpatterns = [
    path('users/', UserList.as_view()),    
]

master_application/urls.py

urlpatterns = [
    path('admin/', admin.site.urls),
    path('', include('users.urls')),
    path('api/', include('api.urls')),
    path('api-auth/', include('rest_framework.urls')),
    path('api/rest-auth/', include('rest_auth.urls')),
    path('api/rest-auth/registration/', include('rest_auth.registration.urls')),
    path('', include('django.contrib.auth.urls')),    
    path('users/', include('users.urls')),
    path('users/', include('django.contrib.auth.urls')),
]

settings.py

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAdminUser',
        'rest_framework.permissions.IsAuthenticated',
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
       'rest_framework.authentication.SessionAuthentication',
       'rest_framework.authentication.TokenAuthentication', 
    ]
}
解决方案

1. 修复Token认证后无法访问的问题

你的settings.py中DEFAULT_PERMISSION_CLASSES同时配置了IsAdminUser和IsAuthenticated,这意味着请求需要同时满足是管理员和已认证两个条件,普通携带Token的非管理员用户会被直接拒绝访问。

修改settings.py的权限配置,仅保留IsAuthenticated即可:

REST_FRAMEWORK = {
    'DEFAULT_PERMISSION_CLASSES': [
        'rest_framework.permissions.IsAuthenticated',  # 仅保留这一行
    ],
    'DEFAULT_AUTHENTICATION_CLASSES': [
       'rest_framework.authentication.SessionAuthentication',
       'rest_framework.authentication.TokenAuthentication', 
    ]
}

同时确保请求时正确携带Token:

  • 在请求头中添加:Authorization: Token <你的Token值>
  • 或通过URL参数传递:?token=<你的Token值>

如果仍然报错,检查是否给目标用户生成了Token:可以通过Django admin查看,或执行命令生成:

python manage.py drf_create_token <用户名>

2. 限制用户仅能查看自身信息

当前UserList返回所有用户数据,要实现用户仅能查看自身信息,推荐以下两种方案:

方案一:改用RetrieveAPIView获取当前用户信息

修改api/views.py,创建返回当前请求用户数据的视图:

from django.contrib.auth import get_user_model
from rest_framework import generics, permissions
from rest_framework.authentication import TokenAuthentication
from .serializers import UserSerializer

class CurrentUserView(generics.RetrieveAPIView):
    serializer_class = UserSerializer
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = [TokenAuthentication]

    def get_object(self):
        return self.request.user

更新api/urls.py:

from django.urls import path
from .views import CurrentUserView

urlpatterns = [
    path('user/', CurrentUserView.as_view()),  # 单个用户的端点,符合REST规范
]

用户访问/api/user/时,只会返回自身的信息。

方案二:修改ListAPIView的queryset过滤当前用户

如果坚持使用ListAPIView(不推荐,列表接口返回单个数据不符合REST规范),可以通过重写get_queryset过滤数据:

class UserList(generics.ListAPIView):
    serializer_class = UserSerializer
    permission_classes = (permissions.IsAuthenticated,)
    authentication_classes = [TokenAuthentication]

    def get_queryset(self):
        # 仅返回当前请求用户的数据
        return get_user_model().objects.filter(id=self.request.user.id)

额外扩展:管理员与普通用户的权限区分

如果需要实现"管理员可查看所有用户,普通用户仅能查看自身"的细粒度控制,可以自定义权限类:

from rest_framework import permissions

class IsOwnerOrAdmin(permissions.BasePermission):
    def has_permission(self, request, view):
        # 管理员允许访问所有接口
        if request.user.is_staff:
            return True
        # 普通用户仅允许访问自身信息的详情接口
        return view.action == 'retrieve' and request.user.id == view.kwargs.get('pk')

然后在视图中使用该权限类:permission_classes = (IsOwnerOrAdmin,)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 08:10:32