Thewebframeworkforperfectionistswithdeadlines.
Django自带的身份验证已经足够满足大多数常见的情况,但你可能有一些需求没有被开箱即用的默认值所满足。在你的项目中定制身份验证需要了解所提供系统的哪些点是可扩展或可替换的。本文档详细介绍了如何定制认证系统。
有时候你需要连接到其他认证源——一个包含用户名及密码的源或者认证方法。
例如,你的公司可能已经有了一个LDAP配置,为每个员工存储了一个用户名和密码。如果用户在LDAP和基于Django的应用程序中分别有不同的账户,那么对于网络管理员和用户本身来说都是一件很麻烦的事情。
所以,为了处理这样的情况,Django认证系统让你可以插入其他认证源。你可以覆盖Django默认的基于数据库的方案,也可以将默认系统与其他系统串联使用。
注解
get_user方法接收一个user_id——可以是用户名、数据库ID或其他什么,但必须是用户对象的主键——然后返回一个用户对象或None。
authenticate方法采用request参数和证书作为关键字参数。大多数情况下,它看起来像这样:
fromdjango.contrib.auth.backendsimportBaseBackendclassMyBackend(BaseBackend):defauthenticate(self,request,username=None,password=None):#Checktheusername/passwordandreturnauser....但它也可以认证一个令牌,比如:
fromdjango.contrib.auth.backendsimportBaseBackendclassMyBackend(BaseBackend):defauthenticate(self,request,token=None):#Checkthetokenandreturnauser....无论哪种方式,authenticate()应该检查它所得到的凭证,如果凭证有效,则返回一个与这些凭证相匹配的用户对象。如果无效,则应返回None。
下面是一个后端实例,它可以根据settings.py文件中定义的用户名和密码变量进行验证,并在用户第一次验证时创建一个DjangoUser对象:
用户所拥有的权限将是所有验证后端返回的所有权限的一个超集。也就是说,如果任何后端之一将一个权限赋予了用户,那么Django最终也将该权限赋予这个用户。
后端可以像这样为管理员实现权限:
权限系统中对匿名用户的支持,可以实现匿名用户有权限做某事,而非激活的认证用户没有权限的场景。
不要忘记在自己的后端权限方法中测试用户的is_active属性。
这个Task模型创建了两个自定义权限,即用户可以或不可以对Task实例进行的操作,具体到你的应用程序:
如果你准备启动一个新的项目,强烈推荐你设置一个自定义的用户模型,即使默认的用户模型对你来说已经足够了。这个模型的行为与默认用户模型相通,但是你能在未来需要的时候自定义它:
同样的,在app中的admin.py中注册模型。
此外,当你运行迁移时,你可能会遇到一个CircularDependencyError,因为Django不会因为动态依赖而自动打破依赖循环。如果你看到这个错误,你应该通过将你的用户模型所依赖的模型移动到第二个迁移中来打破这个循环。(如果你想看看通常是怎么做的,你可以尝试做两个正常的模型,它们之间有一个ForeignKey,看看makemigrations是如何解决这个循环依赖的。)
如果你使用默认的认证后端,那么你的模型必须有一个可用于识别目的的唯一字段。这可以是一个用户名,一个电子邮件地址,或任何其他独特的属性。如果你使用可以支持的自定义认证后端,则允许使用非唯一的用户名字段。
描述用户模型上用作唯一标识符的字段名称的字符串。这通常是某种用户名,但也可以是电子邮件地址,或任何其他独特的标识符。该字段必须是唯一的(即在其定义中设置了unique=True),除非你使用的自定义认证后端可以支持非唯一的用户名。
接下来的样例中,identifier字段将被用作识别字段:
例如,这里是一个用户模型的部分定义,它定义了两个必填字段——出生日期和身高:
REQUIRED_FIELDS必须包含用户模型上的所有必填字段,但不应包含USERNAME_FIELD或password,因为这些字段总是会被提示。
导入AbstractBaseUser
返回USERNAME_FIELD指定的字段的值。
应用NFKCUnicode规范化用户名,使得不同Unicode码位视觉相同字符视为相同。
如果给定的原始字符串是用户的正确密码,返回True。(在进行比较时,这将处理密码散列。)
如果你的应用程序的身份验证是针对现有的外部源(如LDAP目录)进行的,你可能需要这个功能。
返回密码字段的HMAC。用于session-invalidation-onpassword-change。
哈希算法已更改为SHA-256。
create_user()的原型应该接受username字段,加上其他所有必须的字段作为参数。举例,如果你的用户模型使用email作为用户名字段,date_of_birth字段作为必填字段,那么create_user应该如下定义:
通过降低电子邮件地址的域部分来规范化电子邮件地址。
使用USERNAME_FIELD指定的字段的内容检索用户实例。
返回具有给定长度和给定字符串的随机密码。请注意,allowed_chars的默认值不包含可能导致用户混淆的字母,包括:
以下表单对用户模型进行了假设,如果满足这些假设,则可以按原样使用:
如果自定义的用户模型是AbstractUser的子类,则可以使用下面的方式来扩展表单:
如果允许用户有访问admin页面就返回True。
返回``True``,如果该用户的账号当前是激活状态
如果用户有指定的权限,则返回True。如果提供了参数obj,则需要对指定的对象实例进行权限检查。
如果用户有权限访问指定app里的模型,那么返回True。
如果正在使用自定义的ModelAdmin是django.contrib.auth.admin.UserAdmin的子类,那么你需要添加自定义字段到fieldsets(用于在编辑用户中使用)和add_fieldsets(用于在创建用户时使用)。比如
布尔值。指定该用户拥有所有权限,而不用一个个开启权限。
返回用户本身就自带的权限字符串集合。
如果传入了obj,则只返回指定对象的用户权限。
返回用户拥有权限的字符串集合,从用户所属组的权限中获取。
如果传入obj参数,则只返回指定对象所属组的权限。
返回用户拥有权限的字符串集合,同时从用户所属组及用户本身的权限中获取。
如果传入obj参数,则这个方法不会检查该模型权限,而只会检查这个出传入对象的权限。
如果传入参数obj,则这个方法不会检查指定的权限列表,只检查指定对象的权限。
PermissionsMixin和ModelBackend
这里是一个兼容admin的自定义的用户app的例子。这个用户模型使用email地址作为username,并且生日是必填字段;除了用户账户上的adminflag之外,它本身不提供权限检查。除用户创建的表单外,此模型和所有内置的身份验证表单和视图兼容。此例只是说明了大多数组件如何协同工作,不要直接复制到生产环境里。
这段代码将一直存在于models.py文件中,用于自定义身份验证app: