Аутентификация Django и Ajax - URL, которые требуют входа - PullRequest
49 голосов
/ 23 ноября 2008

Я хочу добавить Ajax -neness на мой сайт, кодированный Django.

В моем коде Django я использую декоратор @login_required из django.contrib.auth.decorators, чтобы отметить, какое представление требует аутентификации. Поведение по умолчанию, когда пользователь, не прошедший проверку подлинности, щелкает его, состоит в том, чтобы перенаправить его на страницу входа в систему и затем передать целевую страницу.

То, что я видел на некоторых сайтах, и мне очень понравилось, что когда пользователь щелкает ссылку, ведущую к месту, ограниченному только для зарегистрированных пользователей, вместо того, чтобы перенаправляться на страницу входа, он / она получает всплывающее окно (через JavaScript) попросить его / ее войти или зарегистрироваться. Нет никакой части перенаправления, поэтому пользователю не нужно использовать клавишу «назад», если он / она решит, что ему / ей действительно не нравится веб-сайт достаточно, чтобы тратить время на регистрацию.

Итак, вопрос: как бы вы справились с задачей автоматической пометки некоторых ссылок как «ограниченных», чтобы JavaScript мог обрабатывать их событие onclick и отображать всплывающее окно «Пожалуйста, войдите в систему»?

Ответы [ 5 ]

55 голосов
/ 07 февраля 2009

Я сталкиваюсь с той же проблемой, и, как и вы, я бы хотел, чтобы простой декоратор обернул представление Ajax Django, чтобы обрабатывать аутентификацию так же, как и другие представления. Один из подходов, который мне кажется многообещающим, заключается в использовании такого декоратора в сочетании с 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):

$.post('/restricted-url/', data, function(json) {
    if (json.not_authenticated) {
        alert('Not authorized.');  // Or something in a message DIV
        return;
    }
    // Etc ...
});

РЕДАКТИРОВАТЬ : Я пытался использовать functools.wraps, как было предложено. На самом деле я не использовал этот декоратор в рабочем коде, поэтому остерегайтесь возможных ошибок.

5 голосов
/ 24 ноября 2008

Я бы согласился с S.Lott

Сделайте проверку в шаблоне, если пользователь залогинен, просто поставьте ссылку как обычно, если нет, поставьте что-то вроде

<a href="{{link}}" onclick="return login_popup()"> 

где login_popup вернет false, если пользователь скажет отменить.

Вероятно, это можно сделать гораздо проще в Jinja2 через макросы .

Если шаблон не знает, какие URL-адреса требуют от пользователя входа в систему, вам, вероятно, необходимо пересмотреть свой дизайн.

Если вам нужно, я думаю, вы можете сделать то же самое, что и диспетчер URL-адресов django, чтобы обнаружить функцию представления.
см .: django.core.urlresolvers

как только вы захватили функцию просмотра, вы можете проверить, украшена ли она @login_required.

Возможно, это будет сделано в пользовательском теге.
Если вы используете Jinja2, вам не понадобится тег, просто реализуйте функцию и предоставьте ее среде, это просто, но вам придется немного прочесть о API Jinja2)

5 голосов
/ 24 ноября 2008

Похоже на возможность шаблона страницы.

  1. Вы можете передать LINK_VIA (или что-то), которое вы предоставляете как onClick="return popup(this, 'arg')" или None. Каждая ссылка будет <A HREF="link" {{LINK_VIA}}>some text</a>.

    • Для анонимных сессий LINK_VIA имеет значение.
    • Для зарегистрированных сеансов LINK_VIA Нет
  2. Вы можете использовать оператор {% if %} вокруг ваших тегов <A HREF=...>. Это кажется многословным.

  3. Вы можете написать свой собственный тег для {% link_via %}. Я недостаточно знаком с этим, но вы можете предоставить ссылку и текст в виде строк, и ваш тег может генерировать один из двух видов ссылок.

1 голос
/ 01 марта 2018

Построен из решения Эрика Уокера , но для 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
1 голос
/ 21 августа 2016

Здесь предлагается версия декоратора с переносом .__ doc__, перенос .__ 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
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...