Javascript Django身份验证和Ajax—需要登录的URL

Javascript Django身份验证和Ajax—需要登录的URL,javascript,python,django,authentication,Javascript,Python,Django,Authentication,我想给我的Django编码的网站增加一些细节 在Django代码中,我使用Django.contrib.auth.decorators中的@login\u requireddecorator标记哪个视图需要身份验证。未经身份验证的用户单击时的默认行为是将其重定向到登录页面,然后传递目标页面 我在一些网站上看到的,并且我非常喜欢的是,当用户点击一个链接,指向一个仅限于登录用户的地方,而不是重定向到登录页面时,他/她会得到一个弹出窗口(通过JavaScript),要求他/她登录或注册。没有重定向部分

我想给我的Django编码的网站增加一些细节

在Django代码中,我使用
Django.contrib.auth.decorators
中的
@login\u required
decorator标记哪个视图需要身份验证。未经身份验证的用户单击时的默认行为是将其重定向到登录页面,然后传递目标页面

我在一些网站上看到的,并且我非常喜欢的是,当用户点击一个链接,指向一个仅限于登录用户的地方,而不是重定向到登录页面时,他/她会得到一个弹出窗口(通过JavaScript),要求他/她登录或注册。没有重定向部分,因此,如果用户认为他/她真的不喜欢该网站而浪费注册时间,则无需使用“后退”键


因此,问题是:您如何管理自动将某些链接标记为“受限”的任务,以便JavaScript能够处理它们的
onclick
事件并显示“请登录”弹出窗口

听起来像是一个页面模板

  • 您可以通过
    传递
    链接\u(或其他内容),您可以通过
    onClick=“return popup(this,'arg')”
    None
    提供该链接。每个链接都是

    • 对于匿名会话,
      LINK\u VIA
      有一个值
    • 对于登录会话,
      LINK\u VIA
      为无
  • 您可以在
    标记周围使用
    {%if%}
    语句。这似乎有些罗嗦

  • 您可以使用for
    {%link\u via%}
    编写自己的自定义标记。我对此不太熟悉,但您可以提供链接和文本作为字符串,您的标记可以生成两种链接中的一种

  • 我同意

    在模板中做一个检查,如果用户已登录,只需像往常一样放置链接,如果没有,则放置如下内容

    <a href="{{link}}" onclick="return login_popup()"> 
    
    通过它的

    如果模板不知道哪些URL需要用户登录,您可能需要重新考虑您的设计

    如果必须的话,我想您可以像DjangoURL调度器一样发现视图函数
    请参阅:
    django.core.urlResolver

    一旦你掌握了查看功能,你可以检查它是否用@login\u required修饰

    这可能会在自定义标记中完成

    如果您使用Jinja2,您不需要标签,只需实现该功能并将其公开给环境,这很简单,但您需要阅读一下Jinja2的API)

    我也面临同样的问题,而且,和您一样,我想要一个简单的装饰器来包装DjangoAjax视图,以便以与其他视图相同的方式处理身份验证。一种对我来说似乎很有希望的方法是将这种装饰器与JavaScript结合使用,以在响应中查找特定值

    这是装饰师的第一份修订稿:

    from functools import wraps
    
    def ajax_login_required(view_func):
        @wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if request.user.is_authenticated():
                return view_func(request, *args, **kwargs)
            json = simplejson.dumps({ 'not_authenticated': True })
            return HttpResponse(json, mimetype='application/json')
        return wrapper
    
    以下是视图:

    @ajax_login_required
    def ajax_update_module(request, module_slug, action):
        # Etc ...
        return HttpResponse(json, mimetype='application/json')
    
    下面是JavaScript(jQuery):



    编辑:我已尝试按照建议使用
    functools.wrapps
    。我还没有在工作代码中实际使用过这个装饰器,所以要小心可能的bug。

    这里是建议的带有wrap的装饰器版本。\uuu doc\uuu,wrap.\uu name__

    from functools import wraps
    
    def ajax_login_required(function):
        def wrap(request, *args, **kwargs):
            if request.user.is_authenticated():
                return function(request, *args, **kwargs)
            json = simplejson.dumps({ 'not_authenticated': True })
            return HttpResponse(json, mimetype='application/json')  
        wrap.__doc__ = function.__doc__
        wrap.__name__ = function.__name__
        return wrap
    
    基于解决方案构建,但适用于Django 2.0

    # Standard Imports
    import functools
    import django.http
    
    def ajax_login_required(view_func):
        @functools.wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if request.user.is_authenticated:
                return view_func(request, *args, **kwargs)
    
            return django.http.JsonResponse('Unauthorized', status=401, safe=False)
    
        return wrapper
    

    我想知道的是,如何从模板的角度确定链接指向的视图是否用@login\u required修饰…模板没有随机链接。它有您在模板中专门设计和编码的特定链接。我建议您更改模板中专门放置的每个链接。可能值得指出的是,您可以使用
    functools.wrapps
    def wrapp
    decorator,以避免分配给
    wrapp.\uuu doc\uuuuuuuuuu
    wrapp.\uuu dict\uuuuuuuuuu
    wrapp.\uu name\uuuuuuuuu
    (本回答中未提及,但应这样做)。请参见@Anders:请继续编辑响应以合并更改。我已经有一段时间没有使用Python了,我不想把它搞砸。视图不应该改为发送401 HTTP状态吗?我不确定为什么这是可接受的答案。这只适用于ajax请求。如果用户单击链接访问受限视图会怎么样?您是否应该更改所有相关的客户端代码以使用initiate ajax请求?我在这一点上迟到了很多,但不管怎样:这是不理想的,因为用户可以直接链接到相关页面,在这种情况下,需要登录的弹出式方法将中断。
    # Standard Imports
    import functools
    import django.http
    
    def ajax_login_required(view_func):
        @functools.wraps(view_func)
        def wrapper(request, *args, **kwargs):
            if request.user.is_authenticated:
                return view_func(request, *args, **kwargs)
    
            return django.http.JsonResponse('Unauthorized', status=401, safe=False)
    
        return wrapper