《Web接口开发与自动化测试基于Python语言》–第3章

《Web接口开发与自动化测试基于Python语言》–读书笔记

第3章

3.1 来写个登录功能

修改/guest/sign/templates/index.html:

<span style="color:#000000"><code class="language-html"><span style="color:#4f4f4f"><!DOCTYPE html></span>
<span style="color:#006666"><<span style="color:#4f4f4f">html</span>></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">head</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">meta</span> <span style="color:#4f4f4f">charset</span>=<span style="color:#009900">"utf-8"</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">title</span>></span>Django Page<span style="color:#006666"></<span style="color:#4f4f4f">title</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">head</span>></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">body</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">h1</span>></span>发布会管理<span style="color:#006666"></<span style="color:#4f4f4f">h1</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">form</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">input</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"username"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"text"</span> <span style="color:#4f4f4f">placeholder</span>=<span style="color:#009900">"username"</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">br</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">input</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"password"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"password"</span> <span style="color:#4f4f4f">placeholder</span>=<span style="color:#009900">"password"</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">br</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">button</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"btn"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"submit"</span>></span>登录<span style="color:#006666"></<span style="color:#4f4f4f">button</span>></span>
        <span style="color:#006666"></<span style="color:#4f4f4f">form</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">body</span>></span>
<span style="color:#006666"></<span style="color:#4f4f4f">html</span>></span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

思考如下问题:

  • 当用户输入用户名密码并点击登录按钮后,登录表单form中的数据以何种方式提交GET/POST到服务器端?

  • Django如何验证用户名密码的正确性?

  • 如果验证成功应该如何处理?

  • 如果验证失败应该如何处理?

下面一一解答上述的疑问。

GET与POST请求

GET:从指定的资源请求数据;

POST:向指定的资源提交要被处理的数据。

GET请求

get方法传递参数,修改index.html,给form表单增加属性method=”get”:

<span style="color:#000000"><code class="language-html">        <span style="color:#006666"><<span style="color:#4f4f4f">form</span> <span style="color:#4f4f4f">method</span>=<span style="color:#009900">"get"</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">input</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"username"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"text"</span> <span style="color:#4f4f4f">placeholder</span>=<span style="color:#009900">"username"</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">br</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">input</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"password"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"password"</span> <span style="color:#4f4f4f">placeholder</span>=<span style="color:#009900">"password"</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">br</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">button</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"btn"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"submit"</span>></span>登录<span style="color:#006666"></<span style="color:#4f4f4f">button</span>></span>
        <span style="color:#006666"></<span style="color:#4f4f4f">form</span>></span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5

输入用户名密码admin/admin123,点击登录按钮,浏览器的URL地址栏变为:

http://127.0.0.1:8000/index/?username=admin&password=admin123

get方法会将用户提交的数据添加到URL地址中,路径后面跟问号?,其中username为HTML代码中<\input>标签的name属性值(name=”username”),admin是用户在用户名输入框中填写的用户名,多个参数之间用&符号分隔。

POST请求

修改method=”post”,再次输入用户名密码并点击登录按钮,页面提示403错误:

这里写图片描述

建议:仔细阅读错误帮助信息有助于解决问题。

CSRF漏洞:跨站请求伪造漏洞,Cross-Site Request Forgery。

Django针对CSRF的保护措施是在生成的每个表单中放置一个自动生成的令牌,通过这个令牌判断POST请求是否来自同一个网站。

还是修改index.html,增加csrf信息,使用Django模板中的标签:{% csrf_token %}

再次刷新页面并使用浏览器的F12功能查看POST请求具体信息:

<span style="color:#000000"><code><span style="color:#000000">Form</span> <span style="color:#000000">Data</span>
<span style="color:#000000">username</span><span style="color:#000000">:admin</span>
<span style="color:#000000">password</span><span style="color:#000000">:admin123</span>
<span style="color:#000000">csrfmiddlewaretoken</span><span style="color:#000000">:CEueSfB9S4bJQoW9x</span>……<span style="color:#000000">n0OvGDAhWC9rIH2S7PegwZew</span></code></span>
  • 1
  • 2
  • 3
  • 4

可以看到当页面向Django服务器发送POST请求的时候,服务器端还要求客户端加上csrfmiddlewaretoken字段,该字段的值为当前会话ID加上一个密钥的散列值。

如果想忽略掉该检查,可以修改/guest/settings.py文件的MIDDLEWARE:

<span style="color:#000000"><code class="language-python">MIDDLEWARE = [
    <span style="color:#009900">'django.middleware.security.SecurityMiddleware'</span>,
    <span style="color:#009900">'django.contrib.sessions.middleware.SessionMiddleware'</span>,
    <span style="color:#009900">'django.middleware.common.CommonMiddleware'</span>,
    <span style="color:#880000">#'django.middleware.csrf.CsrfViewMiddleware',</span>
    <span style="color:#009900">'django.contrib.auth.middleware.AuthenticationMiddleware'</span>,
    <span style="color:#009900">'django.contrib.messages.middleware.MessageMiddleware'</span>,
    <span style="color:#009900">'django.middleware.clickjacking.XFrameOptionsMiddleware'</span>,
]</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

处理登录请求

Django服务器如何接收请求的数据并加以处理呢? 
还是修改index.html,在form表单中增加action属性来指定提交的路径:

<form method="post" action="/login_action/">

这样,当我们再次点击登录按钮,将由http://127.0.0.1:8000/login_action/路径来提交登录请求。 
我们再来处理login_action,先修改/guest/urls.py文件增加login_action的路由:

<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> sign <span style="color:#000088">import</span> views

urlpatterns = [
    url(<span style="color:#009900">r'^login_action/$'</span>, views.login_action)
]</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5

然后修改视图/guest/sign/views.py文件,增加login_action函数来处理验证信息:

<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> django.http <span style="color:#000088">import</span> HttpResponse
<span style="color:#000088">from</span> django.shortcuts <span style="color:#000088">import</span> render

<span style="color:#880000"># Create your views here.</span>
<span style="color:#000088">def</span> <span style="color:#009900">index</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#000088">return</span> render(request, <span style="color:#009900">"index.html"</span>)

<span style="color:#880000"># 登录动作</span>
<span style="color:#000088">def</span> <span style="color:#009900">login_action</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#000088">if</span> request.method == <span style="color:#009900">'POST'</span>:
        username = request.POST.get(<span style="color:#009900">'username'</span>, <span style="color:#009900">''</span>)
        password = request.POST.get(<span style="color:#009900">'password'</span>, <span style="color:#009900">''</span>)
        <span style="color:#000088">if</span> username == <span style="color:#009900">'admin'</span> <span style="color:#000088">and</span> password == <span style="color:#009900">'admin123'</span>:
            <span style="color:#000088">return</span> HttpResponse(<span style="color:#009900">"Login Success!"</span>)
        <span style="color:#000088">else</span>:
            <span style="color:#000088">return</span> render(request, <span style="color:#009900">'index.html'</span>, {<span style="color:#009900">'error'</span>:<span style="color:#009900">'username or password error!'</span>})</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

对上述代码进行分析:

  1. 通过request.method得到客户端的请求方式,并判断是否为POST方式;

  2. 通过request.POST来获取POST请求数据,通过.get()方法获取username、password,如果参数为空,则返回一个空的字符串;

  3. 通过if语句判断username、password是否为admin/admin123,如果是则通过HttpResponse类返回字符串Login Success!,否则通过render返回index.html登录页面,并且同时返回错误提示的字典。

注意:

客户端发送的请求信息全部包含在request中,如何获取request中的信息,可参考: 
https://docs.djangoproject.com/en/1.10/ref/request-response/

由于views.py里的login_action函数定义了登录失败时的错误提示,所以要同步修改index.html,增加错误信息展示的代码,修改如下:

<span style="color:#000000"><code class="language-html">            <span style="color:#006666"><<span style="color:#4f4f4f">input</span> <span style="color:#4f4f4f">name</span>=<span style="color:#009900">"password"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"password"</span> <span style="color:#4f4f4f">placeholder</span>=<span style="color:#009900">"password"</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">br</span>></span>
            {{ error }}<span style="color:#006666"><<span style="color:#4f4f4f">br</span>></span>
            <span style="color:#006666"><<span style="color:#4f4f4f">button</span> <span style="color:#4f4f4f">id</span>=<span style="color:#009900">"btn"</span> <span style="color:#4f4f4f">type</span>=<span style="color:#009900">"submit"</span>></span>登录<span style="color:#006666"></<span style="color:#4f4f4f">button</span>></span></code></span>
  • 1
  • 2
  • 3

这里依然是使用了Django模板的标签功能,它对应render返回字典中的key,即“error”,在登录失败的页面中显示对应的value,即“username or password error!”。

刷新/index/查看登录成功和登录失败的效果。

登录成功页

当登录验证通过后,就需要其他HTML页面来展示下一步内容。

根据本例发布会签到系统,登录成功后应进入发布会管理页面,创建/guest/sign/templates/event_manage.html

<span style="color:#000000"><code class="language-html"><span style="color:#4f4f4f"><!DOCTYPE html></span>
<span style="color:#006666"><<span style="color:#4f4f4f">html</span>></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">head</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">meta</span> <span style="color:#4f4f4f">charset</span>=<span style="color:#009900">"utf-8"</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">title</span>></span>Event Manage Page<span style="color:#006666"></<span style="color:#4f4f4f">title</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">head</span>></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">body</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">h1</span>></span>Login Success!<span style="color:#006666"></<span style="color:#4f4f4f">h1</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">body</span>></span>
<span style="color:#006666"></<span style="color:#4f4f4f">html</span>></span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

同时修改视图/guest/sign/views.py文件增加event_manage函数:

<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> django.http <span style="color:#000088">import</span> HttpResponse, HttpResponseRedirect

<span style="color:#880000"># 登录动作</span>
<span style="color:#000088">def</span> <span style="color:#009900">login_action</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#000088">if</span> request.method == <span style="color:#009900">'POST'</span>:
        username = request.POST.get(<span style="color:#009900">'username'</span>, <span style="color:#009900">''</span>)
        password = request.POST.get(<span style="color:#009900">'password'</span>, <span style="color:#009900">''</span>)
        <span style="color:#000088">if</span> username == <span style="color:#009900">'admin'</span> <span style="color:#000088">and</span> password == <span style="color:#009900">'admin123'</span>:
            <span style="color:#880000">#return HttpResponse("Login Success!")</span>
            <span style="color:#000088">return</span> HttpResponseRedirect(<span style="color:#009900">'/event_manage/'</span>)
        <span style="color:#000088">else</span>:
            <span style="color:#000088">return</span> render(request, <span style="color:#009900">'index.html'</span>, {<span style="color:#009900">'error'</span>:<span style="color:#009900">'username or password error!'</span>})

<span style="color:#880000"># 发布会管理</span>
<span style="color:#000088">def</span> <span style="color:#009900">event_manage</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#000088">return</span> render(request, <span style="color:#009900">"event_manage.html"</span>)</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

注意: HttpResponseRedirect类,它可以对路径进行重定向,从而将登录成功之后的请求指向/event_mange/目录,即http://127.0.0.1:8000/event_manage/

最后修改/guest/urls.py文件增加event_mange路由:

<span style="color:#000000"><code class="language-python">urlpatterns = [
    url(<span style="color:#009900">r'^admin/'</span>, admin.site.urls),
    url(<span style="color:#009900">r'^index/$'</span>, views.index),
    url(<span style="color:#009900">r'^login_action/$'</span>, views.login_action),
    url(<span style="color:#009900">r'^event_manage/$'</span>, views.event_manage),
]</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

3.2 Cookie和Session

通过在登录成功后,增加登录成功页显示“嘿,admin 你好!”,来研究Cookie和Session。

Cookie机制: Cookie分发通过扩展HTTP协议来实现,服务器通过在HTTP的响应头中加上一行特殊的指示来提示浏览器按照指示生成相应的Cookie。浏览器检查所有存储的Cookie,如果某个Cookie所声明的作用范围大于等于将要请求的资源所在的位置,则把该Cookie附在请求资源的HTTP请求头上发给服务器。

Session机制: Session机制是一种服务器端的机制,服务器使用一种类似于散列表的结构来保存信息。

Cookie的使用

这里我调整了下顺序,感觉按作者之前提到的Django的工作顺序来讲解代码的修改更合理:

  • 首先,修改/guest/urls.py文件,由于还是使用上面提到的登录成功后的展示页面,所以依然使用event_mange路由,无需修改;

  • 其次,修改/guest/sign/views.py文件,添加Cookie处理相关代码:

<span style="color:#000000"><code class="language-python"><span style="color:#880000"># 登录动作</span>
<span style="color:#000088">def</span> <span style="color:#009900">login_action</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#000088">if</span> request.method == <span style="color:#009900">'POST'</span>:
        username = request.POST.get(<span style="color:#009900">'username'</span>, <span style="color:#009900">''</span>)
        password = request.POST.get(<span style="color:#009900">'password'</span>, <span style="color:#009900">''</span>)
        <span style="color:#000088">if</span> username == <span style="color:#009900">'admin'</span> <span style="color:#000088">and</span> password == <span style="color:#009900">'admin123'</span>:
            <span style="color:#880000">#return HttpResponse("Login Success!")</span>
            <span style="color:#880000">#return HttpResponseRedirect('/event_manage/')</span>
            response = HttpResponseRedirect(<span style="color:#009900">'/event_manage/'</span>)
            response.set_cookie(<span style="color:#009900">'user'</span>, username, <span style="color:#006666">3600</span>) <span style="color:#880000"># 添加浏览器Cookie</span>
            <span style="color:#000088">return</span> response
        <span style="color:#000088">else</span>:
            <span style="color:#000088">return</span> render(request, <span style="color:#009900">'index.html'</span>, {<span style="color:#009900">'error'</span>:<span style="color:#009900">'username or password error!'</span>})

<span style="color:#880000"># 发布会管理</span>
<span style="color:#000088">def</span> <span style="color:#009900">event_manage</span><span style="color:#4f4f4f">(request)</span>:
    username = request.COOKIES.get(<span style="color:#009900">'user'</span>, <span style="color:#009900">''</span>) <span style="color:#880000"># 读取浏览器Cookie</span>
    <span style="color:#000088">return</span> render(request, <span style="color:#009900">"event_manage.html"</span>, {<span style="color:#009900">"user"</span>:username})</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18

讲解上述代码,当用户登录成功后,在跳转到event_mange视图函数的过程中,通过set_cookie()方法向浏览器中添加Cookie信息。

set_cookie()方法传递了三个参数:user,用于表示写入浏览器的Cookie名;username,是由用户在登录页面上输入的用户名即admin;3600,是用于设置Cookie信息在浏览器中的保持时间,单位为秒。

在event_mange视图函数中,通过request.COOKIES来读取Cookie名为“user”的值,并且通过render将它和event_mange.html页面一起返回。

  • 最后,修改/guest/sign/templates/event_manage.html文件,添加<\div>标签来显示用户名:
<span style="color:#000000"><code class="language-html"><span style="color:#4f4f4f"><!DOCTYPE html></span>
<span style="color:#006666"><<span style="color:#4f4f4f">html</span>></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">head</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">meta</span> <span style="color:#4f4f4f">charset</span>=<span style="color:#009900">"utf-8"</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">title</span>></span>Event Manage Page<span style="color:#006666"></<span style="color:#4f4f4f">title</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">head</span>></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">div</span> <span style="color:#4f4f4f">style</span>=<span style="color:#009900">"float:right;"</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">a</span>></span>嘿!{{ user }} 欢迎<span style="color:#006666"></<span style="color:#4f4f4f">a</span>></span><span style="color:#006666"><<span style="color:#4f4f4f">hr</span>/></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">div</span>></span>
    <span style="color:#006666"><<span style="color:#4f4f4f">body</span>></span>
        <span style="color:#006666"><<span style="color:#4f4f4f">h1</span>></span>Login Success!<span style="color:#006666"></<span style="color:#4f4f4f">h1</span>></span>
    <span style="color:#006666"></<span style="color:#4f4f4f">body</span>></span>
<span style="color:#006666"></<span style="color:#4f4f4f">html</span>></span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

注意: 这里仍使用模板标签,user将会由views.py中的event_mange函数获取的username所代替。

最后重新登录查看效果,并且通过浏览器的F12功能查看POST请求的头部中Cookie信息为:

Cookie:csrftoken=djsNd8BDErmFNZVXqg……9nZrDez5PgQFIaVLcVHhHcA1; user=admin

Session的使用

Cookie虽然好但是存在安全性问题,不法分子可能会篡改Cookie获取想要的数据。

Session相比要安全很多,在Django中使用Session和Cookie类似,只需要将Cookie的几步操作替换为Session操作即可。

只需要修改/guest/sign/views.py文件:

<span style="color:#000000"><code class="language-python"><span style="color:#880000"># 登录动作</span>
<span style="color:#000088">def</span> <span style="color:#009900">login_action</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#000088">if</span> request.method == <span style="color:#009900">'POST'</span>:
        username = request.POST.get(<span style="color:#009900">'username'</span>, <span style="color:#009900">''</span>)
        password = request.POST.get(<span style="color:#009900">'password'</span>, <span style="color:#009900">''</span>)
        <span style="color:#000088">if</span> username == <span style="color:#009900">'admin'</span> <span style="color:#000088">and</span> password == <span style="color:#009900">'admin123'</span>:
            <span style="color:#880000">#return HttpResponse("Login Success!")</span>
            <span style="color:#880000">#return HttpResponseRedirect('/event_manage/')</span>
            response = HttpResponseRedirect(<span style="color:#009900">'/event_manage/'</span>)
            <span style="color:#880000">#response.set_cookie('user', username, 3600) # 添加浏览器Cookie</span>
            request.session[<span style="color:#009900">'user'</span>] = username           <span style="color:#880000"># 将session信息添加到浏览器</span>
            <span style="color:#000088">return</span> response
        <span style="color:#000088">else</span>:
            <span style="color:#000088">return</span> render(request, <span style="color:#009900">'index.html'</span>, {<span style="color:#009900">'error'</span>:<span style="color:#009900">'username or password error!'</span>})

<span style="color:#880000"># 发布会管理</span>
<span style="color:#000088">def</span> <span style="color:#009900">event_manage</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#880000">#username = request.COOKIES.get('user', '') # 读取浏览器Cookie</span>
    username = reuqest.session.get(<span style="color:#009900">'user'</span>, <span style="color:#009900">''</span>)  <span style="color:#880000"># 读取浏览器session</span>
    <span style="color:#000088">return</span> render(request, <span style="color:#009900">"event_manage.html"</span>, {<span style="color:#009900">"user"</span>:username})</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20

再次刷新页面登录,得到了如下错误:

<span style="color:#000000"><code class="language-html">OperationalError at /login_action/
no such table: django_session</code></span>
  • 1
  • 2

为什么会有此错误?

原因:使用Session从Web服务器来记录用户信息,就应该有存放用户sessionid对应信息的地方才行,即需要在数据库中创建用于存放sessionid的表。

Django已经准备好这些常用表,只需要使用如下命令来生成即可:

<span style="color:#000000"><code>root<span style="color:#4f4f4f">@TEST</span><span style="color:#009900">:/home/test/guest</span><span style="color:#880000"># python manage.py migrate</span>
<span style="color:#009900">Operations</span> to <span style="color:#009900">perform:</span>
  <span style="color:#009900">Apply</span> all <span style="color:#009900">migrations:</span> admin, auth, contenttypes, sessions
<span style="color:#009900">Running</span> <span style="color:#009900">migrations:</span>
  <span style="color:#009900">Applying</span> contenttypes.<span style="color:#006666">0001_</span>initial... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">0001_</span>initial... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> admin.<span style="color:#006666">0001_</span>initial... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> admin.<span style="color:#006666">0002_</span>logentry_remove_auto_add... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> contenttypes.<span style="color:#006666">0002_</span>remove_content_type_name... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">0002_</span>alter_permission_name_max_length... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">0003_</span>alter_user_email_max_length... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">0004_</span>alter_user_username_opts... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">0005_</span>alter_user_last_login_null... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">0006_</span>require_contenttypes_0002... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">0007_</span>alter_validators_add_error_messages... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> auth.<span style="color:#006666">000</span>8_alter_user_username_max_length... <span style="color:#009900">OK</span>
  <span style="color:#009900">Applying</span> sessions.<span style="color:#006666">0001_</span>initial... <span style="color:#009900">OK</span></code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

migrate命令可进行数据迁移,那么问题来了,我们并没有设置数据库,为什么已经生成了数据库表呢? 
这是因为Django默认设置了SQLite3数据库,数据库配置存储在/guest/settings.py文件中:

<span style="color:#000000"><code class="language-python"><span style="color:#880000"># Database</span>
<span style="color:#880000"># https://docs.djangoproject.com/en/1.10/ref/settings/#databases</span>

DATABASES = {
    <span style="color:#009900">'default'</span>: {
        <span style="color:#009900">'ENGINE'</span>: <span style="color:#009900">'django.db.backends.sqlite3'</span>,
        <span style="color:#009900">'NAME'</span>: os.path.join(BASE_DIR, <span style="color:#009900">'db.sqlite3'</span>),
    }
}</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

3.3 Django认证系统

前面的例子,对于用户身份的验证,只是使用了简单的if语句进行判断,本节会实现真正的用户信息验证。

登录Admin后台

在使用migrate命令进行数据迁移时,Django同时也创建了auth_user表,该表中存放的用户信息可以用来登录Django自带的Admin管理后台。在此之前,需要使用如下命令,创建Admin帐号:

python manage.py createsuperuser

本例创建的超级管理员Admin帐号:admin/admin123456

Admin管理后台的地址是:http://127.0.0.1:8000/admin/

都是图形操作界面,不再做过多解释。可自己动手尝试增加用户。

引用Django认证登录

Django已经封装好了用户认证和登录的相关方法,只需要拿来用即可。并且,同样使用auth_user表中的数据进行验证,前面已经通过Admin后台向该表中添加了用户信息。

要达到此目的,只需要修改/guest/sign/views.py文件中的login_action函数:

<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> django.contrib <span style="color:#000088">import</span> auth

<span style="color:#880000"># 登录动作</span>
<span style="color:#000088">def</span> <span style="color:#009900">login_action</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#000088">if</span> request.method == <span style="color:#009900">'POST'</span>:
        username = request.POST.get(<span style="color:#009900">'username'</span>, <span style="color:#009900">''</span>)
        password = request.POST.get(<span style="color:#009900">'password'</span>, <span style="color:#009900">''</span>)
        user = auth.authenticate(username=username, password=password)
        <span style="color:#000088">if</span> user <span style="color:#000088">is</span> <span style="color:#000088">not</span> <span style="color:#000088">None</span>:
            auth.login(request, user)                   <span style="color:#880000"># 登录</span>
        <span style="color:#880000">#if username == 'admin' and password == 'admin123':</span>
            <span style="color:#880000">#return HttpResponse("Login Success!")</span>
            <span style="color:#880000">#return HttpResponseRedirect('/event_manage/')</span>
            <span style="color:#880000">#response.set_cookie('user', username, 3600) # 添加浏览器Cookie</span>
            request.session[<span style="color:#009900">'user'</span>] = username           <span style="color:#880000"># 将session信息添加到浏览器</span>
            response = HttpResponseRedirect(<span style="color:#009900">'/event_manage/'</span>)
            <span style="color:#000088">return</span> response
        <span style="color:#000088">else</span>:
            <span style="color:#000088">return</span> render(request, <span style="color:#009900">'index.html'</span>, {<span style="color:#009900">'error'</span>:<span style="color:#009900">'username or password error!'</span>})</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

代码讲解:

authenticate()函数认证给出的用户名和密码,它接受两个参数:username、password,并且会在用户名密码正确的情况下返回一个user对象,否则authenticate()返回None。

if语句对authenticate()返回对象进行判断,如果不为None,说明用户认证通过,则调用auth的login()函数进行登录,它接受两个参数:HttpRequest对象、一个user对象。

返回到index页面,尝试使用admin/admin123456和自定义用户进行登录。

关上窗户

在浏览器中直接访问:http://127.0.0.1:8000/event_manage/

不需要认证也可以访问这个页面,这是个漏洞,我们不允许用户不经认证就直接访问这些页面,所有需要将这个窗户关闭。

要做到这点,只需要再指定的视图函数前增加装饰器即可,如下修改/guest/sign/views.py文件:

<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> django.contrib.auth.decorators <span style="color:#000088">import</span> login_required

<span style="color:#880000"># 发布会管理</span>
<span style="color:#006666">@login_required</span>
<span style="color:#000088">def</span> <span style="color:#009900">event_manage</span><span style="color:#4f4f4f">(request)</span>:
    <span style="color:#880000">#username = request.COOKIES.get('user', '') # 读取浏览器Cookie</span>
    username = request.session.get(<span style="color:#009900">'user'</span>, <span style="color:#009900">''</span>)  <span style="color:#880000"># 读取浏览器Session</span>
    <span style="color:#000088">return</span> render(request, <span style="color:#009900">"event_manage.html"</span>, {<span style="color:#009900">"user"</span>:username})</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8

清空缓存,再次访问/event_manage/,Django会提示页面不存在:Page not found 404

我们可以发现一个问题,当访问@login_required装饰器的视图时,默认跳转的URL中会包含“/accounts/login/”,这里为什么不让它直接跳转到登录页面?不仅要告诉用户窗户是关着的,还指引用户到门的位置来进行登录操作呢?

想要达到这个目的,需要做如下修改,在/guest/urls.py文件中,增加新的路径配置:

<span style="color:#000000"><code class="language-python"><span style="color:#000088">from</span> sign <span style="color:#000088">import</span> views

urlpatterns = [
    url(<span style="color:#009900">r'^$'</span>, views.index),
    url(<span style="color:#009900">r'^admin/'</span>, admin.site.urls),
    <span style="color:#880000">#url(r'^index/$', views.index),</span>
    url(<span style="color:#009900">r'^login_action/$'</span>, views.login_action),
    url(<span style="color:#009900">r'^event_manage/$'</span>, views.event_manage),
    url(<span style="color:#009900">r'^accounts/login/$'</span>, views.index),
]</code></span>
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

当用户访问: 
http://127.0.0.1:8000 
http://127.0.0.1:8000/index/ 
http://127.0.0.1:8000/event_manage/ 
都会跳转到登录页面。但是如果尝试访问一个不存在的页面,Django依然会给出404错误。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值