Django:ajax 调用时 login_required

Posted

技术标签:

【中文标题】Django:ajax 调用时 login_required【英文标题】:Django: login_required on ajax call 【发布时间】:2014-04-07 10:22:40 【问题描述】:

我正在尝试对 ajax 帖子上的用户进行身份验证,但不起作用。这是我所做的

settings.py

LOGIN_URL = '/accounts/login/'
LOGIN_REDIRECT_URL = '/'

模板

<script>
  $('.btn-request').click(function()
        var button = this;
        $.ajax(
                 type: "POST",
                 url: "% url 'like' %",
                 data: 'tutorial_id': $(this).attr('name'), 'csrfmiddlewaretoken': 'csrf_token',
                 dataType: "json",
                 success: function(json) 
                    toastr.success(json.message);

                  ,
                  error: function(rs, e) 
                        alert(rs.responseText);
                  
            );
      )
  </script>

urls.py

url(r'^like/$', 'apps.quotation.views.like', name='like'),

views.py - 尝试 1

@login_required
def like(request):
        vars = 
        if request.method == 'POST':
            response_dict = 

            if not something:
                response_dict.update('message': "Requested" )
            else:
                response_dict.update('message': "You have already requested" )

        return HttpResponse(simplejson.dumps(response_dict),
                        mimetype='application/javascript')

views.py - 尝试 2

def like(request):
    if not request.user.is_authenticated():
        return HttpResponseRedirect('/accounts/login')
    else:
        vars = 
        if request.method == 'POST':
            response_dict = 
            if not something:
                response_dict.update('message': "Requested" )
            else:
                response_dict.update('message': "You have already requested" )

        return HttpResponse(simplejson.dumps(response_dict),
                        mimetype='application/javascript')

运行服务器日志

[05/Mar/2014 05:19:16] "POST /like/ HTTP/1.1" 302 0
[05/Mar/2014 05:19:16] "GET /accounts/login/?next=/like/ HTTP/1.1" 200 5610

我错过了什么?

【问题讨论】:

您是否已登录以管理管理站点? views.py 尝试 2:“如果不是 request.user.is_authenticated():return...” 这与我使用的代码相同,为什么不在模板中显示用户? request.user 以确保您没有登录 我没有登录管理员。 request.user 在模板中显示了 AnonymousUser,我猜这意味着用户未通过身份验证? 是的,用户未经过身份验证,但您似乎在某个地方管理未经身份验证的用户。尝试类似“if request.user == 'AnonymousUser': return...” 【参考方案1】:

我不确定这是否是一个优雅的解决方案,但我按照Priyank Patel 的建议让它工作

<script>
  $('.btn-request').click(function()
        var button = this;
        $.ajax(
                 type: "POST",
                 url: "% url 'like' %",
                 data: 'tutorial_id': $(this).attr('name'), 'csrfmiddlewaretoken': 'csrf_token',
                 dataType: "json",
                 success: function(json) 
                    if(json.not_authenticated) 

                      window.location.replace("/accounts/login");
                    
                    else 
                    toastr.success(json.message);
                      
                  ,
                  error: function(rs, e) 
                    alert(rs.responseText);
                  
            );
      )
  </script>

views.py

def like(request):
    response_dict = 
    if request.user.is_authenticated():
        if request.method == 'POST':
            if not something:
                response_dict.update('message': "Requested" )
            else:
                response_dict.update('message': "You have already requested" )

        return HttpResponse(simplejson.dumps(response_dict),
                        mimetype='application/javascript')
    else:
        response_dict.update('message': "Login please",'not_authenticated':True  )
        return HttpResponse(simplejson.dumps(response_dict),
                        mimetype='application/javascript')

【讨论】:

【参考方案2】:

而不是:

if not request.user.is_authenticated():
   return HttpResponseRedirect('/accounts/login')

返回 json 响应:

if request.user.is_authenticated():
    ## write your code...
    jsonr = json.dumps( 'authenticated': True )
    return HttpResponse(jsonr, mimetype='application/json')
else:
    jsonr = json.dumps( 'authenticated': False )
    return HttpResponse(jsonr, mimetype='application/json')

并且在您的 ajax 成功响应中,如果未通过身份验证,则使用 windows.location 重定向到登录。

你可以写装饰器: Django authentication and Ajax - URLs that require login

【讨论】:

is_authenticated 现在是布尔运算符.. 对于 Django 2.0【参考方案3】:

当我想检查在进行 Ajax 调用时用户是否已登录,这是我使用的:

from functools import wraps
from django.core.exceptions import PermissionDenied

def ajax_login_required(view):
    @wraps(view)
    def wrapper(request, *args, **kwargs):
        if not request.user.is_authenticated():
            raise PermissionDenied
        return view(request, *args, **kwargs)
    return wrapper

raise PermissionDenied 将导致向客户端返回 403 状态代码。否则,如果您使用 @login_required 装饰器或手动执行对表单的重定向,那么 Ajax 调用视为响应的内容对人类有意义,但对 Ajax 调用没有意义。

【讨论】:

我认为如果问题是用户没有登录而不是他们没有适当的权限,他们应该得到一个 401 错误而不是 403。 OP 不是关于要返回的状态代码的表达式混淆,而是当请求是 AJAX 时使用什么机制来返回合理的东西。如果开发人员需要,我的答案可以很容易地适应给 401 而不是 403。当用户未登录时,必需肯定不是真的。(例如,参见this answer。) @Louis 401 与 403 链接的要点不是:401 = 未经过身份验证(即登录)并且; 403 = 未授权(即已登录但没有正确的权限)? @CpILL 这根本不是我链接到的答案的要点。那里的许多其他答案都对您提到的 401 和 403 进行了区分,但我链接到的答案特别指出这不是正确的区分。 401 用于当您的身份验证机制使用 Authorization 标头时。我部署的所有 Django 服务器都没有使用这种机制。 您的第一个报价结束得太早了。以下是相关部分:“服务器正在请求客户端通过 HTTP 身份验证登录并已发送回复标头以启动流程”我已将重要部分加粗。看,401 不是您在任何时候由于用户未登录而无法完成请求时发送的响应。仅在您希望用户使用“HTTP 身份验证”时发送它。而且“HTTP 身份验证”不是一个通用术语,而是一个指代 HTTP 标头的特定用途的术语。默认情况下,django不使用这个方法,所以401是不合适的。

以上是关于Django:ajax 调用时 login_required的主要内容,如果未能解决你的问题,请参考以下文章

jQuery AJAX POST 在第一次调用时跳过 Django CSRF 令牌标头

当前路径具有子目录或 url 参数时,使用 AJAX 调用视图函数不起作用(Django)

在 Django 视图中调用“request.POST”时,Ajax POST 不发送数据

Ajax 调用不更新模板 django

Django 管理员添加表单 ajax 调用

如何使用 javascript/jquery/AJAX 调用 Django REST API?