django用户认证

django默认提供用户认证系统,它提供用户账号权限cookie用户session等功能,此文档解释了django如何实现这些功能,此外也介绍如何在项目中自定义用户认证系统 extend and customize

概述

django处理用户验证和授权.简而言之,身份验证如何证明我是我,授权是用户有什么权限。

认证系统包括:

  • 用户
  • 权限: (yes/no)标志,指定用户是否可通过检查,可以执行某些操作
  • 组: 组和app关联,用户添加到组中,交集判断用户是否有权限
  • 密码加密系统(hashing)
  • Forms view logging user 用户表单,视图,限制返回内容等
  • 可插拔后台系统

django认证系统是通用系统,不提供web认证系统一些特点,已有第三app已实现

  • Password strength checking 密码强度检查
  • Throttling of login attempts 登录尝试
  • Authentication against third-parties (OAuth, for example) 第三方认证系统

安装

启用用户权限功能需要在以下安装组件提供相对应的功能django.contrib.auth,默认以安装django-admin startproject启动的时候,已将这些功能安装在INSTALLED_APPS设定中

Usage

django默认已经实现

API reference for the default implementation

Customizing Users and authentication

Password management in Django

Using the Django authentication system

本文档适用于配置了django默认的认证系统,适用于很多常见的用户验证项目,权限和密码权限等需求。亦可进行自行扩展 extension and customization认证系统.

django提供了认证和授权,一般称为认证系统,功能有些耦合

User objects

User用户对象时身份验证系统的核心。 用户有自身的基本属性(个人详情信息),通过这些属性信息集合django认证的框架,以达到管理普通用户不同类的对象

主要有以下属性:

See the full API documentation for full reference, the documentation that follows is more task oriented.

Creating users

The most direct way to create users is to use the included create_user() helper function 直接创建用户的函数:

>>> 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()

另一种创建用户的方法。If you have the Django admin installed, you can also create users interactively.

Creating superusers

创建管理员命令 createsuperuser :

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

输入以上命令后 --username or --email 会有输入密码的请求.

Changing passwords

Django不是以明文存储密码 (clear text)在user model中, 而是hash (see documentation of how passwords are managed因此,不要试图直接操纵用户的密码属性。这就是创建用户时使用辅助函数的原因.

要更改用户的密码,您有几个选项:

manage.py changepassword *username* 提供一种从命令行更改用户密码的方法。它提示您更改给定用户的密码,您必须输入两次密码。如果两者都匹配,则新密码将立即更改。如果不提供用户,则命令将尝试更改用户名与当前登录的系统用户相匹配的密码(当前登录到此系统的用户)

另一种修改密码的方式 set_password():

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

如果启用了admin后台也可以修改所有用户的密码authentication system’s admin pages.

Django也提供 views and forms 修改用户的密码

修改用户密码后期session信息会失效. 详情查看 Session invalidation on password change .

Authenticating users

  • authenticate(request=None, *\credentials*)[source]

    使用authenticate() 作为验证凭证. 将, usernamepassword 以关键字传入函数进行验证, 后台会进行检查 authentication backend, 返回一个 User 对象如果通过检查. 如果验证不通过则抛出异常 PermissionDenied, 返回值为 None. For example:

from django.contrib.auth import authenticate
user = authenticate(username='john', password='secret')
if user is not None:
# A backend authenticated the credentials
else:
# No backend authenticated the credentials

request是一个HttpRequest 生成的对象, 这是通过 authenticate() 后端方法认证

Changed in Django 1.11:

The optional request argument was added.

Permissions and Authorization

Django有一个简单的权限系统。它提供了一种将权限分配给特定用户和用户组的方法。

它是由Django管理后台站点中使用,你也可以用于自己的代码中。

Django管理后台站点使用权限如下:

  • 总的来说有三个权限add, change,delete
  • Access to view the “add” form and add an object is limited to users with the “add” permission for that type of object.
  • Access to view the change list, view the “change” form and change an object is limited to users with the “change” permission for that type of object.
  • Access to delete an object is limited to users with the “delete” permission for that type of object.

权限不仅可以设置每个对象类型,而且可以设置每个特定对象实例。通过使用has_add_permission(), has_change_permission() and has_delete_permission() 所提供的方法 ModelAdmin 类, 可以为同一类型的不同对象实例定制权限。

User 对象有两个多对多字段: groupsuser_permissions. User 对象可以以与其他方法相同的方式访问它们的相关对象 Django model:

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

Default permissions

django.contrib.auth设定于 INSTALLED_APPS setting中, 它将会三个默认权限 – add, change and delete– 是在你安装的应用程序定义的每个Django模型默认创建.

这些权限将在运行时创建 manage.py migrate; 第一次运行 migrate 在加入django.contrib.authINSTALLED_APPS, 将为所有以前安装的模型创建默认权限,以及当时安装的任何新model. 然后, 每次运行时,它将为新模型创建默认权限 manage.py migrate (创建权限的函数连接到post_migrate 信号).

假设您有一个带有 app_label foo 和model名为 Bar, 要测试基本权限,您应该使用:

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

The Permission 很少直接访问模型

Groups

django.contrib.auth.models.Group models是对用户进行分类的通用方法,因此您可以应用权限, 或其他标签,哪些用户. 一个用户可以属于一个或多个组.

组中的用户自动拥有授予该组的权限. For example, 如果组 Site editors 有权限 can_edit_home_page, 该组中的任何用户都将获得该权限.

Beyond permissions, 组是一种方便的方法来分类用户给他们一些标签, 或扩展功能
. For example, 你可以创建一个组 'Special users', and you could write code that could, say, give them access to a members-only portion of your site, or send them members-only email messages (组内成员操作).

Programmatically creating permissions

custom permissions 可以在模型中定义 Meta 类, 您还可以直接创建权限. For example, you can create the can_publish permission for a BlogPost model in myapp:

from myapp.models import BlogPost
from django.contrib.auth.models import 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,
)

然后可以将权限分配给 User 通过其 user_permissions 属性或 Group 通过其 permissions属性.

Permission caching

The ModelBackend 在第一次为权限检查获取用户对象时,对其进行缓存. 对于请求响应周期来说,这通常是很好的,因为在添加权限后,通常不会立即检查权限(例如,在admin后台中)。如果您正在添加权限并立即检查它们, 例如,在测试或视图中, 最简单的解决方案是从数据库中重新获取用户. For example:

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

from myapp.models import BlogPost

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_blogpost')

content_type = ContentType.objects.get_for_model(BlogPost)
permission = Permission.objects.get(
codename='change_blogpost',
content_type=content_type,
)
user.user_permissions.add(permission)

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

# Request new instance of User
# Be aware that user.refresh_from_db() won't clear the cache.
user = get_object_or_404(User, pk=user_id)

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

...

Authentication in Web requests

Django 使用sessions 中间件将认证系统接入 request objects.

这提供一个 request.user表示当前用户的每个请求的属性.如果当前用户没有登录,则该属性将被设置为AnonymousUser, otherwise it will be an instance of User.

你可以把它们区分开来 is_authenticated, 像这样:

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

How to log a user in

如果您有一个经过身份验证的用户要附加到当前会话-这是用 login() 函数.

从视图中记录一个用户已登录, 使用 login(). 它需要一个 HttpRequest 对象和一个 User 对象. login() 将用户ID保存在会话中, using Django’s session framework.注意,匿名会话中的任何数据集都保留在用户登录后的会话中.这个示例演示了如何使用这两种方法authenticate()login():

from django.contrib.auth import authenticate, login

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

Changed in Django 1.10:

在旧版本中,当您手动记录用户时,您必须*成功地验证用户
authenticate()在调用前 login(). 现在您可以使用新的后端设置 backend 参数.

Selecting the authentication backend

当用户登录时,用户ID和用于身份验证的后端保存在用户会话中。这允许相同的authentication backend 在将来的请求中获取用户的详细信息. 在会话中保存的身份验证后端选择如下:

  1. 使用可选项 backend 参数, 如果已设定.
  2. Use the value of the user.backend attribute, 这是目前. 这允许配对authenticate()login():authenticate() 集the user.backend attribute on the user object it returns.
  3. Use the backend in AUTHENTICATION_BACKENDS, if there is only one.
  4. Otherwise, raise an exception.

In cases 1 and 2, the value of the backend argument or the user.backend attribute should be a dotted import path string (like that found in AUTHENTICATION_BACKENDS), not the actual backend class.

How to log a user out

from django.contrib.auth import logout

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

Note that logout() 如果用户没有登录不会抛出任何的异常.

当你调用 logout(), 当前请求的会话数据已完全清除。所有现有数据都已删除. 这是为了防止另一个人使用同一个Web浏览器登录并访问以前用户的会话数据. 如果您希望在登录后立即向用户可用的会话中放入任何内容, do that after calling django.contrib.auth.logout().

Limiting access to logged-in users

The raw way

限制页面访问的简单、原始方法是检查 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))
# ...

…or display an error message:

from django.shortcuts import render

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