DRF技术问询:如何为DefaultRouter设置登录保护,限制API Root访问?
为Django REST Framework的DefaultRouter设置登录保护(API Root权限控制)
你提到的问题很常见:虽然你已经给OrderViewSet配置了IsAuthenticated权限,但DefaultRouter生成的API Root页面(也就是访问根路径时显示的API列表)默认是允许匿名访问的——因为DRF的默认API Root视图没有绑定权限类。下面给你两种可行的解决方法:
方法一:自定义API Root视图(精准控制)
这种方法只给API Root添加权限,不影响全局其他视图(如果有的话),步骤如下:
- 在你的views文件中,自定义一个带权限校验的API Root视图,复用DefaultRouter的API列表生成逻辑:
from rest_framework import viewsets, permissions from rest_framework.response import Response from rest_framework.views import APIView from .models import Order from .serializers import OrderSerializer # 你的OrderViewSet保持不变,注意修正权限类的格式(末尾加逗号,确保是可迭代对象) class OrderViewSet(viewsets.ReadOnlyModelViewSet): permission_classes = (permissions.IsAuthenticated,) queryset = Order.objects.all() serializer_class = OrderSerializer # 自定义受保护的API Root视图 class ProtectedAPIRootView(APIView): permission_classes = (permissions.IsAuthenticated,) def get(self, request, *args, **kwargs): # 复用DefaultRouter的API根目录生成逻辑 router = DefaultRouter() router.register(r'orders', OrderViewSet) return Response(router.get_api_root_view().get(request).data)
- 在urls.py中,替换默认的router根路径,改用自定义视图:
from django.conf.urls import url, include from rest_framework.routers import DefaultRouter from . import views router = DefaultRouter() router.register(r'orders', views.OrderViewSet) urlpatterns = [ # 用自定义视图替换默认API Root url(r'^$', views.ProtectedAPIRootView.as_view(), name='api-root'), # 保留其他路由配置 url(r'^', include(router.urls)), url(r'^auth/', include('rest_framework.urls')), ]
方法二:全局设置默认权限(适合全API需登录的场景)
如果你的整个API都要求用户登录才能访问,直接在项目的settings.py中配置DRF的全局默认权限类即可——这样包括API Root在内的所有视图都会自动应用这个权限:
REST_FRAMEWORK = { 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.IsAuthenticated', ] }
设置后,你甚至可以不用给OrderViewSet单独写permission_classes(当然保留也没问题,视图级别的权限优先级高于全局设置)。如果有个别视图需要允许匿名访问,只需在对应视图类中设置permission_classes = (permissions.AllowAny,)即可覆盖全局配置。
重要注意点
permission_classes的值必须是可迭代对象(元组或列表),所以要写成(permissions.IsAuthenticated,)(末尾加逗号),否则会因传入单个对象而报错。- 确保你已经配置了DRF的登录视图(即代码中的
url(r'^auth/', include('rest_framework.urls'))),这样用户可以通过该路径登录获取访问权限。
内容的提问来源于stack exchange,提问作者bdoubleu
相关产品推荐
相关产品推荐

