【问题标题】:Django Update Middleware to replace decoratorDjango 更新中间件以替换装饰器
【发布时间】:2021-12-18 23:01:27
【问题描述】:

我有以下装饰器,当应用于不同的视图时效果很好:@otp_required(login_url='login') 在我的网站上:

装饰器

from django.contrib.auth.decorators import user_passes_test

from django_otp import user_has_device
from django_otp.conf import settings


def otp_required(view=None, redirect_field_name='next', login_url=None, if_configured=False):
    """
    Similar to :func:`~django.contrib.auth.decorators.login_required`, but
    requires the user to be :term:`verified`. By default, this redirects users
    to :setting:`OTP_LOGIN_URL`.

    :param if_configured: If ``True``, an authenticated user with no confirmed
        OTP devices will be allowed. Default is ``False``.
    :type if_configured: bool
    """
    if login_url is None:
        login_url = settings.OTP_LOGIN_URL

    def test(user):
        return user.is_verified() or (if_configured and user.is_authenticated and not user_has_device(user))

    decorator = user_passes_test(test, login_url=login_url, redirect_field_name=redirect_field_name)

    return decorator if (view is None) else decorator(view)

但是,我想将其转换为中间件,因为我想避免将装饰器应用于我网站上的每个视图,但无法正常工作。 我尝试修改我目前拥有的以下中间件,这些中间件仅适用于授权用户并且一直在工作,但根据上述装饰器,我希望此中间件也扩展为也需要 OTP:

中间件

from django.utils.deprecation import MiddlewareMixin
from django.urls import resolve, reverse
from django.http import HttpResponseRedirect
from wfi_workflow import settings
from django_otp import user_has_device
from django_otp.decorators import otp_required
from django_otp.middleware import is_verified

class LoginRequiredMiddleware(MiddlewareMixin):
    """
    Middleware that requires a user to be authenticated to view any page other
    than LOGIN_URL. Exemptions to this requirement can optionally be specified
    in settings by setting a tuple of routes to ignore
    """

    #@otp_required(login_url='login')
    def process_request(self, request):
        assert hasattr(request, 'user'), """
        The Login Required middleware needs to be after AuthenticationMiddleware.
        Also make sure to include the template context_processor:
        'django.contrib.account.context_processors.account'."""


        if not request.user.is_verified() and not request.path.startswith('/admin/') and not request.path.startswith('/account/' ):

            current_route_name = resolve(request.path_info).url_name

            if not current_route_name in settings.AUTH_EXEMPT_ROUTES:
                return HttpResponseRedirect(reverse(settings.LOGIN_URL))

非常感谢您的帮助。

【问题讨论】:

  • 你能分享MIDDLEWARE的设置吗?

标签: django decorator django-middleware


【解决方案1】:

您返回 HttpResponseRedirect 的事实将不起作用:Django 的 MiddlewareMixin 将简单地调用该函数来(可选地)更改请求,但它永远不会考虑返回。

您可以做的是在类似装饰器的结构中定义中间件,并返回 HttpResponseRedirect 以防用户应该通过以下方式进行身份验证:

from django.urls import resolve, reverse
from django.http import HttpResponseRedirect
from wfi_workflow import settings

def OTPRequiredMiddleware(get_response):
    """
    Middleware that requires a user to be authenticated to view any page other
    than LOGIN_URL. Exemptions to this requirement can optionally be specified
    in settings by setting a tuple of routes to ignore
    """
    def middleware(request):
        from django_otp import user_has_device
        if not user.is_verified() and not (if_configured and user.is_authenticated and not user_has_device(user)):
            return HttpResponseRedirect(settings.OTP_LOGIN_URL)
        return get_response(request)

【讨论】:

  • 对不起,我不确定我是否足够清楚,我上面显示的中间件实际上适用于我的网站,但我想将我显示的装饰器转换为我的中间件,因为我希望用户不能除非需要 otp,否则查看我网站上的页面。如果我在页面上使用装饰器,那么它可以限制用户,但我宁愿使用中间件而不是装饰器。谢谢
  • @rob:但答案中的中间件将装饰器的逻辑实现为中间件类,因此您可以将其添加到中间件类中。您应该继承自 MiddlewareMixin 基类:它来自 django.deprecation 模块,并且仅用于在现代版本的 Django 中使用 old-style 中间件但建议使用新的中间件。
  • @rob:我更新了中间件以使用装饰器中指定的 OTP。
猜你喜欢
  • 2019-10-21
  • 1970-01-01
  • 2015-11-18
  • 2012-02-02
  • 1970-01-01
  • 2021-11-20
  • 1970-01-01
  • 2018-04-12
  • 2015-01-18
相关资源
最近更新 更多