通过 login_required 装饰器转发 POST 参数的建议方法? [英] Suggested Method to Forward POST Parameters Through login_required Decorator?

查看:30
本文介绍了通过 login_required 装饰器转发 POST 参数的建议方法?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我目前遇到的问题是,当我在任何视图上使用 django.contrib.auth.decorators 中的 login_required 装饰器时,只要装饰器重定向(到登录页面),我的 POST 参数就不会到达受保护的视图) 并再次返回到受保护的视图.感谢有关如何解决此问题的建议(最好保持 login_required 装饰器和 POST 方法的便利性)!

I am currently having the problem that when I use the login_required decorator from django.contrib.auth.decorators on any of my views, my POST parameters do not arrive at the protected view whenever the decorator did redirect (to the login page) and back again to the protected view. Suggestions about how to work around this (preferably maintaining the convenience of the login_required decorator and the POST method) appreciated!

此页面似乎是关于此事的有争议的 Django 票证.尽管错误/增强是根据模板与视图逻辑构建的,而不仅仅是让视图可以访问参数,这是我的问题.

This page appears to be a contested Django ticket about the matter. Although the bug/enhancement was framed in terms of template vs. view logic instead of just making parameters accessible to a view, which is my problem.

推荐答案

我使用我认为可以接受的会话开发了以下解决方案.处理重定向和替换视图很棘手,这种方法似乎是在获得所需功能的同时不摆弄框架和不对抗 HTTP 协议的最佳平衡.这种方法的不利方面是在每个受保护的视图中检查会话变量所需的额外工作.

I have developed the following solution using sessions that I find acceptable. Dealing with redirects and substituting views is tricky, and this method seems to be the best balance of not fiddling with the framework and not fighting the HTTP protocol while gaining the desired functionality. The negative aspect of this method is the extra work required in each protected view checking the session variables.

  1. 创建一个自定义装饰器(login_required2,如下),如果用户通过身份验证则返回请求的视图,否则返回项目的登录视图.
  2. 登录视图:
  1. Create a custom decorator (login_required2, below) that returns the requested view if the user is authenticated and the project's login view otherwise.
  2. The login view:
  1. 将原始 POST 参数存储在会话变量中.
  2. 将原始 HTTP_REFERER 存储在会话变量中
  3. 如果用户正确认证,则返回与请求路径对应的视图(请求路径在整个登录过程中保持相同,并且与用户最初通过登录视图时请求的路径相同.)
  4. 莉>
  1. Stores the original POST parameters in a session variable.
  2. Stores the original HTTP_REFERER in a session variable
  3. If the user correctly authenticates, returns the view corresponding to the requested path (the requested path remains identical throughout the login process, and is identical to the path the user requested when they were originally passed the login view instead.)

  • 因此任何受保护的视图都必须在使用请求的 POSTMETA['HTTP_REFERER']
  • 之前检查会话变量

  • Any views protected thus must check the session variables before they use either the request's POST or META['HTTP_REFERER']
  • 代码如下:

    def login_view(request):    
        from django.conf import settings
        from django.core.urlresolvers import resolve
    
        USERNAME_FIELD_KEY = 'username'
        PASSWORD_FIELD_KEY = 'password'
    
        message = '' #A message to display to the user
        error_message = '' #An error message to display to the user
    
        #If the request's path is not the login URL, the user did not explicitly request 
        # the login page and we assume this view is protecting another.
        protecting_a_view = request.path != settings.LOGIN_URL
    
        post_params_present = bool(request.POST)
    
        #Any POST with username and password is considered a login attempt, regardless off what other POST parameters there may be
        login_attempt = request.POST and request.POST.has_key(USERNAME_FIELD_KEY) and request.POST.has_key(PASSWORD_FIELD_KEY)
    
        if protecting_a_view:
            message = 'You must login for access.'
            if not request.session.has_key(ACTUAL_REFERER_KEY):
                #Store the HTTP_REFERER if not already
                request.session[ACTUAL_REFERER_KEY] = request.META.get(HTTP_REFERER_KEY)
    
        if protecting_a_view and post_params_present and not login_attempt: 
            #Store the POST parameters for the protected view
            request.session[FORWARDED_POST_PARAMS_KEY] = request.POST
    
        if login_attempt:
            form = LoginForm(request.POST)
            if form.is_valid():
                username = form.cleaned_data[USERNAME_FIELD_KEY]
                password = form.cleaned_data[PASSWORD_FIELD_KEY]
                user = auth.authenticate(username=username, password=password)
                if user is not None:
                    if user.is_active:
                        auth.login(request, user)
                        if protecting_a_view:
                            actual_view, actual_args, actual_kwargs = resolve(request.path) #request.path refers to the protected view
                            return actual_view(request, *actual_args, **actual_kwargs)
                        else:
                            HttpResponseRedirect('/')
                    else:
                        message = 'That account is inactive.'
                else:
                    error_message = 'That username or password is incorrect.'
        else:
            form = LoginForm()
    
        context_dict = {
            'form': form,
            'message': message,
            'error_message': error_message,
        }
        return render_to_response2('my_app/login.html', context_dict)
    
    @login_required2
    def protected_view(request):
        post_params = {}
    
        if request.POST:
            post_params = request.POST
        elif request.session.has_key(FORWARDED_POST_PARAMS_KEY):
            post_params = request.session[FORWARDED_POST_PARAMS_KEY]
            del request.session[FORWARDED_POST_PARAMS_KEY]
        if post_params:
            #Process post_params as if it were request.POST here:
            pass
    
        #assuming this view ends with a redirect.  Otherwise could render view normally
        if request.session.has_key(ACTUAL_REFERER_KEY):
            redirect_location = request.session.get(ACTUAL_REFERER_KEY)
        elif request.META.get(HTTP_REFERER_KEY) != request.path:
            redirect_location = request.META.get(HTTP_REFERER_KEY)
        else:
            redirect_location = ROOT_PATH
        return HttpResponseRedirect(redirect_location)
    
    def login_required2(view_func):
        """
        A decorator that checks if the request has an authenticated user.
        If so it passes the request to the view.
        Otherwise, it passes the request to the login view, which is responsible
        for recognizing that the request was originally for another page and forwarding
        state along (GET, POST).
    
        See django.contrib.auth.decorators for how Django's auth decorators mesh 
        using _CheckLogin.  This decorator bypasses that for my ease of creation.
        """
        def login_required_decoration(request, *args, **kwargs):
            if request.user.is_authenticated():
                return view_func(request, *args, **kwargs)
            else:
                from django.conf import settings
                from django.core.urlresolvers import resolve
    
                login_url = settings.LOGIN_URL
                login_view, login_args, login_kwargs = resolve(login_url)
                #Here the user gets a login view instad of the view they requested
                return login_view(request, *login_args, **login_kwargs)
        return login_required_decoration
    

    这篇关于通过 login_required 装饰器转发 POST 参数的建议方法?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

    查看全文
    登录 关闭
    扫码关注1秒登录
    发送“验证码”获取 | 15天全站免登陆