【问题标题】:Django Write Authentication Redirect for Blackboxed Route URLsDjango 为黑盒路由 URL 编写身份验证重定向
【发布时间】:2026-01-13 21:50:01
【问题描述】:

我正在使用一个名为 django-dashing 的 django 库,它具有一组预定义的 url,用于呈现仪表板。我像这样导入它们

urlpatterns = [
    ...
    url(r'^dashboard/', include(dashing_router.urls)),
    ...
]

我希望路由器只能由管理员访问,我可以通过 django-dashing 中的一些配置设置来实现。但是,当非管理员用户尝试访问 /dashboard/ 时,我想将他们重定向到 django 的 /admin/ 面板让他们登录,而不是像 django-dashing 那样抛出 403

由于django-dashing 视图被有效地黑盒化,我想知道是否有一种方法可以编写一个“预览”来拦截对/dashboard/ 的请求,运行一些代码——具体来说,进行适当的重定向——然后继续进入实际的仪表板。

我知道这很容易通过编写两个 URL 来完成,例如 /dashboard-auth/ 重定向到 /dashboard/,但我不希望用户必须转到一个 URL 才能到达另一个 URL

有什么建议吗?

【问题讨论】:

    标签: python django django-views


    【解决方案1】:

    Django 简单的自定义中间件是另一种选择...

    from django.core.urlresolvers import reverse
    from django.http import HttpResponseRedirect
    
    class DashingRedirectMiddleware(object):
    
        def process_request(self, request):
            if request.path.startswith('/dashing/') and not request.user.is_staff:
                return HttpResponseRedirect(reverse('admin:login'))
            return
    

    不要忘记将此中间件添加到您的 DJANGO SETTINGS...

    MIDDLEWARE_CLASSES = [
        ...
        'django.contrib.auth.middleware.AuthenticationMiddleware',
        'yourapp.middleware.DashingRedirectMiddleware',
        ...
    ]
    

    或者类似的东西。

    【讨论】:

    • 谢谢,绝对是最干净/最简单的答案
    • 您还可以设置next参数:'{0}?next={1}'.format(reverse('admin:login'), request.path),以便用户在登录后转到他们试图访问的页面。
    • 这个答案的唯一缺点是中间件会在对站点任何部分的每个请求上运行,这似乎有点矫枉过正
    【解决方案2】:

    我这样做的方法是覆盖 dashing 的默认路由器。所有的 url 都是由 Router 类动态生成的,因此通过覆盖 get_urls 方法,您可以将每个函数包装在 staff_member_required 装饰器中。

    from django.contrib.admin.views.decorators import staff_member_required
    from django.conf.urls import url
    
    from dashing.utils import Router
    from dashing.views import Dashboard
    
    
    class AdminRequiredRouter(Router):
    
        def get_urls(self):
            urlpatterns = [
                url(r'^$', staff_member_required(Dashboard.as_view()), name='dashboard'),
            ]
            for widget, basename, parameters in self.registry:
                urlpatterns += [
                    url(r'/'.join((
                        r'^widgets/{}'.format(basename),
                        r'/'.join((r'(?P<{}>{})'.format(parameter, regex)
                                   for parameter, regex in parameters.items())),
                    )),
                        staff_member_required(widget.as_view()),
                        name='widget_{}'.format(basename)),
                ]
            return urlpatterns
    
    router = AdminRequiredRouter()
    

    然后包括你的路由器而不是 dashing 的

    from .router import router
    
    urlpatterns = [
        ...
        url(r'^dashboard/', include(router.urls)),
        ...
    ]
    

    【讨论】:

      【解决方案3】:

      如果您愿意look inside 破折号网址的“黑匣子”,您可以看到/dashboard/Dashboard 视图处理。您可以将此视图子类化,并捕获 PermissionDenied 错误。

      from django.core.exceptions import PermissionDenied
      
      from dashing.views import Dashboard
      
      class MyDashboard(Dashboard):
          def get(self, request, *args, **kwargs):
              try:
                  return super(MyDashboard, self).get(request, *args, **kwargs)
              except PermissionDenied:
                  return redirect('/admin/')
      

      然后在上方添加你的视图:

      urlpatterns = [
          ...
          url(r'^dashboard/$', MyDashboard.as_view())
          url(r'^dashboard/', include(dashing_router.urls)),
          ...
      ]
      

      【讨论】:

      • 其他仪表板网址呢?他们将对任何人开放
      • @Brobin 为什么你认为他们会对任何人开放?我没有从其他 url 中删除任何权限检查,它们将具有与以前相同的权限检查。
      • 它们不会对任何人开放,它们会向您在django-dashing 的配置中配置的权限中的任何人开放
      • 我猜对任何人开放是不正确的。我的意思是,如果用户要访问 /dashboard/something 网址之一,他们不会像我认为 OP 正在寻找的那样被重定向到管理员登录
      • 我没有意识到人们直接访问了其他 url,我认为人们在浏览器中访问了 /dashboard/,并且小部件加载了 ajax。如果您还需要对小部件 url 进行重定向,那么中间件或自定义路由器将是一个不错的方法。