aboutsummaryrefslogtreecommitdiff
path: root/files/zh-cn/learn/server-side/django/authentication/index.html
diff options
context:
space:
mode:
Diffstat (limited to 'files/zh-cn/learn/server-side/django/authentication/index.html')
-rw-r--r--files/zh-cn/learn/server-side/django/authentication/index.html710
1 files changed, 710 insertions, 0 deletions
diff --git a/files/zh-cn/learn/server-side/django/authentication/index.html b/files/zh-cn/learn/server-side/django/authentication/index.html
new file mode 100644
index 0000000000..c6536c3309
--- /dev/null
+++ b/files/zh-cn/learn/server-side/django/authentication/index.html
@@ -0,0 +1,710 @@
+---
+title: 'Django 教程 8: 用户授权与许可'
+slug: learn/Server-side/Django/Authentication
+translation_of: Learn/Server-side/Django/Authentication
+---
+<div>{{LearnSidebar}}</div>
+
+<div>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</div>
+
+<p class="summary">在<font><font>本教程中,我们将向您展示如何允许用户使用自己的帐户登录到您的网站,以及如何根据用户是否已登录及其</font></font><em><font><font>权限</font></font></em><font><font>来控制他们可以执行和查看的内容</font><font>。</font><font>作为演示的一部分,我们将扩展</font></font><a href="https://developer.mozilla.org/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website" style='color: rgb(63, 135, 166); margin: 0px; padding: 0px; border: 0px; text-decoration: none; font-family: "Open Sans", arial, x-locale-body, sans-serif; font-size: 20px; font-style: normal; font-weight: 400; letter-spacing: normal; text-align: start; text-indent: 0px; text-transform: none; white-space: normal; background-color: rgb(255, 255, 255);'><font><font>LocalLibrary</font></font></a><font><font>网站,添加登录页面和注销页面,以及用户和员工特定的页面以查看已借阅的图书</font></font>。</p>
+
+<table class="learn-box standard-table">
+ <tbody>
+ <tr>
+ <th scope="row">先决条件:</th>
+ <td>完成之前的所有教程主题,包括<a href="/zh-CN/docs/Learn/Server-side/Django/Sessions">Django 教程 7:Sessions 框架</a>。</td>
+ </tr>
+ <tr>
+ <th scope="row">目的:</th>
+ <td>了解如何设置和使用用户身份验证和权限。</td>
+ </tr>
+ </tbody>
+</table>
+
+<h2 id="概观">概观</h2>
+
+<p>Django 提供了一个身份验证和授权(“权限”)系统,该系统构建在<a href="/zh-CN/docs/Learn/Server-side/Django/Sessions">上一个教程</a>中讨论的会话框架之上,允许您验证用户凭据,并定义每个用户可允许执行的操作。该框架包括用户<code>Users</code>和分组<code>Groups</code>的内置模型(一次向多个用户应用权限的通用方法),用于登录用户的权限/标志,以指定用户是否可以执行任务,表单和视图,以及查看限制内容的工具。</p>
+
+<div class="note">
+<p><strong>注意</strong>: Django身份验证系统的目标非常通用,因此不提供其他Web身份验证系统中,所提供的某些功能。某些常见问题的解决方案,可作为第三方软件包提供。例如,限制登录尝试,和针对第三方的身份验证(例如 OAuth)。</p>
+</div>
+
+<p>在本教程中,我们将向您展示,如何在<a href="/zh-CN/docs/Learn/Server-side/Django/Tutorial_local_library_website">LocalLibrary</a>网站中,启用用户身份验证,创建您自己的登录和注销页面,为模型添加权限,以及控制对页面的访问。我们将使用身份验证/权限,来显示用户和图书馆员借用图书的列表。</p>
+
+<p>身份验证系统非常灵活,您可以根据需要,从头开始构建 URLs,表单,视图和模板,只需调用提供的API,即可登录用户。但是,在本文中,我们将在登录和注销页面,使用 Django 的“库存” 身份验证视图和表单。我们仍然需要创建一些模板,但这很简单。</p>
+
+<p>我们还将向您展示如何创建权限,以及检查视图和模板中的登录状态和权限。</p>
+
+<h2 id="启用身份验证">启用身份验证</h2>
+
+<p>我们在<a href="/zh-CN/docs/Learn/Server-side/Django/skeleton_website">创建框架网站</a>时(在教程2中),自动启用了身份验证,因此您此时,无需再执行任何操作。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 当我们使用 <code>django-admin startproject </code>命令,以创建应用程序时,所有必要的配置都已完成。当我们第一次调用 <code>python manage.py migrate</code> 时,创建了用户和模型权限的数据库表。</p>
+</div>
+
+<p>配置在项目文件(<strong>locallibrary/locallibrary/settings.py</strong>)的<code>INSTALLED_APPS</code>和<code>MIDDLEWARE</code>部分中设置,如下所示:</p>
+
+<pre class="brush: python">INSTALLED_APPS = [
+ ...
+<strong>    'django.contrib.auth', </strong>#Core authentication framework and its default models.
+<strong>    'django.contrib.contenttypes', #</strong>Django content type system (allows permissions to be associated with models).
+ ....
+
+MIDDLEWARE = [
+ ...
+<strong>    'django.contrib.sessions.middleware.SessionMiddleware',</strong> #Manages sessions across requests
+ ...
+<strong>    'django.contrib.auth.middleware.AuthenticationMiddleware',</strong> #Associates users with requests using sessions.
+ ....
+</pre>
+
+<h2 id="创建用户和分组">创建用户和分组</h2>
+
+<p>在教程 4 中,当我们查看 <a href="/zh-CN/docs/Learn/Server-side/Django/Admin_site">Django 管理站点</a>时,您已经创建了第一个用户(这是一个超级用户,使用命令 <code>python manage.py createsuperuser </code>创建)。我们的超级用户已经过身份验证,并拥有所有权限,因此我们需要创建一个测试用户,来代表普通网站用户。我们将使用管理站点,来创建我们的 locallibrary 组別和网站登录,因为这是最快的方法之一。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 您还可以用编程方式创建用户,如下所示。您会必须这样做,例如,如果要开发一个界面,能允许用户创建自己的登录(您不应该授予用户访问管理站点的权限)。</p>
+
+<pre class="brush: python">from django.contrib.auth.models import User
+
+# Create user and save to the database
+user = User.objects.create_user('myusername', 'myemail@crazymail.com', 'mypassword')
+
+# Update fields and then save again
+user.first_name = 'John'
+user.last_name = 'Citizen'
+user.save()
+</pre>
+</div>
+
+<p>下面,我们首先创建一个分组,然后创建一个用户。即使我们还没有为我们的图书馆成员添加任何权限,如果我们以后需要,将它们添加到分组中,要比单独添加到每个成员要容易得多。</p>
+
+<p>启动开发服务器,并到本地 Web 浏览器中的管理站点(<a href="http://127.0.0.1:8000/admin/">http://127.0.0.1:8000/admin/</a>)。使用超级用户帐户的凭据,登录该站点。 Admin 站点的最上级显示所有模型,按 “django application” 排序。在 “身份验证和授权” <strong>Authentication and Authorisation </strong>部分 ,您可以单击用户 <strong>Users ,</strong>或分组 <strong>Groups </strong>链接,以查看其现有记录。</p>
+
+<p><img alt="Admin site - add groups or users" src="https://mdn.mozillademos.org/files/14091/admin_authentication_add.png" style="border-style: solid; border-width: 1px; display: block; height: 364px; margin: 0px auto; width: 661px;"></p>
+
+<p>首先,我们为图书馆成员,创建一个新的分组。</p>
+
+<ol>
+ <li>单击“添加” <strong>Add </strong>按钮(“分组” Group 旁边)以创建新的分组;在分组的名称<strong> Name</strong> ,输入“Library Members”。<img alt="Admin site - add group" src="https://mdn.mozillademos.org/files/14093/admin_authentication_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 561px; margin: 0px auto; width: 800px;"></li>
+ <li>我们不需要该组的任何权限,因此只需按<strong>SAVE</strong>(您将进入分组列表)。</li>
+</ol>
+
+<p>现在让我们创建一个用户:</p>
+
+<ol>
+ <li>回到管理站点的主页</li>
+ <li>单击“用户”旁边的“添加”按钮 <strong>Add</strong>,以打开“添加用户”对话框。<img alt="Admin site - add user pt1" src="https://mdn.mozillademos.org/files/14095/admin_authentication_add_user_prt1.png" style="border-style: solid; border-width: 1px; display: block; height: 409px; margin: 0px auto; width: 800px;"></li>
+ <li>为测试用户输入适当的用户名(<strong>Username)</strong>和密码/密码确认<strong>(Password/Password confirmation</strong> )</li>
+ <li>按 <strong>SAVE</strong> 创建用户。
+ <p> </p>
+
+ <p>管理站点将创建新用户,并立即转到 “更改用户” 屏幕,您可以在其中更改用户名(<strong>username</strong>),并添加用户模型的可选字段的信息。这些字段包括名字,姓氏,电子邮件地址,用户状态和权限(仅应设置活动标志<strong> Active</strong>)。再往下,您可以指定用户的分组和权限,并查看与用户相关的重要日期(例如,他们的加入日期和上次登录日期)。</p>
+ <img alt="Admin site - add user pt2" src="https://mdn.mozillademos.org/files/14097/admin_authentication_add_user_prt2.png" style="border-style: solid; border-width: 1px; display: block; height: 635px; margin: 0px auto; width: 800px;"></li>
+ <li>在“分组”(<em>Groups</em>)部分中,从“可用分组”(<em>Available groups</em>)列表中,选择“图书馆成员”分组 <strong>Library Member</strong>,然后点击这些框之间的<strong>右箭头</strong>,将其移动到“选择的分组”(<em>Chosen groups</em>)框中。<img alt="Admin site - add user to group" src="https://mdn.mozillademos.org/files/14099/admin_authentication_user_add_group.png" style="border-style: solid; border-width: 1px; display: block; height: 414px; margin: 0px auto; width: 933px;"></li>
+ <li>我们不需要在此处执行任何其他操作,因此只需再次选择<strong> SAVE</strong> ,即可转到用户列表。</li>
+</ol>
+
+<p>就是这样!现在您有一个 “普通的图书馆成员” 帐户,您可以使用该帐户进行测试(一旦我们实现了页面,使他们能够登录)。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 您应该尝试创建另一个图书馆用户。此外,为图书馆管理员创建一个分组,并添加一个用户!</p>
+</div>
+
+<h2 id="设置身份验证视图">设置身份验证视图</h2>
+
+<p>Django 提供了创建身份验证页面所需的几乎所有功能,让处理登录,注销和密码管理等工作,都能 “开箱即用”。这些相关功能包括了 url 映射器,视图和表单,但它不包括模板 - 我们必须创建自己的模板!</p>
+
+<p>在本节中,我们将展示如何将默认系统,集成到 LocalLibrary 网站并创建模板。我们将它们放在主项目的 URL 当中。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 您不必一定要使用这些代码,但您可能希望这样做,因为它使事情变得更容易。如果更改用户模型(高级主题!),您几乎肯定需要更改表单处理代码。但即便如此,您仍然可以使用先前已经有的视图功能。</p>
+</div>
+
+<div class="note">
+<p><strong>注意: </strong>在这种情况下,我们可以合理地将认证页面(包括URL和模板)放在我们的目录应用程序中。但是,如果我们有多个应用程序,最好将这个共享登录行为分开,并让它在整个站点上可用,这就是我们在这里展示的内容!</p>
+</div>
+
+<h3 id="项目网址">项目网址</h3>
+
+<p>将以下内容,添加到项目 urls.py(<strong>locallibrary/locallibrary/urls.py</strong>)文件的底部:</p>
+
+<pre class="brush: python"># Use include() to add URLS from the catalog application and authentication system
+from django.urls import include
+
+#Add Django site authentication urls (for login, logout, password management)
+urlpatterns += [
+ path('accounts/', include('django.contrib.auth.urls')),
+]
+</pre>
+
+<p>打开 URL <a href="http://127.0.0.1:8000/accounts/">http://127.0.0.1:8000/accounts/</a> (注意前面的斜杠!),Django将显示一个错误,它无法找到此URL,并列出它尝试过的所有URL。从中您可以看到可以使用的URL,例如:</p>
+
+<div class="note">
+<p><strong>注意: </strong>使用上面的方法,添加以下带有方括号中的名称的 URL,可用于反转 URL 映射。您不必实现任何其他内容 - 上面的 url 映射,会自动映射下面提到的URL。</p>
+</div>
+
+<div class="note">
+<pre class="brush: python">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/&lt;uidb64&gt;/&lt;token&gt;/ [name='password_reset_confirm']
+accounts/ reset/done/ [name='password_reset_complete']</pre>
+</div>
+
+<p>现在尝试打开登录 URL(<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>)。这将再次失败,但有一个错误告诉您,我们在模板搜索路径上缺少必需的模板(<strong>registration/login.html</strong>)。您将在顶部的黄色部分中,看到以下文字:</p>
+
+<pre class="brush: python">Exception Type: TemplateDoesNotExist
+Exception Value: <strong>registration/login.html</strong></pre>
+
+<p>下一步是在搜索路径上创建注册目录,然后添加 <strong>login.html </strong>文件。</p>
+
+<h3 id="模板目录">模板目录</h3>
+
+<p>我们希望在模板搜索路径中的目录 <strong>/registration/</strong> 某处,找到刚刚添加的 url(以及隐式视图)的关联模板。</p>
+
+<p>对于此站点,我们将 HTML 页面,放在 <strong>templates/registration/ </strong>目录中。此目录应该位于项目的根目录中,即与 <strong>catalog </strong>和 <strong>locallibrary </strong>文件夹相同的目录)。请立即创建这些文件夹。</p>
+
+<div class="note">
+<p><strong>注意:</strong> 您的文件夹结构,现在应如下所示:<br>
+ locallibrary (django project folder)<br>
+    |_catalog<br>
+    |_locallibrary<br>
+    |_templates <strong>(new)</strong><br>
+                 |_registration</p>
+</div>
+
+<p>要使这些目录对模板加载器可见(即将此目录放在模板搜索路径中),请打开项目设置(<strong>/locallibrary/locallibrary/settings.py</strong>),并更新<code>TEMPLATES </code>部分的 “<code>DIRS</code>” 那一行,如下所示。</p>
+
+<pre class="brush: python">TEMPLATES = [
+ {
+ ...
+<strong> 'DIRS': ['./templates',],</strong>
+ 'APP_DIRS': True,
+ ...
+</pre>
+
+<h3 id="登录模板">登录模板</h3>
+
+<div class="warning">
+<p><strong>重要说明</strong>: 本文提供的身份验证模板,是 Django 演示登录模板的基本/略微修改版本。您可能需要自定义它们,以供自己使用!</p>
+</div>
+
+<p>创建一个名为 <strong>/locallibrary/templates/registration/login.html</strong> 的新HTML文件。为它加入以下内容:</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+
+{% if form.errors %}
+&lt;p&gt;Your username and password didn't match. Please try again.&lt;/p&gt;
+{% endif %}
+
+{% if next %}
+    {% if user.is_authenticated %}
+    &lt;p&gt;Your account doesn't have access to this page. To proceed,
+    please login with an account that has access.&lt;/p&gt;
+    {% else %}
+    &lt;p&gt;Please login to see this page.&lt;/p&gt;
+    {% endif %}
+{% endif %}
+
+&lt;form method="post" action="{% url 'login' %}"&gt;
+{% csrf_token %}
+
+&lt;div&gt;
+  &lt;td&gt;\{{ form.username.label_tag }}&lt;/td&gt;
+  &lt;td&gt;\{{ form.username }}&lt;/td&gt;
+&lt;/div&gt;
+&lt;div&gt;
+  &lt;td&gt;\{{ form.password.label_tag }}&lt;/td&gt;
+  &lt;td&gt;\{{ form.password }}&lt;/td&gt;
+&lt;/div&gt;
+
+&lt;div&gt;
+  &lt;input type="submit" value="login" /&gt;
+  &lt;input type="hidden" name="next" value="\{{ next }}" /&gt;
+&lt;/div&gt;
+&lt;/form&gt;
+
+{# Assumes you setup the password_reset view in your URLconf #}
+&lt;p&gt;&lt;a href="{% url 'password_reset' %}"&gt;Lost password?&lt;/a&gt;&lt;/p&gt;
+
+{% endblock %}</pre>
+
+<p>此模板与我们之前看到的模板,有一些相似之处 - 它扩展了我们的基本模板,并覆盖了内容区块 <code>content</code>。其余代码,是相当标准的表单处理代码,我们将在后面的教程中讨论。您现在需要知道的是,这将显示一个表单,您可以在其中输入您的用户名和密码,如果您输入的值无效,则会在页面刷新时,提示您输入正确的值。</p>
+
+<p>保存模板后,回到登录页面(<a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a>),您应该看到如下内容:</p>
+
+<p><img alt="Library login page v1" src="https://mdn.mozillademos.org/files/14101/library_login.png" style="border-style: solid; border-width: 1px; display: block; height: 173px; margin: 0px auto; width: 441px;"></p>
+
+<p>如果您尝试登录,将会成功,并且您将被重定向到另一个页面(默认情况下,这将是 <a href="http://127.0.0.1:8000/accounts/profile/">http://127.0.0.1:8000/accounts/profile/</a>)。这里的问题是,默认情况下,Django希望在登录后,你可能会被带到个人资料页面,这可能是,也可能不是。由于您还没有定义此页面,您将收到另一个错误!</p>
+
+<p>打开项目设置(<strong>/locallibrary/locallibrary/settings.py</strong>),并将下面的文本添加到底部。现在登录时,您应该默认重定向到站点主页。</p>
+
+<pre class="brush: python"># Redirect to home URL after login (Default redirects to /accounts/profile/)
+LOGIN_REDIRECT_URL = '/'
+</pre>
+
+<h3 id="登出模板">登出模板</h3>
+
+<p>如果您打开登出网址(<a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a>),那么您会看到一些奇怪的行为 - 您所属的用户肯定会被登出,但您将被带到管理员登出页面。这不是您想要的,只是因为该页面上的登录链接,将您带到管理员登录屏幕(并且仅对具有<code>is_staff</code>权限的用户可用)。</p>
+
+<p>创建并打开 /<strong>locallibrary/templates/registration/logged_out.html</strong>。将下面的文字,复制到文档中:</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+&lt;p&gt;Logged out!&lt;/p&gt;
+
+&lt;a href="{% url 'login'%}"&gt;Click here to login again.&lt;/a&gt;
+{% endblock %}</pre>
+
+<p>这个模板非常简单。它只显示一条消息,通知您已登出,并提供一个链接,您可以点击此按钮,返回登录屏幕。如果再次回到登出 URL,您应该看到此页面:</p>
+
+<p><img alt="Library logout page v1" src="https://mdn.mozillademos.org/files/14103/library_logout.png" style="border-style: solid; border-width: 1px; display: block; height: 169px; margin: 0px auto; width: 385px;"></p>
+
+<h3 id="密码重置模板">密码重置模板</h3>
+
+<p>默认密码重置系统,使用电子邮件向用户发送重置链接。您需要创建表单,以获取用户的电子邮件地址,发送电子邮件,允许他们输入新密码,以及记录整个过程的完成时间。</p>
+
+<p>以下模板可作为起点。</p>
+
+<h4 id="密码重置表单">密码重置表单</h4>
+
+<p>这是用于获取用户电子邮件地址的表单(用于发送密码重置电子邮件)。创建 <strong>/locallibrary/templates/registration/password_reset_form.html</strong>,并为其提供以下内容:</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+{% block content %}
+
+&lt;form action="" method="post"&gt;{% csrf_token %}
+ {% if form.email.errors %} \{{ form.email.errors }} {% endif %}
+ &lt;p&gt;\{{ form.email }}&lt;/p&gt;
+ &lt;input type="submit" class="btn btn-default btn-lg" value="Reset password" /&gt;
+&lt;/form&gt;
+
+{% endblock %}
+</pre>
+
+<h4 id="密码重置完成">密码重置完成</h4>
+
+<p>收集您的电子邮件地址后,会显示此表单。创建 <strong>/locallibrary/templates/registration/password_reset_done.html</strong>,并为其提供以下内容:</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+{% block content %}
+&lt;p&gt;We've emailed you instructions for setting your password. If they haven't arrived in a few minutes, check your spam folder.&lt;/p&gt;
+{% endblock %}
+</pre>
+
+<h4 id="密码重置电子邮件">密码重置电子邮件</h4>
+
+<p>此模板提供 HTML 电子邮件的文本,其中包含我们将发送给用户的重置链接。创建 <strong>/locallibrary/templates/registration/password_reset_email.html</strong>,并为其提供以下内容:</p>
+
+<pre class="brush: html">Someone asked for password reset for email \{{ email }}. Follow the link below:
+\{{ protocol}}://\{{ domain }}{% url 'password_reset_confirm' uidb64=uid token=token %}
+</pre>
+
+<h4 id="密码重置确认">密码重置确认</h4>
+
+<p>点击密码重置电子邮件中的链接后,您可以在此页面输入新密码。创建 <strong>/locallibrary/templates/registration/password_reset_confirm.html</strong>,并为其提供以下内容:</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+
+{% block content %}
+
+ {% if validlink %}
+ &lt;p&gt;Please enter (and confirm) your new password.&lt;/p&gt;
+ &lt;form action="" method="post"&gt;
+ &lt;div style="display:none"&gt;
+ &lt;input type="hidden" value="\{{ csrf_token }}" name="csrfmiddlewaretoken"&gt;
+ &lt;/div&gt;
+ &lt;table&gt;
+ &lt;tr&gt;
+ &lt;td&gt;\{{ form.new_password1.errors }}
+ &lt;label for="id_new_password1"&gt;New password:&lt;/label&gt;&lt;/td&gt;
+ &lt;td&gt;\{{ form.new_password1 }}&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;\{{ form.new_password2.errors }}
+ &lt;label for="id_new_password2"&gt;Confirm password:&lt;/label&gt;&lt;/td&gt;
+ &lt;td&gt;\{{ form.new_password2 }}&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;tr&gt;
+ &lt;td&gt;&lt;/td&gt;
+ &lt;td&gt;&lt;input type="submit" value="Change my password" /&gt;&lt;/td&gt;
+ &lt;/tr&gt;
+ &lt;/table&gt;
+ &lt;/form&gt;
+ {% else %}
+ &lt;h1&gt;Password reset failed&lt;/h1&gt;
+ &lt;p&gt;The password reset link was invalid, possibly because it has already been used. Please request a new password reset.&lt;/p&gt;
+ {% endif %}
+
+{% endblock %}
+</pre>
+
+<h4 id="密码重置完成_2">密码重置完成</h4>
+
+<p>这是最后一个密码重置模板,显示该模板,以在密码重置成功时通知您。创建 <strong>/locallibrary/templates/registration/password_reset_complete.html</strong>,并为其提供以下内容:</p>
+
+<pre class="brush: html">{% extends "base_generic.html" %}
+{% block content %}
+
+&lt;h1&gt;The password has been changed!&lt;/h1&gt;
+&lt;p&gt;&lt;a href="{% url 'login' %}"&gt;log in again?&lt;/a&gt;&lt;/p&gt;
+
+{% endblock %}</pre>
+
+<h3 id="测试新的身份验证页面">测试新的身份验证页面</h3>
+
+<p>现在您已经添加了 URL 配置,并创建了所有模板,现在认证页面应该可以正常工作了!</p>
+
+<p>您可以尝试登录,然后使用以下 URL 登出超级用户帐户,来测试新的身份验证页面:</p>
+
+<ul>
+ <li><a href="http://127.0.0.1:8000/accounts/login/">http://127.0.0.1:8000/accounts/login/</a></li>
+ <li><a href="http://127.0.0.1:8000/accounts/logout/">http://127.0.0.1:8000/accounts/logout/</a></li>
+</ul>
+
+<p>您将能够从登录页面中的链接,测试密码重置功能。<strong>请注意,Django只会向已存储在其数据库中的地址(用户)发送重置电子邮件!</strong></p>
+
+<div class="note">
+<p><strong>注意</strong>: 密码重置系统,要求您的网站支持电子邮件,这超出了本文的范围,因此该部分<strong>将无法使用</strong>。要测试此功能,请将以下一行放在 settings.py 文件的末尾。这会记录发送到命令行控制台的所有电子邮件(因此您可以从命令行控制台,复制密码重置链接)。</p>
+
+<pre class="brush: python">EMAIL_BACKEND = 'django.core.mail.backends.console.EmailBackend'
+</pre>
+
+<p>有关更多信息,请参阅<a href="https://docs.djangoproject.com/en/2.0/topics/email/">发送电子邮件</a>(Django文档)。</p>
+</div>
+
+<h2 id="测试已验证身份的用户">测试已验证身份的用户</h2>
+
+<p>本节介绍如何根据用户是否登录,来有选择地控制用户看到的内容。</p>
+
+<h3 id="在模板中测试">在模板中测试</h3>
+
+<p>您可以使用<code>\{{ user }}</code>模板变量,以获取有关模板中,当前登录用户的信息(默认情况下,在我们在骨架中设置项目时,会将其添加到模板上下文中)。</p>
+
+<p>通常,您将首先针对 <code>\{{ user.is_authenticated }} </code>模板变量进行测试,以确定用户是否有资格查看特定内容。为了展示这一点,接下来我们将更新侧边栏,以在用户登出时,显示“登录”链接,如果他们已登录,则显示“登出”链接。</p>
+
+<p>打开基本模板(<strong>/locallibrary/catalog/templates/base_generic.html</strong>),并将以下文本,复制到侧边栏区块<code>sidebar</code>中,紧接在<code>endblock</code>模板标记之前。</p>
+
+<pre class="brush: html"> &lt;ul class="sidebar-nav"&gt;
+
+ ...
+
+ <strong>{% if user.is_authenticated %}</strong>
+ &lt;li&gt;User: <strong>\{{ user.get_username }}</strong>&lt;/li&gt;
+ &lt;li&gt;&lt;a href="{% url 'logout'%}?next=\{{request.path}}"&gt;Logout&lt;/a&gt;&lt;/li&gt;
+ <strong>{% else %}</strong>
+ &lt;li&gt;&lt;a href="{% url 'login'%}?next=\{{request.path}}"&gt;Login&lt;/a&gt;&lt;/li&gt;
+ <strong>{% endif %} </strong>
+ &lt;/ul&gt;</pre>
+
+<p>如您所见,我们使用 <code>if</code>-<code>else</code>-<code>endif</code>模板标签,根据 <code>\{{ user.is_authenticated }}</code> 是否为 true ,来有条件地显示文本。如果用户已通过身份验证,那么我们知道,我们拥有有效用户,因此我们会调用 <strong>\{{ user.get_username }} </strong>,来显示其名称。</p>
+
+<p>我们使用 <code>url</code>模板标记,和相应 URL 配置的名称,创建登录和登出链接 URL。另外请注意,我们如何将 “<code>?next=\{{request.path}}</code>附加到URL的末尾。这样做,是将包含当前页面地址(URL)的URL参数,添加到链接URL的末尾。用户成功登录/登出后,视图将使用此“下一个”值,将用户重定向,回到他们首次单击登录/登出链接的页面。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 试试吧!如果您在主页上,并单击侧栏中的“登录/登出”,在操作完成后,您应该返回到同一页面。</p>
+</div>
+
+<h3 id="在视图中测试">在视图中测试</h3>
+
+<p>如果您正在使用基于函数的视图,则限制访问函数的最简单方法,是将<code>login_required</code>装饰器,应用于您的视图函数,如下所示。如果用户已登录,则您的视图代码将正常执行。</p>
+
+<p>如果用户未登录,则会重定向到项目设置 (<code>settings.LOGIN_URL</code>)中定义的登录URL,并将当前绝对路径,作为URL参数("下一个"<code>next</code>)来传递。如果用户成功登录,则会返回到此页面,但这次会进行身份验证。</p>
+
+<pre class="brush: python">from django.contrib.auth.decorators import login_required
+
+@login_required
+def my_view(request):
+ ...</pre>
+
+<div class="note">
+<p><strong>注意:</strong> 您可以通过<code>request.user.is_authenticated</code>,测试手动执行类似的操作,但装饰器更方便!</p>
+</div>
+
+<p>同样,在基于类别的视图中,限制对登录用户的访问的最简单方法,是从<code>LoginRequiredMixin</code>派生。您需要在主视图类之前的超类列表中,首先声明此 mixin。</p>
+
+<pre class="brush: python">from django.contrib.auth.mixins import LoginRequiredMixin
+
+class MyView(LoginRequiredMixin, View):
+ ...</pre>
+
+<p>这与<code>login_required</code>装饰器,具有完全相同的重定向行为。如果用户未经过身份验证(<code>login_url</code>),还可以指定一个替代位置,以将用户重定向到该位置,并使用URL参数名称,而不是“<code>next</code>”,来插入当前绝对路径(<code>redirect_field_name</code>)。</p>
+
+<pre class="brush: python">class MyView(LoginRequiredMixin, View):
+ login_url = '/login/'
+ redirect_field_name = 'redirect_to'
+</pre>
+
+<p>有关其他详细信息,请查看<a href="https://docs.djangoproject.com/en/2.0/topics/auth/default/#limiting-access-to-logged-in-users">Django</a>文档。</p>
+
+<h2 id="示例_-_列出当前用户的书本">示例 - 列出当前用户的书本</h2>
+
+<p>现在我们知道,如何将页面限制为特定用户,让我们为当前用户借阅的书本,创建一个视图。</p>
+
+<p>不幸的是,我们还没有办法让用户借书!因此,在我们创建图书清单之前,我们首先会扩展<code>BookInstance</code>模型,以支持借阅的概念,并使用Django Admin应用程序,借给测试用户一些书。</p>
+
+<h3 id="模型">模型</h3>
+
+<p>首先,我们必须让用户可以借用书本实例<code>BookInstance</code>(我们已经拥有状态<code>status</code>和还书日期<code>due_back</code>,但这个模型和用户之间,没有任何关联。我们将使用<code>ForeignKey</code>(一对多)字段,来创建一个。我们还需要一个简单的机制,来测试借出的书是否过期。</p>
+
+<p>打开 <strong>catalog/models.py</strong>,然后从 <code>django.contrib.auth.models</code>  导入 <code>User</code>模型(在文件顶部的上一个导入行的正下方添加它,好让后续代码可以使用 <code>User</code>):</p>
+
+<pre class="brush: python">from django.contrib.auth.models import User
+</pre>
+
+<p>接下来将借用者字段<code>borrower</code>,添加到<code>BookInstance</code>模型:</p>
+
+<pre class="brush: python">borrower = models.ForeignKey(User, on_delete=models.SET_NULL, null=True, blank=True)
+</pre>
+
+<p>当我们在这里,让我们添加一个属性,我们可以从模板中调用它,来判断特定的书本实例是否过期。虽然我们可以在模板本身中计算这一点,但使用如下所示的<a href="https://docs.python.org/3/library/functions.html#property">属性</a>会更有效率。将其添加到文件的底部:</p>
+
+<pre class="brush: python">from datetime import date
+
+@property
+def is_overdue(self):
+ if self.due_back and date.today() &gt; self.due_back:
+ return True
+ return False</pre>
+
+<div class="note">
+<p><strong>注意</strong>: 在进行比较之前,我们首先验证<code>due_back</code>是否为空。空的<code>due_back</code>字段,会导致Django抛出错误,而不是显示页面:空值不具有可比性。这不是我们希望用户体验到的东西!</p>
+</div>
+
+<p>现在我们已经更新了模型,我们需要对项目进行新的迁移,然后应用这些迁移:</p>
+
+<pre class="brush: bash">python3 manage.py makemigrations
+python3 manage.py migrate
+</pre>
+
+<h3 id="管理员">管理员</h3>
+
+<p>现在打开 <strong>catalog/admin.py</strong>,并将<code>borrower</code>字段,添加到<code>BookInstanceAdmin</code>类别中的<code>list_display</code>和<code>fieldsets</code>,如下所示。这将使该字段在Admin部分中可见,以便我们可以在需要时将<code>User</code>分配给<code>BookInstance</code>。</p>
+
+<pre class="brush: python">@admin.register(BookInstance)
+class BookInstanceAdmin(admin.ModelAdmin):
+    list_display = ('book', 'status'<strong>, 'borrower'</strong>, 'due_back', 'id')
+    list_filter = ('status', 'due_back')
+
+    fieldsets = (
+        (None, {
+            'fields': ('book','imprint', 'id')
+        }),
+        ('Availability', {
+            'fields': ('status', 'due_back'<strong>,'borrower'</strong>)
+        }),
+    )</pre>
+
+<h3 id="借几本书">借几本书</h3>
+
+<p>现在可以将书本借给特定用户,然后借出一些<code>BookInstance</code>记录。将他们的借用字段<code>borrowed</code>,设置为您的测试用户,将状态<code>status</code>设置为 “On loan”,并在将来和过去设置截止日期。</p>
+
+<div class="note">
+<p><strong>注意</strong>: 我们不会一步一步说明这个流程,因为您已经知道如何使用管理站点!</p>
+</div>
+
+<h3 id="在借书视图">在借书视图</h3>
+
+<p>现在我们将添加一个视图,以获取已经借给当前用户的所有书本列表。我们将使用我们熟悉的、基于类的通用类列表视图,但这次我们还将导入并派生自<code>LoginRequiredMixin</code>,以便只有登录用户才能调用此视图。我们还将选择声明<code>template_name</code>,而不是使用默认值,因为我们最终可能会有几个不同的 BookInstance 记录列表,其中包含不同的视图和模板。</p>
+
+<p>将以下内容添加到 catalog/views.py:</p>
+
+<pre class="brush: python">from django.contrib.auth.mixins import LoginRequiredMixin
+
+class LoanedBooksByUserListView(LoginRequiredMixin,generic.ListView):
+ """
+ Generic class-based view listing books on loan to current user.
+ """
+ model = BookInstance
+ template_name ='catalog/bookinstance_list_borrowed_user.html'
+ paginate_by = 10
+
+ def get_queryset(self):
+ return BookInstance.objects.filter(borrower=self.request.user).filter(status__exact='o').order_by('due_back')</pre>
+
+<p>为了将查询,限制为当前用户的<code>BookInstance</code>对象,我们重新实现了<code>get_queryset()</code>,如上所示。请注意,“o”是表示借出当中“on loan”的存储代码,我们按<code>due_back</code>日期排序,以便首先显示最旧的项目。</p>
+
+<h3 id="借书的_URL_设置">借书的 URL 设置</h3>
+
+<p>现在打开<strong>/catalog/urls.py</strong>,并添加指向上面视图的<code>path()</code>(您只需将下面的文本复制到文件末尾)。</p>
+
+<pre class="brush: python">urlpatterns += [
+ path('mybooks/', views.LoanedBooksByUserListView.as_view(), name='my-borrowed'),
+]</pre>
+
+<h3 id="借书的模板">借书的模板</h3>
+
+<p>现在,我们需要为此页面添加一个模板。首先,创建模板文件<strong>/catalog/templates/catalog/bookinstance_list_borrowed_user.html</strong>,并为其提供以下内容:</p>
+
+<pre class="brush: python">{% extends "base_generic.html" %}
+
+{% block content %}
+ &lt;h1&gt;Borrowed books&lt;/h1&gt;
+
+ {% if bookinstance_list %}
+ &lt;ul&gt;
+
+ {% for bookinst in bookinstance_list %}
+ &lt;li class="{% if bookinst.is_overdue %}text-danger{% endif %}"&gt;
+ &lt;a href="{% url 'book-detail' bookinst.book.pk %}"&gt;\{{bookinst.book.title}}&lt;/a&gt; (\{{ bookinst.due_back }})
+ &lt;/li&gt;
+ {% endfor %}
+ &lt;/ul&gt;
+
+ {% else %}
+ &lt;p&gt;There are no books borrowed.&lt;/p&gt;
+ {% endif %}
+{% endblock %}</pre>
+
+<p>此模板与我们之前为 <code>Book </code>和 <code>Author</code>对象创建的模板非常相似。这里唯一新的东西,是我们检查在模型中添加的方法(<code>bookinst.is_overdue</code>),并使用它,来更改过期项目的颜色。</p>
+
+<p>当开发服务器运行时,您现在应该能够在浏览器中,查看登录用户的列表,网址为<a href="http://127.0.0.1:8000/catalog/mybooks/">http://127.0.0.1:8000/catalog/mybooks/</a>。在您的用户登录并登出后,尝试此操作(在第二种情况下,您应该被重定向到登录页面)。</p>
+
+<p> </p>
+
+<h3 id="将列表添加到侧栏">将列表添加到侧栏</h3>
+
+<p>最后一步,是将这个新页面的链接,添加到侧边栏中。我们将把它放在我们为登录用户显示其他信息的同一部分。</p>
+
+<p>打开基本模板(<strong>/locallibrary/catalog/templates/base_generic.html</strong>),并将粗体标识的那一行,添加到侧边栏区块,如下所示。</p>
+
+<pre class="brush: python"> &lt;ul class="sidebar-nav"&gt;
+ {% if user.is_authenticated %}
+ &lt;li&gt;User: \{{ user.get_username }}&lt;/li&gt;
+<strong> &lt;li&gt;&lt;a href="{% url 'my-borrowed' %}"&gt;My Borrowed&lt;/a&gt;&lt;/li&gt;</strong>
+ &lt;li&gt;&lt;a href="{% url 'logout'%}?next=\{{request.path}}"&gt;Logout&lt;/a&gt;&lt;/li&gt;
+ {% else %}
+ &lt;li&gt;&lt;a href="{% url 'login'%}?next=\{{request.path}}"&gt;Login&lt;/a&gt;&lt;/li&gt;
+ {% endif %}
+ &lt;/ul&gt;
+</pre>
+
+<h3 id="它看起来是什么样子的?">它看起来是什么样子的?</h3>
+
+<p>当任何用户登录时,他们会在侧栏中看到 My Borrowed 链接,并显示如下所示的书本列表(第一本书没有截止日期,这是我们希望在以后的教程中修复的错误!) 。</p>
+
+<p><img alt="Library - borrowed books by user" src="https://mdn.mozillademos.org/files/14105/library_borrowed_by_user.png" style="border-style: solid; border-width: 1px; display: block; height: 215px; margin: 0px auto; width: 530px;"></p>
+
+<h2 id="权限">权限</h2>
+
+<p>权限与模型相关联,并定义可以由具有权限的用户,在模型实例上执行的操作。默认情况下,Django会自动为所有模型提供添加,更改和删除权限,这允许具有权限的用户,通过管理站点执行相关操作。您可以为模型定义自己的权限,并将其授予特定用户。您还可以更改与同一模型的不同实例关联的权限。</p>
+
+<p>对于视图和模板中的权限测试,非常类似于对身份验证状态的测试(实际上,测试权限也会测试身份验证)。</p>
+
+<h3 id="模型_2">模型</h3>
+
+<p>在模型“<code>class Meta</code>”部分上,使用 <code>permissions</code>字段,完成权限定义。您可以在元组中指定所需的权限,每个权限本身,都在包含权限名称和权限显示值的嵌套元组中被定义。例如,我们可能会定义一个权限,允许用户标记已归还的图书,如下所示:</p>
+
+<pre class="brush: python">class BookInstance(models.Model):
+ ...
+  class Meta:
+  ...
+<strong> permissions = (("can_mark_returned", "Set book as returned"),) </strong> </pre>
+
+<p>然后,我们可以将权限分配给管理站点中的图书管理员“Librarian”分组。打开 <strong>catalog/models.py</strong>,然后添加权限,如上所示。您需要重新运行迁移(调用 <code>python3 manage.py makemigrations</code> 和 <code>python3 manage.py migrate</code>),以适当地更新数据库。</p>
+
+<p> </p>
+
+<h3 id="模板">模板</h3>
+
+<p>当前用户的权限,存在名为 <code>\{{ perms }}</code>的模板变量中。您可以使用关联的Django “app” 中的特定变量名,来检查当前用户是否具有特定权限 - 例如,如果用户具有此权限,则 <code>\{{ perms.catalog.can_mark_returned }}</code>将为True,否则为False。我们通常使用模板标记 <code>{% if %}</code> 测试权限,如下所示:</p>
+
+<pre class="brush: python">{% if perms.catalog.<code>can_mark_returned</code> %}
+ &lt;!-- We can mark a BookInstance as returned. --&gt;
+  &lt;!-- Perhaps add code to link to a "book return" view here. --&gt;
+{% endif %}
+</pre>
+
+<h3 id="视图">视图</h3>
+
+<p>在功能视图中,可以使用 <code>permission_required</code>装饰器,或在基于类别的视图中,使用 <code>PermissionRequiredMixin</code>测试权限。模式和行为与登录身份验证相同,但当然您可能需要添加多个权限。</p>
+
+<p>功能视图装饰器:</p>
+
+<pre class="brush: python">from django.contrib.auth.decorators import permission_required
+
+@permission_required('catalog.<code>can_mark_returned</code>')
+@permission_required('catalog.<code>can_edit</code>')
+def my_view(request):
+ ...</pre>
+
+<p>基于类别视图的权限要求 mixin。</p>
+
+<pre class="brush: python">from django.contrib.auth.mixins import PermissionRequiredMixin
+
+class MyView(PermissionRequiredMixin, View):
+ permission_required = 'catalog.<code>can_mark_returned</code>'
+ # Or multiple permissions
+ permission_required = ('catalog.<code>can_mark_returned</code>', 'catalog.can_edit')
+ # Note that 'catalog.can_edit' is just an example
+ # the catalog application doesn't have such permission!</pre>
+
+<h3 id="示例">示例</h3>
+
+<p>我们不会在这里更新 LocalLibrary;也许在下一个教程中!</p>
+
+<h2 id="挑战自己"><a id="Challenge_yourself" name="Challenge_yourself"></a>挑战自己</h2>
+
+<p>在本文前面,我们向您展示了,如何为当前用户创建一个页面,列出他们借用的书本。现在的挑战,是创建一个只对图书馆员可见的类似页面,它显示所有借用的书本,其中包括每个借用人的名字。</p>
+
+<p>您应该能够遵循与其他视图相同的模式。主要区别在于,您需要将视图限制为仅限图书馆员。您可以根据用户是否是工作人员(函数装饰器:<code>staff_member_required</code>,模板变量:<code>user.is_staff</code>)来执行此操作,但我们建议您改为使用<code>can_mark_returned</code>权限,和 <code>PermissionRequiredMixin</code>,如上一节所述。</p>
+
+<div class="warning">
+<p><strong>重要</strong>: 请记住,不要使用超级用户进行基于权限的测试(即使尚未定义权限,权限检查也会对超级用户返回 true)。而是要创建一个图书管理员用户,并添加所需的功能。</p>
+</div>
+
+<p>完成后,您的页面应该类似于下面的屏幕截图。</p>
+
+<p><img alt="All borrowed books, restricted to librarian" src="https://mdn.mozillademos.org/files/14115/library_borrowed_all.png" style="border-style: solid; border-width: 1px; display: block; height: 283px; margin: 0px auto; width: 500px;"></p>
+
+<ul>
+</ul>
+
+<h2 id="总结">总结</h2>
+
+<p>做的太好了 — 你已经创造了一个网站,图书馆用户可以登入并检视他们拥有的内容,图书管理员(有正确的授权)可以检视所有借出的书本以及借阅者。目前,我们仍然只是查看内容,但是当您想要开始修改和添加数据时,会使用相同的原则和技术。</p>
+
+<p>在我们的下一篇文章,我们将介绍如何使用Django 表单,收集使用者输入,然后开始修改我们储存的一些资料。</p>
+
+<h2 id="也可以参考">也可以参考</h2>
+
+<ul>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/auth/">Django中的用户授权</a> (Django 文档)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/auth/default//">使用 Django 授权系统(默认) </a>(Django 文档)</li>
+ <li><a href="https://docs.djangoproject.com/en/2.0/topics/class-based-views/intro/#decorating-class-based-views">介绍从基于类别的视图 &gt; 到使用装饰器的基于类别的视图</a> (Django 文档)</li>
+</ul>
+
+<p>{{PreviousMenuNext("Learn/Server-side/Django/Sessions", "Learn/Server-side/Django/Forms", "Learn/Server-side/Django")}}</p>
+
+<p> </p>
+
+<h2 id="本教程文档">本教程文档</h2>
+
+<ul>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Introduction">Django 介绍</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/development_environment">架设 Django 开发环境</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Tutorial_local_library_website">Django 教程: The Local Library website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/skeleton_website">Django 教程 2: Creating a skeleton website</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Models">Django 教程 3: Using models</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Admin_site">Django 教程 4: Django admin site</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Home_page">Django 教程 5: Creating our home page</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Generic_views">Django 教程 6: Generic list and detail views</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Sessions">Django 教程 7: Sessions framework</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Authentication">Django 教程 8: User authentication and permissions</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Forms">Django 教程 9: Working with forms</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Testing">Django 教程 10: Testing a Django web application</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/Deployment">Django 教程 11: Deploying Django to production</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/web_application_security">Django 网页应用安全</a></li>
+ <li><a href="/en-US/docs/Learn/Server-side/Django/django_assessment_blog">DIY Django 微博客</a></li>
+</ul>
+
+<p> </p>