django 认证系统 使用Django认证系统

扩展和自定义认证。

Django的认证同时提供认证和授权,并通常统一称为认证系统,因为这些功能某些地方是耦合的。


'staff'用户只是具有特殊属性集的user对象,而不是不同类型的user对象。

默认user的基本属性有:

文档,以下的内容更偏重特定的任务。


create_user()辅助函数:

>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user('john', 'lennon@thebeatles.com', 'johnpassword')

# At this point, user is a User object that has already been saved
# to the database. You can continue to change its attributes
# if you want to change other fields.
>>> user.last_name = 'Lennon'
>>> user.save()

交互式地创建users.


createsuperuser命令创建superusers:

$ python manage.py createsuperuser --username=joe --email=joe@example.com

--email选项,将会提示你输入这些值。


这也是为什么创建一个user时要使用辅助函数。

若要修改一个用户的密码,你有几种选择:

如果你没有提供user,命令行将尝试修改与当前系统用户匹配的用户名的密码。

set_password()

>>> from django.contrib.auth.models import User
>>> u = User.objects.get(username='john')
>>> u.set_password('new password')
>>> u.save()

认证系统的admin页面修改user的密码。

forms用于允许user修改他们自己密码。

New in Django 1.7.

密码修改后会话失效


authenticate(**credentials)[source]

例子:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
    # the password verified for the user
    if user.is_active:
        print("User is valid, active and authenticated")
    else:
        print("The password is valid, but the account has been disabled!")
else:
    # the authentication system was unable to verify the username and password
    print("The username and password were incorrect.")

注意:

login_required()装饰器。


它提供一种分配权限给特定的用户和用户组的方法。

它被Django的admin站点使用,但欢迎你在你自己的代码中使用。

Django admin 站点使用如下的权限:

  • 查看修改列表、查看“change”表单以及修改一个对象的权利只限于具有该类型对象的“change”权限的用户拥有。
  • 用户必须在一个对象上具有“delete”权限,才能删除这个对象。

has_delete_permission()方法,可以针对相同类型的不同对象实例自定义权限。

Django 模型一样的方式访问它们相关的对象:

myuser.groups = [group_list]
myuser.groups.add(group, group, ...)
myuser.groups.remove(group, group, ...)
myuser.groups.clear()
myuser.user_permissions = [permission_list]
myuser.user_permissions.add(permission, permission, ...)
myuser.user_permissions.remove(permission, permission, ...)
myuser.user_permissions.clear()

INSTALLED_APPS设置中列出时,它将确保为你安装的应用中的每个Django模型创建3个默认的权限 – add、change和delete。

migrate时,它都将为新的模型创建默认的权限。

Bar的模型,要测试基本的权限,你应该使用:

  • add: user.has_perm('foo.add_bar')
  • change: user.has_perm('foo.change_bar')
  • delete: user.has_perm('foo.delete_bar')

Permission模型。


一个用户可以属于任意多个组。

can_edit_home_page,那么该组中的任何用户都具有该权限。

users',然后你可以这样写代码,给他们访问你的站点仅限会员的部分,或者给他们发仅限于会员的邮件。


can_publish权限:

from myapp.models import BlogPost
from django.contrib.auth.models import Group, Permission
from django.contrib.contenttypes.models import ContentType

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.create(codename='can_publish',
                                       name='Can Publish Posts',
                                       content_type=content_type)

Group


例如:

from django.contrib.auth.models import Permission, User
from django.shortcuts import get_object_or_404

def user_gains_perms(request, user_id):
    user = get_object_or_404(User, pk=user_id)
    # any permission check will cache the current set of permissions
    user.has_perm('myapp.change_bar')

    permission = Permission.objects.get(codename='change_bar')
    user.user_permissions.add(permission)

    # Checking the cached permission set
    user.has_perm('myapp.change_bar')  # False

    # Request new instance of User
    user = get_object_or_404(User, pk=user_id)

    # Permission cache is repopulated from the database
    user.has_perm('myapp.change_bar')  # True

    ...


对象到认证系统中。

User的实例。

is_authenticated()区分它们,像这样:

if request.user.is_authenticated():
    # Do something for authenticated users.
    ...
else:
    # Do something for anonymous users.
    ...


login()函数完成。

login()[source]

login()使用Django的session框架来将用户的ID保存在session中。

注意任何在匿名会话中设置的数据都会在用户登入后的会话中都会记住。

login()

from django.contrib.auth import authenticate, login

def my_view(request):
    username = request.POST['username']
    password = request.POST['password']
    user = authenticate(username=username, password=password)
    if user is not None:
        if user.is_active:
            login(request, user)
            # Redirect to a success page.
        else:
            # Return a 'disabled account' error message
            ...
    else:
        # Return an 'invalid login' error message.
        ...

authenticate()

如果你试图登入一个直接从数据库中取出的用户,将会抛出一个错误。


logout()[source]

例如:

from django.contrib.auth import logout

def logout_view(request):
    logout(request)
    # Redirect to a success page.

logout()也不会抛出任何错误。

django.contrib.auth.logout()之后放入。



request.user.is_authenticated()并重定向到一个登陆页面:

from django.conf import settings
from django.shortcuts import redirect

def my_view(request):
    if not request.user.is_authenticated():
        return redirect('%s?next=%s' % (settings.LOGIN_URL, request.path))
    # ...

...或者显示一个错误信息:

from django.shortcuts import render

def my_view(request):
    if not request.user.is_authenticated():
        return render(request, 'myapp/login_error.html')
    # ...


login_required([redirect_field_name=REDIRECT_FIELD_NAME, login_url=None])[source]

login_required()装饰器:

from django.contrib.auth.decorators import login_required

@login_required
def my_view(request):
    ...

login_required()完成下面的事情:

  • /accounts/login/?next=/polls/3/
  • 视图的代码可以安全地假设用户已经登入。

redirect_field_name参数:

from django.contrib.auth.decorators import login_required

@login_required(redirect_field_name='my_redirect_field')
def my_view(request):
    ...

例如:

from django.contrib.auth.decorators import login_required

@login_required(login_url='/accounts/login/')
def my_view(request):
    ...

例如,使用默认值,可以添加下面几行到你的URLconf中:

from django.contrib.auth import views as auth_views

url(r'^accounts/login/$', auth_views.login),

这允许你*地重新映射你的URLconf中的登录视图而不用更新设置。

login_required装饰器不检查user的is_active标志位。


基于特定的权限和其他方式来限制访问,你最好按照前面描述的那样操作。

例如,视图检查用户的邮件属于特定的地址(例如@example.com),若不是,则重定向到登录页面。

from django.shortcuts import redirect

def my_view(request):
    if not request.user.email.endswith('@example.com'):
        return redirect('/login/?next=%s' % request.path)
    # ...
user_passes_test(func[, login_url=None, redirect_field_name=REDIRECT_FIELD_NAME])[source]

False 时会执行一个重定向操作:

from django.contrib.auth.decorators import user_passes_test

def email_check(user):
    return user.email.endswith('@example.com')

@user_passes_test(email_check)
def my_view(request):
    ...

User 是否为匿名对象。

user_passes_test()接收两个额外的参数:

login_url
settings.LOGIN_URL
redirect_field_name
None 来把它从 URL 中移除,当你想把通不过检查的用户重定向到没有next page 的非登录页面时。

例如:

@user_passes_test(email_check, login_url='/login/')
def my_view(request):
    ...


permission_required(perm[, login_url=None, raise_exception=False])[source]

permission_required() 装饰器:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote')
def my_view(request):
    ...

polls 应用下一个模块的权限。

例如:

from django.contrib.auth.decorators import permission_required

@permission_required('polls.can_vote', login_url='/loginpage/')
def my_view(request):
    ...

LOGIN_URL。

the 403 (HTTP Forbidden) 视图而不是重定向到登录页面。

Changed in Django 1.7:

permission_required()装饰器既可以接收一个权限序列也可以接收一个单个的权限。

编写一个封装as_view()的mixin


New in Django 1.7.

警告

startproject生成,它会被包含进来。

SessionAuthenticationMiddleware的模板生成的项目,考虑在阅读下面的升级说明之后开启它。

这允许用户通过修改密码来登出所有的会话。

如果你拥有自定义的密码修改视图,并且希望具有相似的行为,使用这个函数:

update_session_auth_hash(request, user)

使用示例:

from django.contrib.auth import update_session_auth_hash

def password_change(request):
    if request.method == 'POST':
        form = PasswordChangeForm(user=request.user, data=request.POST)
        if form.is_valid():
            form.save()
            update_session_auth_hash(request, form.user)
    else:
        ...

SessionAuthenticationMiddleware开始运行你的站点,任何没有登录并且会话使用验证哈希值升级过的用户的现有会话都会失效,并且需要重新登录。

注意

SECRET_KEY,使用新的私钥升级你的站点会使所有现有会话失效。


内建的认证表单,但你也可以传递你自己的表单。

所有的认证视图.


django.contrib.auth.urls 中提供的URLconf到你自己的URLconf中,例如

urlpatterns = [
    url('^', include('django.contrib.auth.urls'))
]

这将包含进下面的URL模式:

^login/$ [name='login']
^logout/$ [name='logout']
^password_change/$ [name='password_change']
^password_change/done/$ [name='password_change_done']
^password_reset/$ [name='password_reset']
^password_reset/done/$ [name='password_reset_done']
^reset/(?P<uidb64>[0-9A-Za-z_-]+)/(?P<token>[0-9A-Za-z]{1,13}-[0-9A-Za-z]{1,20})/$ [name='password_reset_confirm']
^reset/done/$ [name='password_reset_complete']

URL文档

如果你想更多地控制你的URL,你可以在你的URLconf中引用一个特定的视图:

urlpatterns = [
    url('^change-password/', 'django.contrib.auth.views.password_change')
]

例如:

urlpatterns = [
    url(
        '^change-password/',
        'django.contrib.auth.views.password_change',
        {'template_name': 'change-password.html'}
    )
]

一种方法是在你自己的视图中封装一个视图:

from django.contrib.auth import views

def change_password(request):
    template_response = views.password_change(request)
    # Do something with `template_response`
    return template_response

TemplateResponse文档


使用视图

login(request[, template_name, redirect_field_name, authentication_form, current_app, extra_context])[source]

login

URL 文档

可选的参数:

  • template_name: registration/login.html
  • redirect_field_name: next
  • authentication_form: AuthenticationForm。
  • current_app: 命名URL的解析策略。
  • extra_context: 一个上下文数据的字典,将被添加到传递给模板的默认上下文数据中。

django.contrib.auth.views.login所做的事情:

  • 后面有更多这方面的信息。
  • 如果登入不成功,则重新显示登录表单。

模板会得到4个模板上下文变量:

  • form: Form对象。
  • next: 它还可能包含一个查询字符串。
  • site: HttpRequest获得site名称和域名。
  • site_name: “sites” 框架

myapp/login.html

url(r'^accounts/login/$', auth_views.login, {'template_name': 'myapp/login.html'}),

next

base.html模板:

{% extends "base.html" %}

{% block content %}

{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}

<form method="post" action="{% url 'django.contrib.auth.views.login' %}">
{% csrf_token %}
<table>
<tr>
    <td>{{ form.username.label_tag }}</td>
    <td>{{ form.username }}</td>
</tr>
<tr>
    <td>{{ form.password.label_tag }}</td>
    <td>{{ form.password }}</td>
</tr>
</table>

<input type="submit" value="login" />
<input type="hidden" name="next" value="{{ next }}" />
</form>

{% endblock %}

get_user方法,此方法返回认证过的用户对象(这个方法永远只在表单验证成功后调用)。

logout(request[, next_page, template_name, redirect_field_name, current_app, extra_context])[source]

登出一个用户。

logout

可选的参数:

  • next_page: 登出之后要重定向的URL。
  • template_name: registration/logged_out.html
  • redirect_field_name: next_page URL。
  • current_app: 命名空间下的URL解析策略 。
  • extra_context: 一个上下文数据的字典,会被添加到向模板传递的默认的上下文数据中。

模板上下文:

  • title: 本地化的字符串“登出”。
  • site: HttpRequest来获取站点名称和域名。
  • site_name: “站点”框架
  • current_app: 命名空间下的URL解析策略 。
  • extra_context: 一个上下文数据的字典,会被添加到向模板传递的默认的上下文数据中。
logout_then_login(request[, login_url, current_app, extra_context])[source]

登出一个用户,然后重定向到登录页面。

没有提供默认的URL

可选的参数:

  • login_url: settings.LOGIN_URL。
  • current_app: 命名空间下的URL解析策略 。
  • extra_context: 一个上下文数据的字典,会被添加到向模板传递的默认的上下文数据中。
password_change(request[, template_name, post_change_redirect, password_change_form, current_app, extra_context])[source]

允许一个用户修改他的密码。

password_change

可选的参数:

  • template_name: registration/password_change_form.html
  • post_change_redirect: 密码修改成功后重定向的URL。
  • password_change_form: PasswordChangeForm。
  • current_app: 命名空间下的URL解析策略 。
  • extra_context: 上下文数据的字典,会添加到传递给模板的默认的上下文数据中。

模板上下文:

  • form: password_change_form)。
password_change_done(request[, template_name, current_app, extra_context])[source]

这个页面在用户修改密码之后显示。

password_change_done

可选参数:

  • template_name: registration/password_change_done.html
  • current_app: 命名空间下的URL解析策略 。
  • extra_context: 上下文数据的字典,会添加到传递给模板的默认的上下文数据中。
password_reset(request[, is_admin_site, template_name, email_template_name, password_reset_form, token_generator, post_reset_redirect, from_email, current_app, extra_context, html_email_template_name])[source]

允许用户通过生成一次性的连接并发送到用户注册的邮箱地址中来重置密码。

password_reset_form 参数。

注意它们不会收到任何错误信息,因为这会暴露它们的账户,也不会发送任何邮件。

password_reset

可选参数:

  • template_name: registration/password_reset_form.html
  • email_template_name: registration/password_reset_email.html
  • subject_template_name: registration/password_reset_subject.txt
  • password_reset_form: PasswordResetForm
  • token_generator: django.contrib.auth.tokens.PasswordResetTokenGenerator 的一个实例。
  • post_reset_redirect: 密码重置请求成功后,将重定向到的URL。
  • from_email: DEFAULT_FROM_EMAIL
  • current_app: namespaced URL resolution strategy
  • extra_context: 将添加到传递给模板的默认上下文数据的上下文数据字典。
  • html_email_template_name: 默认情况下,不发送HTML电子邮件。
New in Django 1.7:

html_email_template_name

is_admin_site参数已被废弃,将在Django2.0中被移除。

模板上下文:

  • form: password_reset_form)。

Email模板上下文:

  • email: user.email的别名
  • user: True)。
  • site_name: The “sites” framework
  • domain: request.get_host()的值。
  • protocol: http或https
  • uid: 用户的主键编码在base 64中。
  • token: 令牌检查重置链接是否有效。

registration/password_reset_email.html样例(邮件正文模板):

Someone asked for password reset for email {{ email }}. Follow the link below:
{{ protocol}}://{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}

主题必须是单行的纯文本字符串。

password_reset_done(request[, template_name, current_app, extra_context])[source]

post_reset_redirectURL,默认会调用这个视图。

password_reset_done

注意

如果提供的email地址在系统中不存在,用户未激活,或者密码不可用,用户仍然会重定向到这个视图,但是不会发送邮件。

可选参数:

  • template_name: registration/password_reset_done.html
  • current_app: 命名空间网址解析策略。
  • extra_context: 将添加到传递给模板的默认上下文数据的上下文数据字典。
password_reset_confirm(request[, uidb64, token, template_name, token_generator, set_password_form, post_reset_redirect, current_app, extra_context])[source]

为输入新密码展示表单。

password_reset_confirm

可选参数:

  • uidb64: None.
  • token: None
  • template_name: registration/password_reset_confirm.html
  • token_generator: django.contrib.auth.tokens.PasswordResetTokenGenerator的一个实例。
  • set_password_form: SetPasswordForm
  • post_reset_redirect: None
  • current_app: 命名空间网址解析策略。
  • extra_context: 将添加到传递给模板的默认上下文数据的上下文数据字典。

模板上下文:

  • form: set_password_form)。
  • validlink: token的组合)有效或未使用,则为True。
password_reset_complete(request[, template_name, current_app, extra_context])[source]

展示一个视图,它通知用户密码修改成功。

password_reset_complete

可选参数:

  • template_name: registration/password_reset_complete.html
  • current_app: 命名空间网址解析策略。
  • extra_context: 将添加到传递给模板的默认上下文数据的上下文数据字典。


redirect_to_login(next[, login_url, redirect_field_name])[source]

重定向到登录页面,然后在登入成功后回到另一个URL。

必需的参数:

  • next: 登陆成功后重定向的URL

可选的参数:

  • login_url: settings.LOGIN_URL。
  • redirect_field_name: next


django.contrib.auth.forms

内建验证表单与自定义用户模型的使用的文档。

class AdminPasswordChangeForm[source]

Admin 站点中使用的表单,用于修改用户密码。

user作为第一个参数。

class AuthenticationForm[source]

用于用户登录的表单。

request 作为第一个参数,它将保存在表单实例中以在子类中使用。

confirm_login_allowed(user)[source]
New in Django 1.7.

ValidationError

例如,若要允许所有用户登录而不管“is_active”状态如何:

from django.contrib.auth.forms import AuthenticationForm

class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
    def confirm_login_allowed(self, user):
        pass

或者只允许某些激活的用户登录:

class PickyAuthenticationForm(AuthenticationForm):
    def confirm_login_allowed(self, user):
        if not user.is_active:
            raise forms.ValidationError(
                _("This account is inactive."),
                code='inactive',
            )
        if user.username.startswith('b'):
            raise forms.ValidationError(
                _("Sorry, accounts starting with 'b' aren't welcome here."),
                code='no_b_users',
            )
class PasswordChangeForm[source]

用于用户修改密码的表单。

class PasswordResetForm[source]

用于生成并邮件发送重置密码的一个一次性链接的表单。

send_email(subject_template_name, email_template_name, context, from_email, to_email[, html_email_template_name=None])
New in Django 1.8.

可以覆盖这个方法,来自定义邮件如何发送给用户。

参数:
  • subject_template_name —— 邮件标题的模板。
  • email_template_name —— 邮件正文的模板。
  • None)。
  • from_email —— 发信人的地址。
  • to_email —— 收件人的地址。
  • None,这种情况下将发送纯文本文件。

password_reset() 向它的邮件上下文传递的变量相同。

class SetPasswordForm[source]

允许用户不输入旧密码修改密码的表单。

class UserChangeForm[source]

Admin 站点中使用的表单,用于修改用户信息和权限。

class UserCreationForm[source]

用于创建新用户的表单。


模板上下文中可以访问。

技术细节

RequestContext 文档


}}中:

{% if user.is_authenticated %}
    <p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
    <p>Welcome, new user. Please log in.</p>
{% endif %}

RequestContext,则不可以访问该模板变量:


的封装,他是一个对于模板友好的权限代理。

True

{{ perms.foo }}

True

{{ perms.foo.can_vote }}

%}语句检查权限:

{% if perms.foo %}
    <p>You have permission to do something in the foo app.</p>
    {% if perms.foo.can_vote %}
        <p>You can vote!</p>
    {% endif %}
    {% if perms.foo.can_drive %}
        <p>You can drive!</p>
    {% endif %}
{% else %}
    <p>You don't have permission to do anything in the foo app.</p>
{% endif %}

例如:

{% if 'foo' in perms %}
    {% if 'foo.can_vote' in perms %}
        <p>In lookup works, too.</p>
    {% endif %}
{% endif %}


admin中还会保存和显示对用户模型编辑的日志。


“Add user” 页面与标准admin页面不同点在于它要求你在编辑用户的其它字段之前先选择一个用户名和密码。

所以Django同时要求添加权限修改权限作为一种轻量的安全措施。

如果你赋予了一个非超级用户编辑用户的能力,这和给他们超级用户的权限在最终效果上是一样的,因为他们将能够提升他们自己下面的用户的权限。


这个信息的显示中包含一条指向修改密码表单的链接,允许管理员修改用户的密码。