>>> from django.contrib.auth.models import User
>>> user = User.objects.create_user("john", "[email protected]", "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()
如果你安装了 Django 管理界面,你还可以 以交互方式创建用户。
创建超级用户
使用 createsuperuser
命令创建超级用户:
$ python manage.py createsuperuser --username=joe --email=[email protected]
更改密码
Django 不会在用户模型上存储原始(明文)密码,而只会存储散列值(详细信息请参阅 有关密码管理的文档)。因此,请不要尝试直接操作用户的密码属性。这就是在创建用户时使用辅助函数的原因。
更改一个用户的密码,你有几个选择:
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()
如果你已安装了 Django 管理员界面,你也可以在 身份验证系统的管理员页面 上更改用户的密码。
Django 还提供了可以用于允许用户更改自己密码的 视图 和 表单。
更改用户的密码将注销其所有会话。请参阅 password-change-session-invalidation 以获取详细信息。
验证用户
authenticate
(request=None, **credentials)[源代码]
aauthenticate
(request=None, **credentials)
异步版本:aauthenticate()
使用 authenticate()
来验证一组凭据。它以关键字参数的形式接受凭据,对于默认情况下,是 username
和 password
,然后检查它们与每个 认证后端 进行匹配,如果凭据对于某个后端是有效的,则返回一个 User
对象。如果凭据对于任何后端都无效,或者如果后端引发 PermissionDenied
,则返回 None
。例如:
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()
方法。
这是一种低级的验证一组凭据的方法;例如,它被 RemoteUserMiddleware
使用。除非你正在编写自己的身份验证系统,否则你可能不会使用它。如果你想要登录用户,最好使用 LoginView
。
Changed in Django 5.0: aauthenticate()
函数已添加。
Django 自带了一个内置的权限系统。它提供了一种将权限分配给特定用户和用户组的方式。
它被 Django 管理站点使用,但欢迎你在自己的代码中使用它。
Django 管理站点使用权限如下:
查看对象的访问权限仅限于具有该类型对象的 "view" 或 "change" 权限的用户。
查看 "添加" 表单并添加对象的访问权限仅限于具有该类型对象的 "add" 权限的用户。
访问更改列表、查看 "更改" 表单和更改对象的权限仅限于具有该类型对象的 "change" 权限的用户。
删除对象的权限仅限于具有该类型对象的 "delete" 权限的用户。
权限不仅可以按对象类型设置,还可以按特定对象实例设置。通过使用 ModelAdmin
类提供的 has_view_permission()
、has_add_permission()
、has_change_permission()
和 has_delete_permission()
方法,可以为相同类型的不同对象实例自定义权限。
User
对象有两个多对多字段:groups
和 user_permissions
。User
对象可以以与任何其他 Django 模型 相同的方式访问其相关对象:
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()
默认权限
当在你的 INSTALLED_APPS
配置中列出了 django.contrib.auth
时,它会确保为每个在你已安装的应用程序中定义的 Django 模型创建四个默认权限:添加、更改、删除和查看。
这些权限将在运行 manage.py migrate
时创建;在将 django.contrib.auth
添加到 INSTALLED_APPS
后首次运行 migrate
时,将为所有先前安装的模型创建默认权限,以及在此时安装的任何新模型。此后,每次运行 manage.py migrate
时(创建权限的函数与 post_migrate
信号相关联),都会为新模型创建默认权限。
假设你有一个带有 app_label
为 foo
的应用程序,并且有一个名为 Bar
的模型,要测试基本权限,你应该使用以下方式:
添加:user.has_perm('foo.add_bar')
修改:user.has_perm('foo.change_bar')
删除:user.has_perm('foo.delete_bar')
查看:user.has_perm('foo.view_bar')
Permission
模型很少直接访问。
django.contrib.auth.models.Group
模型是一种通用的方式,用于对用户进行分类,以便可以为这些用户分配权限或其他标签。一个用户可以属于任意数量的组。
属于组的用户自动拥有分配给该组的权限。例如,如果组 Site editors
具有权限 can_edit_home_page
,那么该组中的任何用户都将具有该权限。
除了权限外,组是一种方便的方式,用于对用户进行分类并为他们提供一些标签或扩展功能。例如,你可以创建一个组 'Special users'
,然后编写代码,可以让他们访问你网站的会员专区,或者发送给他们会员专用的电子邮件消息。
以编程方式创建权限
虽然 自定义权限 可以在模型的 Meta
类中定义,但你也可以直接创建权限。例如,你可以为 myapp
中的 BlogPost
模型创建 can_publish
权限:
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
属性来分配该权限。
代理模型需要有自己的内容类型
如果你想为代理模型创建 权限,请将 for_concrete_model=False
传递给 ContentTypeManager.get_for_model()
以获取适当的 ContentType
:
content_type = ContentType.objects.get_for_model(
BlogPostProxy, for_concrete_model=False
权限缓存
ModelBackend
在第一次需要获取权限进行权限检查后,会将权限缓存到用户对象上。这通常在请求-响应循环中是没问题的,因为权限通常不会在添加后立即进行检查(例如,在管理界面中)。如果你正在添加权限并立即在测试或视图中进行检查,最简单的解决方法是重新从数据库中获取用户。例如:
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
代理模型
代理模型的工作方式和具体模型完全相同。代理模型使用自己的内容类型创建权限。代理模型不会继承其子类的具体模型权限。
class Person(models.Model):
class Meta:
permissions = [("can_eat_pizzas", "Can eat pizzas")]
class Student(Person):
class Meta:
proxy = True
permissions = [("can_deliver_pizzas", "Can deliver pizzas")]
>>> # Fetch the content type for the proxy model.
>>> content_type = ContentType.objects.get_for_model(Student, for_concrete_model=False)
>>> student_permissions = Permission.objects.filter(content_type=content_type)
>>> [p.codename for p in student_permissions]
['add_student', 'change_student', 'delete_student', 'view_student',
'can_deliver_pizzas']
>>> for permission in student_permissions:
... user.user_permissions.add(permission)
>>> user.has_perm("app.add_person")
False
>>> user.has_perm("app.can_eat_pizzas")
False
>>> user.has_perms(("app.add_student", "app.can_deliver_pizzas"))
Web 请求的认证
Django 使用 会话 和中间件将身份验证系统与 请求对象
钩连在一起。
这些提供了每个请求上的 request.user
属性和 request.auser
异步方法,表示当前用户。如果当前用户未登录,这个属性将被设置为 AnonymousUser
的实例,否则它将是 User
的实例。
你可以使用 is_authenticated
来区分它们,如下所示:
if request.user.is_authenticated:
# Do something for authenticated users.
else:
# Do something for anonymous users.
或者在一个异步视图中:
user = await request.auser()
if user.is_authenticated:
# Do something for authenticated users.
else:
# Do something for anonymous users.
Changed in Django 5.0: 已添加了 HttpRequest.auser()
方法。
如何登录用户
如果你有一个已经经过认证的用户,想要将其附加到当前会话中,可以使用 login()
函数来实现。
login
(request, user, backend=None)[源代码]
alogin
(request, user, backend=None)
异步版本:alogin()
要从视图中登录用户,请使用 login()
。它接受一个 HttpRequest
对象和一个 User
对象。login()
会使用 Django 的会话框架将用户的ID保存在会话中。
请注意,在用户登录后,匿名会话期间设置的任何数据都将保留在会话中。
以下示例展示了如何同时使用 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 5.0: alogin()
函数已添加。
选择认证后端
当用户登录时,用户的 ID 和用于认证的后端被保存在用户的会话中。这允许相同的 认证后端 在将来的请求中获取用户的详细信息。要保存在会话中的认证后端是按以下方式选择的:
使用可选的 backend
参数的值,如果提供了的话。
使用 user.backend
属性的值,如果存在的话。这允许将 authenticate()
和 login()
配对使用: authenticate()
会在返回的用户对象上设置 user.backend
属性。
如果只有一个 AUTHENTICATION_BACKENDS
中的后端,则使用其中的后端。
否则,抛出一个异常。
在情况 1 和情况 2 中,backend
参数的值或 user.backend
属性应该是一个点分路径字符串(类似于 AUTHENTICATION_BACKENDS
中的路径),而不是实际的后端类。
如何登出用户
logout
(request)[源代码]
alogout
(request)
异步版本:alogout()
要登出通过 django.contrib.auth.login()
登录的用户,请在你的视图中使用 django.contrib.auth.logout()
。它接受一个 HttpRequest
对象,没有返回值。示例:
from django.contrib.auth import logout
def logout_view(request):
logout(request)
# Redirect to a success page.
请注意,如果用户未登录,logout()
不会引发任何错误。
当你调用 logout()
时,当前请求的会话数据将被完全清除。所有现有的数据都会被移除。这是为了防止其他人使用同一个网络浏览器登录并访问之前用户的会话数据。如果你想将任何内容放入会话中,以便用户在注销后立即使用,请在调用 logout()
之后执行这个操作。
Changed in Django 5.0: alogout()
函数已添加。
原始方式
限制访问页面的原始方法是检查 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(f"{settings.LOGIN_URL}?next={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='next', login_url=None)[源代码]
作为一种快捷方式,你可以使用方便的 login_required()
装饰器:
from django.contrib.auth.decorators import login_required
@login_required
def my_view(request): ...
login_required()
会执行以下操作:
如果用户没有登录,重定向到 settings.LOGIN_URL
,在查询字符串中传递当前的绝对路径。例如: /accounts/login/?next=/polls/3/
。
如果用户已登录,正常执行视图。视图代码可以自由地假设用户已登录。
默认情况下,用户成功认证后应重定向到的路径存储在名为 "next"
的查询字符串参数中。如果你想要使用不同的参数名称,login_required()
接受一个可选的 redirect_field_name
参数:
from django.contrib.auth.decorators import login_required
@login_required(redirect_field_name="my_redirect_field")
def my_view(request): ...
请注意,如果你为 redirect_field_name
提供了一个值,你很可能还需要自定义你的登录模板,因为存储重定向路径的模板上下文变量将使用 redirect_field_name
的值作为其键,而不是(默认值) "next"
。
login_required()
还接受一个可选的 login_url
参数。示例:
from django.contrib.auth.decorators import login_required
@login_required(login_url="/accounts/login/")
def my_view(request): ...
请注意,如果你没有指定``login_url``参数,你需要确保 settings.LOGIN_URL
和你的登录视图正确关联。例如,使用默认值,将以下行添加到你的 URL 配置文件中:
from django.contrib.auth import views as auth_views
path("accounts/login/", auth_views.LoginView.as_view()),
settings.LOGIN_URL
也接受视图函数名称和 命名的 URL 模式。这允许你在 URL 配置中自由重新映射你的登录视图,而无需更新该设置。
login_required
装饰器并不检查用户的 is_active
标志,但默认的 AUTHENTICATION_BACKENDS
会拒绝非活跃用户。
如果你正在为 Django 的管理编写自定义视图(或者需要与内置视图使用相同的授权检查),你可能会发现 django.contrib.admin.views.decorators.staff_member_required()
装饰器是一个有用的替代选择,而不是使用 login_required()
。
Changed in Django 5.1: 已添加对包装异步视图函数的支持。
LoginRequiredMixin
混合类
当使用 基于类的视图 时,你可以通过使用 LoginRequiredMixin
来实现与 login_required
相同的行为。这个混合类应该在继承列表的最左边位置。
class LoginRequiredMixin
[源代码]
如果一个视图使用了这个混合类,所有非经过身份验证的用户的请求将被重定向到登录页面或显示 HTTP 403 禁止访问的错误,这取决于 raise_exception
参数的设置。
你可以设置 AccessMixin
的任何参数来自定义未经授权用户的处理方式:
from django.contrib.auth.mixins import LoginRequiredMixin
class MyView(LoginRequiredMixin, View):
login_url = "/login/"
redirect_field_name = "redirect_to"
New in Django 5.1.
When LoginRequiredMiddleware
is
installed, all views require authentication by default. Some views, such as the
login view, may need to disable this behavior.
login_not_required
()
[源代码]
Allows unauthenticated requests to this view when
LoginRequiredMiddleware
is
installed.
限制只有经过测试的已登录用户才能访问
要基于特定权限或其他测试来限制访问,你可以基本上按照前一节所述的方法进行操作。
你可以直接在视图中对 request.user
进行测试。例如,这个视图检查用户是否拥有所需域中的电子邮件,如果没有,就重定向到登录页面:
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
(test_func, login_url=None, redirect_field_name='next')[源代码]
作为一种快捷方式,你可以使用方便的 user_passes_test
装饰器,当可调用对象返回 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_passes_test()
接受一个必需的参数,即一个可调用对象,该对象接受一个 User
对象,并在用户被允许查看页面时返回 True
。请注意,user_passes_test()
不会自动检查 User
是否是匿名用户。
user_passes_test()
接受两个可选参数:
login_url
允许你指定未通过测试的用户将被重定向到的 URL。如果你没有指定一个 URL,它可能是一个登录页面,并且默认为 settings.LOGIN_URL
。
redirect_field_name
与 login_required()
类似。将其设置为 None
将其从 URL 中移除,如果你将不通过测试的用户重定向到一个没有 "下一页" 的非登录页面,你可能会想这样做。
@user_passes_test(email_check, login_url="/login/")
def my_view(request): ...
Changed in Django 5.1: Support for wrapping asynchronous view functions and using asynchronous
test callables was added.
test_func
()[源代码]
你需要重写类的 test_func()
方法来提供要执行的测试。此外,你可以设置 AccessMixin
的任何参数来自定义未经授权用户的处理方式:
from django.contrib.auth.mixins import UserPassesTestMixin
class MyView(UserPassesTestMixin, View):
def test_func(self):
return self.request.user.email.endswith("@example.com")
集成 UserPassesTestMixin
由于 UserPassesTestMixin
的实现方式,你不能在继承列表中堆叠它们。以下方式是不起作用的:
class TestMixin1(UserPassesTestMixin):
def test_func(self):
return self.request.user.email.endswith("@example.com")
class TestMixin2(UserPassesTestMixin):
def test_func(self):
return self.request.user.username.startswith("django")
class MyView(TestMixin1, TestMixin2, View): ...
如果 TestMixin1
调用了 super()
并考虑了该结果,那么 TestMixin1
将不再能够独立工作。
permission_required
(perm, login_url=None, raise_exception=False)[源代码]
It's a relatively common task to check whether a user has a particular
permission. For that reason, Django provides a shortcut for that case: the
permission_required()
decorator:
from django.contrib.auth.decorators import permission_required
@permission_required("polls.add_choice")
def my_view(request): ...
就像 has_perm()
方法一样,权限名称采用形式 "<app label>.<permission codename>"
(例如,在 polls
应用程序中的模型上的权限为 polls.add_choice
)。
该装饰器还可以接受一个权限的可迭代对象,此时用户必须具备所有这些权限才能访问视图。
请注意,permission_required()
还接受一个可选的 login_url
参数:
from django.contrib.auth.decorators import permission_required
@permission_required("polls.add_choice", login_url="/loginpage/")
def my_view(request): ...
与 login_required()
装饰器一样,login_url
默认为 settings.LOGIN_URL
。
如果提供了 raise_exception
参数,装饰器将引发 PermissionDenied
异常,而不是重定向到登录页面,从而触发 403(HTTP Forbidden)视图。
如果你想使用 raise_exception
,但也想让用户有机会首先登录,你可以添加 login_required()
装饰器:
from django.contrib.auth.decorators import login_required, permission_required
@login_required
@permission_required("polls.add_choice", raise_exception=True)
def my_view(request): ...
这也可以避免在 LoginView
的 redirect_authenticated_user=True
且已登录用户没有所有所需权限时发生重定向循环。
Changed in Django 5.1: 已添加对包装异步视图函数的支持。
PermissionRequiredMixin
Mixin
要将权限检查应用于 基于类的视图,你可以使用 PermissionRequiredMixin
:
class PermissionRequiredMixin
[源代码]
这个混合类,就像 permission_required
装饰器一样,检查访问视图的用户是否具有所有给定的权限。你应该使用 permission_required
参数来指定权限(或权限的可迭代对象):
from django.contrib.auth.mixins import PermissionRequiredMixin
class MyView(PermissionRequiredMixin, View):
permission_required = "polls.add_choice"
# Or multiple of permissions:
permission_required = ["polls.view_choice", "polls.change_choice"]
你可以设置 AccessMixin
的任何参数来自定义未经授权用户的处理方式。
你可能同样需要重写这些方法:
get_permission_required
()[源代码]
返回一个被混合类使用的权限名称的可迭代对象。默认为 permission_required
属性,如果需要会将其转换为元组。
在基于类的视图中重定向未经授权的请求
为了简化在 基于类的视图 中处理访问限制,可以使用 AccessMixin
来配置在拒绝访问时视图的行为。已认证的用户将被拒绝访问,并收到 HTTP 403 禁止访问的响应。匿名用户将根据 raise_exception
属性的设置,被重定向到登录页面或显示 HTTP 403 禁止访问的响应。
class AccessMixin
[源代码]
login_url
get_login_url()
方法的默认返回值。如果未设置,默认为 None
,在这种情况下,get_login_url()
会回退到 settings.LOGIN_URL
。
密码更改时的会话失效
如果你的 AUTH_USER_MODEL
继承自 AbstractBaseUser
或实现了自己的 get_session_auth_hash()
方法,已认证的会话将包括该函数返回的哈希值。在 AbstractBaseUser
的情况下,这是密码字段的 HMAC。Django 在每个请求中验证会话中的哈希是否与请求期间计算的哈希匹配。这允许用户通过更改密码来注销他们的所有会话。
Django 默认包含的密码更改视图,包括 PasswordChangeView
和 django.contrib.auth
管理界面中的 user_change_password
视图,会使用新的密码哈希更新会话,以便用户更改自己的密码不会注销自己。如果你有自定义的密码更改视图并希望具有类似的行为,可以使用 update_session_auth_hash()
函数。
update_session_auth_hash
(request, user)[源代码]
aupdate_session_auth_hash
(request, user)
异步版本:aupdate_session_auth_hash()
这个函数接受当前请求和已更新的用户对象,新的会话哈希将从中派生,并适当地更新会话哈希。它还会轮换会话密钥,以使被盗的会话 cookie 无效。
用法示例:
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:
Changed in Django 5.0: aupdate_session_auth_hash()
函数已添加。
认证视图
Django 提供了多个视图,你可以用来处理登录、注销和密码管理。这些视图使用了 内置的身份验证表单,但你也可以传入自己的表单。
Django 不提供身份验证视图的默认模板。你应该为想要使用的视图创建自己的模板。模板上下文在每个视图中都有文档记录,详见 所有认证视图。
使用视图
有多种方法可以在项目中实现这些视图。最简单的方法是在你自己的 URL 配置中包含提供的 URLconf,例如:
urlpatterns = [
path("accounts/", include("django.contrib.auth.urls")),
这将包括以下 URL 模式:
accounts/login/ [name='login']
accounts/logout/ [name='logout']
accounts/password_change/ [name='password_change']
accounts/password_change/done/ [name='password_change_done']
accounts/password_reset/ [name='password_reset']
accounts/password_reset/done/ [name='password_reset_done']
accounts/reset/<uidb64>/<token>/ [name='password_reset_confirm']
accounts/reset/done/ [name='password_reset_complete']
这些视图提供了一个URL名称,以便更容易引用。有关使用命名URL模式的详细信息,请参阅 URL文档。
如果你想要更多控制你的 URL,你可以在你的 URLconf 中引用一个特定的视图:
from django.contrib.auth import views as auth_views
urlpatterns = [
path("change-password/", auth_views.PasswordChangeView.as_view()),
视图有可选参数,你可以使用这些参数来更改视图的行为。例如,如果你想要更改视图使用的模板名称,你可以提供 template_name
参数。一种方法是在 URLconf 中提供关键字参数,这些参数将传递给视图。例如:
urlpatterns = [
path(
"change-password/",
auth_views.PasswordChangeView.as_view(template_name="change-password.html"),
所有视图都是 基于类的,这使你可以通过子类化轻松自定义它们。
所有认证视图
这是所有由 django.contrib.auth
提供的视图列表。有关实现细节,请参阅 使用视图。
class LoginView
[源代码]
URL 名称: login
请参阅 URL 文档 以获取有关使用命名 URL 模式的详细信息。
方法和属性
template_name
用于显示用户登录视图的模板名称。默认为 registration/login.html
。
如果启用了 redirect_authenticated_user
,其他网站可以通过请求重定向到你网站上的图像文件的 URL 来确定他们的访问者是否在你的站点上进行了身份验证。为了避免这种 "社交媒体指纹识别" 信息泄漏,将所有图像和您的站点图标托管在一个单独的域上。
启用 redirect_authenticated_user
在使用 permission_required()
装饰器时可能会导致重定向循环,除非使用 raise_exception
参数。
get_default_redirect_url
()[源代码]
返回登录后重定向的URL。如果设置了默认实现会解析并返回 next_page
,否则返回 LOGIN_REDIRECT_URL
。
以下是 LoginView
所做的事情:
如果通过 GET
调用,它会显示一个登录表单,该表单将数据 POST 到相同的 URL。稍后会详细介绍这一点。
如果通过用户提交的凭据调用 POST
,它会尝试登录用户。如果登录成功,视图将重定向到 next
参数指定的 URL。如果未提供 next
,它将重定向到 settings.LOGIN_REDIRECT_URL
(默认为 /accounts/profile/
)。如果登录不成功,它会重新显示登录表单。
你需要提供登录模板的 HTML,默认情况下命名为 registration/login.html
。该模板将接收四个模板上下文变量:
form
: 一个代表 AuthenticationForm
的 Form
对象。
next
: 登录成功后要重定向的 URL。这可能包含查询字符串。
site
: 根据 SITE_ID
设置,表示当前的 Site
。如果你没有安装站点框架,它将设置为 RequestSite
的实例,该实例从当前的 HttpRequest
获取站点名称和域名。
site_name
: 用于别名 site.name
。如果你没有安装站点框架,它将设置为 request.META['SERVER_NAME']
的值。有关站点的更多信息,请参阅 “站点”框架。
如果你不想将模板命名为 registration/login.html
,你可以通过额外的参数将 template_name
参数传递给 URLconf 中的 as_view
方法。例如,以下 URLconf 行将使用 myapp/login.html
:
path("accounts/login/", auth_views.LoginView.as_view(template_name="myapp/login.html")),
你还可以使用 redirect_field_name
指定包含登录后重定向 URL 的 GET
字段的名称。默认情况下,该字段称为 next
。
以下是一个示例 registration/login.html
模板,你可以将其用作起点。它假定你有一个定义了 content
块的 base.html
模板:
{% extends "base.html" %}
{% block content %}
{% if form.errors %}
<p>Your username and password didn't match. Please try again.</p>
{% endif %}
{% if next %}
{% if user.is_authenticated %}
<p>Your account doesn't have access to this page. To proceed,
please login with an account that has access.</p>
{% else %}
<p>Please login to see this page.</p>
{% endif %}
{% endif %}
<form method="post" action="{% url 'login' %}">
{% csrf_token %}
<table>
<td>{{ form.username.label_tag }}</td>
<td>{{ form.username }}</td>
<td>{{ form.password.label_tag }}</td>
<td>{{ form.password }}</td>
</table>
<input type="submit" value="login">
<input type="hidden" name="next" value="{{ next }}">
</form>
{# Assumes you set up the password_reset view in your URLconf #}
<p><a href="{% url 'password_reset' %}">Lost password?</a></p>
{% endblock %}
如果你已经自定义了身份验证(参见 自定义身份验证),你可以通过设置 authentication_form
属性来使用自定义的身份验证表单。这个表单必须在其 __init__()
方法中接受一个 request
关键字参数,并提供一个返回经过身份验证的用户对象的 get_user()
方法(此方法仅在表单验证成功后调用)。
title
:本地化的字符串 "已注销"。
site
: 根据 SITE_ID
设置,表示当前的 Site
。如果你没有安装站点框架,它将设置为 RequestSite
的实例,该实例从当前的 HttpRequest
获取站点名称和域名。
site_name
: 用于别名 site.name
。如果你没有安装站点框架,它将设置为 request.META['SERVER_NAME']
的值。有关站点的更多信息,请参阅 “站点”框架。
logout_then_login
(request, login_url=None)[源代码]
在 POST
请求上注销用户,然后重定向到登录页面。
URL 名称: 未提供默认 URL
可选参数:
login_url
: 要重定向到的登录页面的 URL。如果未提供,默认为 settings.LOGIN_URL
。
class PasswordResetView
[源代码]
URL 名称: password_reset
允许用户通过生成一次性使用的链接来重置密码,并将该链接发送到用户注册的电子邮件地址。
如果满足以下条件,此视图将发送电子邮件:
提供的电子邮件地址存在于系统中。
所请求的用户处于活动状态( User.is_active
为 True
)。
所请求的用户具有可用的密码。被标记为不可用密码的用户(参见 set_unusable_password()
)不允许请求密码重置,以防止在使用外部身份验证源如 LDAP 时被滥用。
如果不满足上述任何条件,将不会发送电子邮件,但用户也不会收到任何错误消息。这可以防止信息泄漏给潜在的攻击者。如果您想在这种情况下提供错误消息,可以子类化 PasswordResetForm
并使用 form_class
属性。
请注意,发送电子邮件会耗费额外的时间,因此由于重置请求的持续时间与不存在的电子邮件地址的重置请求的持续时间之间存在差异,您可能会容易受到电子邮件地址枚举时序攻击的影响。为了减少开销,您可以使用第三方包,允许异步发送电子邮件,例如 django-mailer。
template_name
要用于显示密码重置表单的模板的完整名称。如果未提供,默认为 registration/password_reset_form.html
。
email
: user.email
的别名
user
:根据 email
表单字段,表示当前的 User
。只有活动用户才能重置他们的密码( User.is_active is True
)。
site_name
: 用于别名 site.name
。如果你没有安装站点框架,它将设置为 request.META['SERVER_NAME']
的值。有关站点的更多信息,请参阅 “站点”框架。
domain
:site.domain
的别名。如果你没有安装站点框架,这将设置为 request.get_host()
的值。
protocol
:http 或 https
uid
:使用 base 64 编码过的用户主键。
token
:检测重置密码链接是否有效的 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 %}
相同的模板上下文用于主题模板。主题必须是单行纯文本字符串。
class PasswordResetDoneView
[源代码]
URL 名称: password_reset_done
在向用户发送了重置密码链接后显示的页面。如果 PasswordResetView
没有显式设置 success_url
URL,则默认调用此视图。
如果提供的电子邮件地址在系统中不存在,用户处于非活动状态,或者密码不可用,用户仍然会被重定向到此视图,但不会发送电子邮件。
template_name
要使用的模板的完整名称。如果未提供,默认为 registration/password_reset_done.html
。
class PasswordResetCompleteView
[源代码]
URL 名称: password_reset_complete
提供一个视图,通知用户密码已成功更改。
template_name
用于显示视图的模板的完整名称。默认为 registration/password_reset_complete.html
。
redirect_to_login
(next, login_url=None, redirect_field_name='next')[源代码]
重定向到登录页面,登陆成功后跳转到其他 URL 。
next
:成功登陆后跳转的 URL。
可选参数:
login_url
: 要重定向到的登录页面的 URL。如果未提供,默认为 settings.LOGIN_URL
。
redirect_field_name
: GET
字段包含的登录后跳转 URL 的参数名称。如果传递给定的 GET
参数,将会覆盖 next
。
class AdminPasswordChangeForm
[源代码]
A form used in the admin interface to change a user's password, including
the ability to set an unusable password
, which blocks the
user from logging in with password-based authentication.
将 user
作为第一个位置参数。
Changed in Django 5.1: Option to disable (or reenable) password-based authentication was
added.
New in Django 5.1.1.
A form used in the admin interface to create a new user. Inherits from
UserCreationForm
.
It includes an additional usable_password
field, enabled by default. If
usable_password
is enabled, it verifies that password1
and
password2
are non empty and match, validates the password using
validate_password()
, and
sets the user's password using
set_password()
.
If usable_password
is disabled, no password validation is done, and
password-based authentication is disabled for the user by calling
set_unusable_password()
.
confirm_login_allowed
(
user)
[源代码]
默认情况下,AuthenticationForm
拒绝 is_active
标志设置为 False
的用户。您可以通过自定义策略来确定哪些用户可以登录来覆盖此行为。可以通过创建一个子类化 AuthenticationForm
并覆盖 confirm_login_allowed()
方法的自定义表单来实现这一点。如果给定的用户不允许登录,此方法应引发 ValidationError
。
例如,要允许所有用户登录,而不考虑其“active”状态:
from django.contrib.auth.forms import AuthenticationForm
class AuthenticationFormWithInactiveUsersOkay(AuthenticationForm):
def confirm_login_allowed(self, user):
(在这种情况下,您还需要使用允许不活动用户的身份验证后端,例如 AllowAllUsersModelBackend
。)
或者只允许某些活动用户登录:
class PickyAuthenticationForm(AuthenticationForm):
def confirm_login_allowed(self, user):
if not user.is_active:
raise ValidationError(
_("This account is inactive."),
code="inactive",
if user.username.startswith("b"):
raise ValidationError(
_("Sorry, accounts starting with 'b' aren't welcome here."),
code="no_b_users",
send_mail
(subject_template_name, email_template_name, context, from_email, to_email, html_email_template_name=None)[源代码]
Uses the arguments to send an EmailMultiAlternatives
.
Can be overridden to customize how the email is sent to the user. If
you choose to override this method, be mindful of handling potential
exceptions raised due to email sending failures.
subject_template_name -- 主题的模板。
email_template_name -- 电子邮件正文的模板。
context -- 传递给 subject_template
、email_template
和 html_email_template
(如果不为 None
)的上下文。
from_email -- 发送者的电子邮件地址。
to_email -- 请求者的电子邮件地址。
html_email_template_name -- HTML 正文的模板;默认为 None
,在这种情况下发送纯文本电子邮件。
从技术上讲,只有在使用 RequestContext
并启用了 'django.contrib.auth.context_processors.auth'
上下文处理器时,这些变量才会在模板上下文中提供。它在默认生成的设置文件中已经存在。有关更多信息,请参阅 RequestContext 文档。
在渲染模板时, RequestContext
会将当前已登录的用户,可以是 User
实例或 AnonymousUser
实例,存储在模板变量 {{ user }}
中:
{% if user.is_authenticated %}
<p>Welcome, {{ user.username }}. Thanks for logging in.</p>
{% else %}
<p>Welcome, new user. Please log in.</p>
{% endif %}
如果未使用 RequestContext
,则此模板上下文变量将不可用。
当前已登录用户的权限存储在模板变量 {{ perms }}
中。这是 django.contrib.auth.context_processors.PermWrapper
的一个实例,它是权限的模板友好代理。
将 {{ perms }}
的单属性查找评估为布尔值是 User.has_module_perms()
的代理。例如,要检查已登录用户是否在 foo
应用程序中有任何权限:
{% if perms.foo %}
将双层属性查找评估为布尔值是 User.has_perm()
的代理。例如,要检查已登录用户是否具有权限 foo.add_vote
:
{% if perms.foo.add_vote %}
以下是在模板中检查权限的更完整的示例:
{% if perms.foo %}
<p>You have permission to do something in the foo app.</p>
{% if perms.foo.add_vote %}
<p>You can vote!</p>
{% endif %}
{% if perms.foo.add_driving %}
<p>You can drive!</p>
{% endif %}
{% else %}
<p>You don't have permission to do anything in the foo app.</p>
{% endif %}
也可以使用 {% if in %}
语句查找权限。例如:
{% if 'foo' in perms %}
{% if 'foo.add_vote' in perms %}
<p>In lookup works, too.</p>
{% endif %}
{% endif %}
在 admin 中管理用户
当您同时安装了 django.contrib.admin
和 django.contrib.auth
时,管理界面提供了一种方便的方式来查看和管理用户、组和权限。用户可以像任何 Django 模型一样创建和删除。可以创建组,并将权限分配给用户或组。还会存储和显示在管理界面内对模型的用户编辑记录。
创建用户
You should see a link to "Users" in the "Auth"
section of the main admin index page. The "Add user" admin page is different
than standard admin pages in that it requires you to choose a username and
password before allowing you to edit the rest of the user's fields.
Alternatively, on this page, you can choose a username and disable
password-based authentication for the user.
还要注意:如果您希望用户帐户能够使用 Django 管理站点创建用户,您需要为其分配添加用户和更改用户(即“添加用户”和“更改用户”权限)。如果帐户有添加用户的权限但没有更改用户的权限,那么该帐户将无法添加用户。为什么?因为如果您有添加用户的权限,那么您就有了创建超级用户的权力,然后超级用户可以修改其他用户。因此,Django 要求同时具备添加和更改权限作为一种轻微的安全措施。
在允许用户管理权限时要谨慎。如果您授予非超级用户编辑用户的权限,这实际上与授予他们超级用户状态相同,因为他们将能够提升用户的权限,包括他们自己!
更改密码
User passwords are not displayed in the admin (nor stored in the database), but
the password storage details are displayed.
Included in the display of this information is a link to
a password change form that allows admins to change or unset user passwords.