【问题标题】:csrf token for ajax in django2django2中ajax的csrf令牌
【发布时间】:2018-12-11 06:09:29
【问题描述】:

我正在学习Django2,并尝试用csrf_token和ajax制作一个登录页面。

我希望如果用户还没有登录,那会转到登录页面,并在登录前发送一个变量next作为该页面的标签。如果用户登录成功,我可以转到主页或标记的页面通过next

我阅读了 Django2 的文档,并尝试编写如下代码,但是,当我单击“登录”按钮时,它只是刷新登录页面并且没有错误

我很困惑,已经不知道了。请帮忙。

登录浏览量:

def login(request):
    if request.is_ajax():
        uf = UserForm(request.POST)
        if uf.is_valid():
            # get info from form
            username = uf.cleaned_data['username']
            password = uf.cleaned_data['password']
            user = auth.authenticate(request, username=username, password=password)
            if user is not None:  # user match
                auth.login(request, user)
                if request.GET.get('next'):
                    next_url = request.GET.get('next')
                    return JsonResponse({'redirect_url': next_url})
                    # return redirect(request.GET.get('next'))
                else:
                    return JsonResponse({'redirect_url': 'home'})
            else:  # user not match
                error_msg = ["username or pwd mistake"]
                return JsonResponse({'error_msg': error_msg})
    else:
        uf = UserForm()
    return render(request, 'login.html', {'uf': uf})

html:

    <form>
      {% csrf_token %}
       {{ uf.username }}
       {{ uf.password }}
      <div id="errorMsg"></div>
        <button type="submit" class="btn btn-default" id="loginButton">login</button>
     <input type="hidden" name="next" id="redirect-next" value="{{ next|escape }}"/>
   </form>

JQuery:

       $("#loginButton").click(function () {
    $.ajax({
        url: "",
        type: 'POST',
        dataType: "json",
        data: {username: $("#inputEmail3").val(), password: $("#inputPassword3").val()},
        beforeSend: function (xhr, settings) {
            var csrftoken = Cookies.get('csrftoken');
            function csrfSafeMethod(method) {
                // these HTTP methods do not require CSRF protection
                return (/^(GET|HEAD|OPTIONS|TRACE)$/.test(method));
            }
            if (!csrfSafeMethod(settings.type) && !this.crossDomain) {
                xhr.setRequestHeader("X-CSRFToken", csrftoken);
            }
        },
        success: function (result) {
            if (result.error_msg) {
                $('#errorMsg').show().text('user info error') //print an alert on the page
            }
            else {
                location.href = result.redirect_url //turn to homepage or page before login
            }
        }
    })
});

【问题讨论】:

  • 将您的类型从 submit 更改为 buttonsubmit 类型将导致您的表单被提交,而不是点击事件被触发。另请查看我的答案,了解在 django 中实现登录系统的更好方法。

标签: ajax django django-csrf


【解决方案1】:

您不需要像这样费力地编写自己的登录视图。 Django 提供了更简单的方法来实现它。

首先确保您的settings.py中包含以下内容

MIDDLEWARE_CLASSES = [
    ...
    'django.contrib.auth.middleware.AuthenticationMiddleware',
    ...
]
INSTALLED_APPS = [
    ...
    'django.contrib.auth',
    'django.contrib.contenttypes',
    ...
]

将所有登录 URL 添加到您的主 urls.py

from django.urls import path
from django.conf.urls import include


urlpatterns = [
....
    path('accounts/', include('django.contrib.auth.urls')),
....
]

不要忘记运行python manage.py migrate 来创建auth 应用程序所需的表。现在应用程序和 URL 已准备就绪,需要创建模板。该应用程序的所有模板都应放在您的templates 目录下名为registration 的文件夹下。目录结构应该是这样的。

your_django_app/
    templates/
        registration/
            login.html
    __init__.py
    apps.py
    settings.py
    urls.py
    views.py
    wsgi.py

login.html 的内容应该是这样的:

<form id="loginform" action="{% url 'login' %}" method="POST">
{% csrf_token %}
{% if next %}
    <input type="hidden" name="next" value="{{ next }}" />
{% endif %}
    <input name="username" id="id_username" type="text">
    <label>Username</label>
    <input name="password" id="id_password" type="password">
    <label>Password</label>
{% if form.errors %}
    Error! Wrong credentials.
{% endif %}
    <button type="submit">Login</button>
</form>

在此之后将这些包含在您的settings.py 文件中,以便在登录后正确重定向用户。

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

你们都准备好了。确保在运行python manage.py createsuperuser 之前至少创建一个用户。对于需要用户在查看之前登录的所有页面,您可以使用它们各自视图函数上方的@login_required 装饰器在显示页面之前将它们重定向到登录页面。示例:

from django.shortcuts import render
from django.contrib.auth.decorators import login_required

@login_required
def home(request):
    return render(request, 'home/index.html')

【讨论】:

  • 实际上我已经使用了'auth'并在每个页面中添加了@login_required^^我更改了按钮的类型并使用HttpResponse(json.dumps.....)而不是JsonResponse(... .),它有效。你真好^^谢谢
  • 我刚刚提到了一种更清洁的方法。我认为 ajax 和 jquery 对于一个简单的登录页面来说有点太多了。
  • ajax 只是为了显示一些错误信息,例如“用户名或密码错误”而不刷新登录页面。
【解决方案2】:

这里有一种使用 ajax 解析 csrf_token 的简短方法:

在脚本标签内。

    $.ajax({
           url: window.location.pathname,
           type: 'POST',
           data: {
                 ......,
                // Note this step.
                'csrfmiddlewaretoken': "{{ csrf_token }}"
                },
                success: function() {
                   .....
                }
    });

希望一切顺利,因为我已经在我的 2 个基于 Django 的项目中使用这个东西来解析 csrf_token。干杯!

【讨论】:

  • 唯一的问题是后续的ajax请求不起作用。
【解决方案3】:

这可能与issue有关

当您的按钮尝试提交表单但您希望它由脚本处理时。

尝试将按钮类型更改为

type="button" 

【讨论】:

    猜你喜欢
    • 2019-06-01
    • 2018-02-10
    • 2011-06-13
    • 2018-09-07
    • 2016-02-11
    • 1970-01-01
    • 1970-01-01
    • 2019-01-13
    • 2014-04-13
    相关资源
    最近更新 更多