Customizing authentication in Django在Django中自定义身份验证
Django附带的身份验证对于大多数常见的情况来说都是足够好的,但您可能无法通过开箱即用的默认值来满足要求。要为您的项目需求定制身份验证,需要了解提供的系统的哪些点是可扩展的或可替换的。本文档提供了有关如何自定义验证系统的详细信息。
认证后端提供可扩展的系统,用于当与用户模型存储的用户名和密码需要针对不同于Django默认的服务进行身份验证时。
您可以通过Django的授权系统为您的模型提供可以检查的自定义权限。
您可以扩展默认的用户模型,或者替换完全定制的模型。
Specifying authentication backends指定身份验证后端
在幕后,Django维护了一个“身份验证后端”列表,它检查身份验证。当有人调用django.contrib.auth.authenticate()
- 如“如何记录用户”中所述 - Django尝试在所有身份验证后端进行身份验证。如果第一个身份验证方法失败,Django将尝试第二个身份验证方法,等等,直到尝试所有后端。
在AUTHENTICATION_BACKENDS
设置中指定要使用的身份验证后端列表。这应该是指向Python类的Python路径名的列表,它们知道如何进行身份验证。这些类可以在Python路径上的任何地方。
默认情况下,AUTHENTICATION_BACKENDS
设置为:
['django.contrib.auth.backends.ModelBackend']
这是检查Django用户数据库并查询内置权限的基本身份验证后端。它不通过任何速率限制机制提供防止暴力攻击的保护。您可以在自定义验证后端实现自己的速率限制机制,也可以使用大多数Web服务器提供的机制。
AUTHENTICATION_BACKENDS
的顺序很重要,因此如果相同的用户名和密码在多个后端有效,Django将在第一次正面匹配时停止处理。
如果后端引发了PermissionDenied
异常,则身份验证将立即失败。 Django不会检查后面的后端。
注意
一旦用户进行身份验证,Django就会存储用户在会话中使用后台进行身份验证的用户,并且在需要访问当前身份验证的用户时,会在该会话期间重新使用相同的后端。这实际上意味着身份验证源是以每个会话的方式进行缓存的,所以如果您更改
AUTHENTICATION_BACKENDS
,则需要清除会话数据,如果需要强制用户使用不同的方法进行重新身份验证。一个简单的方法是简单地执行Session.objects.all().delete().
Writing an authentication backend编写身份验证后端
身份验证后端是一个实现两个必需方法的类:get_user(user_id)
和authenticate
(**凭证),以及一组可选的权限相关的授权方法。
get_user
方法接受一个user_id
,可以是一个用户名,数据库ID,或者是用户对象的主键,并返回一个用户对象。
authenticate
方法将凭据作为关键字参数。 大多数时候,它会像这样:
class MyBackend(object):
def authenticate(self, username=None, password=None):
# Check the username/password and return a user.
...
But it could also authenticate a token, like so:
class MyBackend(object):
def authenticate(self, token=None):
# Check the token and return a user.
...
无论哪种方式,authenticate()
都应该检查它获得的凭据,如果凭据有效,返回与这些凭据匹配的用户对象。 如果它们无效,它应该返回None
。
Django管理员
紧密耦合到Django User对象
。 处理此问题的最佳方法是为每个后端用户创建一个Django User对象
(例如,在您的LDAP目录,外部SQL数据库等中)。您可以提前编写一个脚本, 或者您的身份验证方法可以在用户首次登录时执行此操作。
这是一个示例后端,用于针对您的settings.py
文件中定义的用户名和密码变量进行身份验证,并在用户首次认证时创建Django User对象
:
from django.conf import settings
from django.contrib.auth.hashers import check_password
from django.contrib.auth.models import User
class SettingsBackend(object):
"""
Authenticate against the settings ADMIN_LOGIN and ADMIN_PASSWORD.
Use the login name and a hash of the password. For example:
ADMIN_LOGIN = 'admin'
ADMIN_PASSWORD = 'pbkdf2_sha256$30000$Vo0VlMnkR4Bk$qEvtdyZRWTcOsCnI/oQ7fVOu1XAURIZYoOZ3iq8Dr4M='
"""
def authenticate(self, username=None, password=None):
login_valid = (settings.ADMIN_LOGIN == username)
pwd_valid = check_password(password, settings.ADMIN_PASSWORD)
if login_valid and pwd_valid:
try:
user = User.objects.get(username=username)
except User.DoesNotExist:
# Create a new user. There's no need to set a password
# because only the password from settings.py is checked.
user = User(username=username)
user.is_staff = True
user.is_superuser = True
user.save()
return user
return None
def get_user(self, user_id):
try:
return User.objects.get(pk=user_id)
except User.DoesNotExist:
return None