|
Оглавление
|
Сейчас вы находитесь на половине пути, соединяющим браузер с Реальными Людьми™. Сессии предоставляют нам механизм хранения данных между отдельными запросами. Вторая часть уравнения — использование сессии для авторизации пользователя. Конечно, мы не можем просто доверять, что они те кем представляются. Следовательно, нам потребуется механизм аутентификации. Django предоставляет инструменты для решения этой частой задачи (и для многих других). Система аутентификации пользователей Django управляет аккаунтами пользователей, группами, правами и пользовательскими сессиями (с помощью cookie). Эту систему часто называют системой аутентификации и авторизации (auth/auth или система АА). Двойное имя означает, что опознавание пользователей часто состоит из двух шагов. Нам необходимо:
Согласно этим нуждам система АА состоит из ряда частей:
Если вы пользовались интерфейсом администратора (описанном в главе «Интерфейс администратора Django», вы видели многие из этих инструментов. Если вы управляли пользователями и группами через интерфейс администратора, в действительности вы управляли данными в таблицах системы аутентификации. Подобно среде управления сессиями, поддержка аутентификации поставляется в виде Django приложения в django.contrib, которое необходимо установить. Как и раньше, система АА уже установлена по умолчанию, но если вы её отключали, то необходимо выполнить следующие шаги:
После выполнения установки мы готовы работать с пользователями в функциях представлений. Главным интерфейсом, который вы будете использовать для управления пользователями, является request.user — это объект, который представляет собой текущего авторизованного пользователя. Если пользователь не авторизован, то вместо этого объекта будет AnonymousUser (подробности будут дальше).
Определить авторизовался ли пользователь можно с помощью
метода if request.user.is_authenticated():
# Пользователь авторизован.
else:
# Анонимный пользователь.
Как только вы получили объект User — чаще
всего от request.user, но возможно и с помощью одного из ранее описанных методов — у вас появился
доступ к полям и методам этого объекта. Объекты
AnonymousUser эмулируют
часть этого интерфейса, но не всю,
поэтому вы всегда должны проверять авторизацию пользователя с
помощью метода Таблица 12.3. Поля объектов User
Таблица 12.4. Методы объектов User
Наконец, объекты User имеют поля «многие-ко-многим»: groups и permissions. Объекты User могут взаимодействовать с другими объектами тем же способом, что и другие поля с такими отношениями: # Определим группу для пользователя: myuser.groups = group_list # Добавим пользователя в несколько других групп: myuser.groups.add(group1, group2,...) # Удалим пользователя из этих групп: myuser.groups.remove(group1, group2,...) # Удалим пользователя из всех групп: myuser.groups.clear() # С правами работаем аналогично: myuser.permissions = permission_list myuser.permissions.add(permission1, permission2, ...) myuser.permissions.remove(permission1, permission2, ...) myuser.permissions.clear()
Django предоставляет встроенные функции представления для
работы с авторизацией и выходом пользователя (а так же ещё для
некоторых вещей), но прежде чем мы начнём их использовать,
рассмотрим «вручную» как пользователи
авторизуются и выходят. Django предоставляет в
django.contrib.auth две функции для выполнения
таких действий:
Для аутентификации пользователя по переданному логину и паролю
следует использовать функцию
>>> from django.contrib import auth >>> user = auth.authenticate(username='john', password='secret') >>> if user is not None: ... print "Правильно!" ... else: ... print "Ой, что-то пошло не так!"
Функция Этот пример показывает как можно совместно использовать эти функции в представлении: from django.contrib import auth
def login(request):
username = request.POST['username']
password = request.POST['password']
user = auth.authenticate(username=username, password=password)
if user is not None and user.is_active:
# Правильный пароль и пользователь "активен"
auth.login(request, user)
# Перенаправление на "правильную" страницу
return HttpResponseRedirect("/account/loggedin/")
else:
# Отображение страницы с ошибкой
return HttpResponseRedirect("/account/invalid/")
Для выхода пользователя следует использовать функцию
from django.contrib import auth
def logout(request):
auth.logout(request)
# Перенаправление на страницу.
return HttpResponseRedirect("/account/loggedout/")
Следует отметить, что функция На практике вам обычно не понадобится писать свои функции авторизации и выхода, так как система АА поставляется с набором представления для общей обработки этих процессов. Первым шагом для использования представлений аутентификации будет их привязка к URL: from django.contrib.auth.views import login, logout
urlpatterns = patterns('',
# существующие шаблоны располагаются здесь...
(r'^accounts/login/$', login),
(r'^accounts/logout/$', logout),
)
URL /accounts/login/ и /accounts/logout/ являются стандартными для этих представлений.
По умолчанию, представление login использует
шаблон {% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p class="error">Сожалеем, вы неправильно ввели логин или пароль</p>
{% endif %}
<form action='.' method='post'>
<label for="username">Логин:</label>
<input type="text" name="username" value="" id="username">
<label for="password">Пароль:</label>
<input type="password" name="password" value="" id="password">
<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next|escape }}" />
</form>
{% endblock %}
Если пользователь ввёл всё правильно, он перенаправляется по
умолчанию на страницу /accounts/profile/. Вы
можете переопределить это поведение, добавив скрытое поле с
именем next к URL для перенаправления на другую
страницу. Вы также можете передать это значение в качестве
параметра GET запроса в представление авторизации и оно будет
автоматически добавлено к контексту в виде переменной
Представление для выхода работает немного по-другому. По
умолчанию, оно использует шаблон
Причиной же, ради которой мы прорываемся сквозь лес проблем, является необходимость ограничения доступа к разделам нашего сайта. Простой и прямолинейный способ ограничения доступа к страницам — проверить результат выполнения
from django.http import HttpResponseRedirect
def my_view(request):
if not request.user.is_authenticated():
return HttpResponseRedirect('/login/?next=%s' % request.path)
# ...
или, возможно, отобразить сообщение об ошибке: def my_view(request):
if not request.user.is_authenticated():
return render_to_response('myapp/login_error.html')
# ...
Для сокращения вы можете использовать удобный декоратор login_required: from django.contrib.auth.decorators import login_required
@login_required
def my_view(request):
# ...
Декоратор делает следующее:
Процедура ограничения доступа, основанная на наличии определённых прав или на какой-дибо другой проверке, или на перенаправлении на другой раздел сайта для авторизации, работает таким же образом (см. предыдущий раздел). Прямолинейным способом является проверка request.user в представлении. Например, нижеприведённое представление проверяет авторизован ли пользователь и обладает ли он правом polls.can_vote (о правах будет рассказано ниже): def vote(request):
if request.user.is_authenticated() and request.user.has_perm('polls.can_vote')):
# Голосуем здесь
else:
return HttpResponse("Вы не можете голосовать по этому списку избирателей.")
И снова Django предоставляет сокращение user_passes_test. Оно принимает аргументы и создаёт специальный декоратор для вашей частной задачи: def user_can_vote(user):
return user.is_authenticated() and user.has_perm("polls.can_vote")
@user_passes_test(user_can_vote, login_url="/login/")
def vote(request):
# Здесь мы точно уверены, что пользователь авторизован и имеет
# необходимы права.
...
Сокращение user_passes_test принимает один обязательный аргумент: функцию, которая принимает объект User и возвращает True, если пользователь успешно прошёл проверку. Следует отметить, что user_passes_test не производит автоматически проверку авторизации пользователя, вам следует сделать это самостоятельно. В этом примере мы показали второй необязательный аргумент login_url, который позволяет указать URL для страницы аутентификации (по умолчанию, /accounts/login/).
Так как задача проверки прав пользователя является общей,
Django предоставляет сокращение и для этого случая: декоратор
from django.contrib.auth.decorators import permission_required
@permission_required('polls.can_vote', login_url="/login/")
def vote(request):
# ...
Следует отметить, что
Ограничение доступа к базовым представлениямОдним из самых популярных вопросов по Django является ограничение доступа к функциям представления. Для реализации такого ограничения вам потребуется написать промежуточный слой для представления и привязать слой к URL, чтобы вся работа шла через него: from django.contrib.auth.decorators import login_required
from django.views.generic.date_based import object_detail
@login_required
def limited_object_detail(*args, **kwargs):
return object_detail(*args, **kwargs)
Естественно, вы можете заменить login_required на любой другой декоратор.
Самым простым способом управления системой аутентификации является интерфейс администратора. В главе «Интерфейс администратора Django» рассматривалось как управлять пользователями, их правами и доступом, большую часть времени для этого использовался интерфейс администратора. Тем не менее, существуют API, которые могут предоставить вам абсолютный контроль над пользователями. Мы рассмотрим их далее.
Создать пользователя можно с помощью функции
>>> from django.contrib.auth.models import User >>> user = User.objects.create_user(username='john', ... email='jlennon@beatles.com', ... password='glass onion')
В данном случае user является экземпляром
класса >>> user.is_staff = True >>> user.save()
Изменить пароль пользователя можно с помощью функции
>>> user = User.objects.get(username='john')
>>> user.set_password('goo goo goo joob')
>>> user.save()
Не устанавливайте атрибут password напрямую, если не знаете, что делаете. Пароль хранится в виде подсоленного хэша FIXME (т.е. хэш с префиксом) и следовательно его просто так не изменить.
Атрибут password объекта
hashtype$salt$hash
Здесь представлены тип хэша, соль и сам хэш, разделённые символами доллара. Тип хэша (hashtype) может быть либо sha1 (по умолчанию), либо md5 и определяет односторонний алгоритм, который используется для создания хэша для пароля. Соль (salt) является случайной строкой, используемой для подсаливания пароля при создании хэша, например: sha1$a1976$a36cc8cbf81742a8fb52e221aaeab48ed7f58ab4
Функции Неужели «подсоленный хэш» имеет отношение к наркоте?Нет, подсоленный хэш не имеет ничего общего с марихуаной. На самом деле это общий метод безопасного хранения паролей. Хэш — это односторонняя криптографическая функция. Такую функцию просто вычислить, но практически невозможно получить обратно из хэша оригинальное значение. Если бы мы хранили пароли в чистом виде, т.е. как текст, то любой, получивший доступ к базе паролей, мог бы их прочитать. Хранение паролей в виде хэша затрудняет получение паролей из украденной базы данных. Однако, атакующий может применить к базе паролей методику перебора паролей, организовав хэширование миллионов паролей и сравнивая их со значениями, хранящимися в базе. Это займёт некоторое время, но гораздо меньшее, чем вы можете подумать — компьютеры сейчас невероятно мощны. Хуже того, в свободном доступе можно найти радужные таблицы, т.е. базы данных заранее просчитанных хэшей для миллионов паролей. Используя такие таблицы атакующий может проверять большое количество паролей в секунду. С помощью добавления соли, некоторого случайного значения, к хэшу мы увеличиваем сложность процесса подбора паролей. Так как соль отличается от пароля к паролю, это делает невозможным использование радужных таблиц и отбрасывает атакующего обратно к обычному методу подбора пароля. Несмотря на то, что подсоленные хэши не являются абсолютно безопасным методом хранения паролей, всё-таки это приемлемая середина между безопасностью и удобством.
Мы можем использовать эти низкоуровневые инструменты для создания представлений, которые позволяют пользователям регистрироваться на сайте. Почти каждый разработчик желает реализовать процедуру регистрации по своему, по этой причине Django оставляет эту часть работы для вас. К счастью, эта работа не сложна. Для простейшего случая мы можем создать небольшое представление которое запрашивает необходимую информацию у пользователя и создаёт этого пользователя. Django предоставляет встроенную форму, которую вы можете использовать для этой задачи, как это сделано в нижеприведённом примере: from django import oldforms as forms
from django.http import HttpResponseRedirect
from django.shortcuts import render_to_response
from django.contrib.auth.forms import UserCreationForm
def register(request):
form = UserCreationForm()
if request.method == 'POST':
data = request.POST.copy()
errors = form.get_validation_errors(data)
if not errors:
new_user = form.save(data)
return HttpResponseRedirect("/books/")
else:
data, errors = {}, {}
return render_to_response("registration/register.html", {
'form' : forms.FormWrapper(form, data, errors)
})
Эта форма использует шаблон
{% extends "base.html" %}
{% block title %}Регистрация пользователя{% endblock %}
{% block content %}
<h1>Регистрация пользователя</h1>
<form action="." method="post">
{% if form.error_dict %}
<p class="error">Пожалуйста исправьте нижеприведённые ошибки.</p>
{% endif %}
{% if form.username.errors %}
{{ form.username.html_error_list }}
{% endif %}
<label for="id_username">Логин:</label> {{ form.username }}
{% if form.password1.errors %}
{{ form.password1.html_error_list }}
{% endif %}
<label for="id_password1">Пароль:</label> {{ form.password1 }}
{% if form.password2.errors %}
{{ form.password2.html_error_list }}
{% endif %}
<label for="id_password2">Пароль (снова):</label> {{ form.password2 }}
<input type="submit" value="Зарегистрировать" />
</form>
{% endblock %}
ЗамечаниеНа время публикации этой книги класс django.contrib.auth.forms.UserCreationForm являлся устаревшим. Обратитесь к документации на http://www.djangoproject.com/documentation/0.96/forms/ для подробностей. Процесс миграции на новую версию форм, который описан в главе «Формы», будет завершён в ближайшем будущем.
После авторизации пользователя вся информация о нём и о его правах становится доступной в контексте шаблона при использовании RequestContext (см. главу «Расширения для шаблонной системы»). ЗамечаниеЭти переменные становятся доступными в контексте шаблона только в том случае, если вы используете RequestContext и ваш параметр TEMPLATE_CONTEXT_PROCESSORS содержит значение django.core.context_processors.auth (по умолчанию так и есть). И снова, см. подробности в главе «Расширения для шаблонной системы».
При использовании RequestContext текущий
пользователь (либо экземпляр {% if user.is_authenticated %}
<p>Добро пожаловать, {{ user.username }}. Спасибо, что не забываете нас.</p>
{% else %}
<p>Добро пожаловать, незнакомец. Кто вы?</p>
{% endif %}
Права текущего пользователя хранятся в переменной шаблона {{ perms }}. Технически это не просто переменная, а промежуточный слой между рядом методов проверки прав, описанных ранее. Существует два способа использования объекта perm. Вы можете использовать, что-то подобное {{ perms.polls }} для проверки того, имеет ли пользователь вообще права для конкретного приложения. Также вы можете использовать что-то подобное {{ perms.polls.can_vote }} для проверки, имеет ли пользователь конкретное право. Следовательно, вы можете проверять права в шаблоне с помощью оператора {% if %}: {% if perms.polls %}
<p>У вас есть права на работу с приложением голосования.</p>
{% if perms.polls.can_vote %}
<p>Вы можете голосовать!</p>
{% endif %}
{% else %}
<p>У вас нет прав на использование приложения.</p>
{% endif %}
|
Увидели ошибку?
Выделите её мышкой и нажмите
-
Обработано:
1049
49
130
71
Версия книги
1.0
2.0
Версия 2.0 в процессе перевода!
Мой луч
Многообразие света
Полезное
Актуальные вакансии,
Python работа
для python-разработчиков.
Скачать в формате
CHM от 2 сентябряЗаказать PDF файл можно через почту, чат, джаббер. Всего 2WMZ. Содержимое точно соответствует содержимому сайта. Чем чаще заказываете — тем больше перевожу. Русская группа
Ускорить процесс перевода!
R130494980980
Z425285133788 E112528079659 U327380922061 Книга помогла реализовать:
|
| © 2008-2009 Ruslan Popov @ gmail.com | Powered by Django 1.1 beta 1 SVN-11114 |