前几节的介绍中我们已经有能力制作一个登陆页面,在验证了用户名和密码的正确性后跳转到后台的页面。但是测试后也发现,如果绕过登陆页面。直接输入后台的url地址也可以直接访问的。这个显然是不合理的。其实我们缺失的就是cookie和session配合的验证。有了这个验证过程,我们就可以实现和其他网站一样必须登录才能进入后台页面了。


    先说一下这种认证的机制。每当我们使用一款浏览器访问一个登陆页面的时候,一旦我们通过了认证。服务器端就会发送一组随机唯一的字符串(假设是123abc)到浏览器端,这个被存储在浏览端的东西就叫cookie。而服务器端也会自己存储一下用户当前的状态,比如login=true,username=hahaha之类的用户信息。但是这种存储是以字典形式存储的,字典的唯一key就是刚才发给用户的唯一的cookie值。那么如果在服务器端查看session信息的话,理论上就会看到如下样子的字典

{'123abc':{'login':true,'username:hahaha'}}

因为每个cookie都是唯一的,所以我们在电脑上换个浏览器再登陆同一个网站也需要再次验证。那么为什么说我们只是理论上看到这样子的字典呢?因为处于安全性的考虑,其实对于上面那个大字典不光key值123abc是被加密的,value值{'login':true,'username:hahaha'}在服务器端也是一样被加密的。所以我们服务器上就算打开session信息看到的也是类似与以下样子的东西

{'123abc':dasdasdasd1231231da1231231}

借用一张别的大神画的图,可以更直观的看出来cookie和session的关系

wKioL1bmwJqQWT79AACFVu-rqIs465.gif


   


    知道了原理,我们下面就来用代码实现


先在templates目录下创建两个html,login.html负责登录页面。backend页面代表后台页面

wKioL1bm3rygxB5QAAAoQMv4T8o844.png

login.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>login</title>
  6.     <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.5-dist/css/bootstrap.min.css">
  7. </head>
  8. <body>
  9.     <div class="container">
  10.         <form action="login.html" method="post">
  11.             <div class="form-group">
  12.                 <label class="sr-only">username</label>
  13.                 <input type="text" class="form-control" name="username" placeholder="用户名"/>
  14.             </div>
  15.             <div class="form-group">
  16.                 <label class="sr-only">Password</label>
  17.                 <input type="password" class="form-control" name="passwd" placeholder="密码"/>
  18.             </div>
  19.             <div class="form-group">
  20.                 <input class="btn btn-primary" type="submit" value="Submit">
  21.             </div>
  22.         </form>
  23. </div>
  24. <script type="application/javascript" src="/static/js/jquery-2.2.1.min.js"></script>
  25. <script type="application/javascript" src="/static/plugins/bootstrap-3.3.5-dist/js/bootstrap.min.js"></script>
  26. </body>
  27. </html>


backend.html

  1. <!DOCTYPE html>
  2. <html lang="en">
  3. <head>
  4.     <meta charset="UTF-8">
  5.     <title>backend</title>
  6.     <link rel="stylesheet" href="/static/plugins/bootstrap-3.3.5-dist/css/bootstrap.min.css">
  7.     <link rel="stylesheet" href="/static/css/commons.css">
  8. </head>
  9. <body>
  10. <div class="container">
  11.     <h2>cookie 内容是 {{ cookie_content }}</h2>
  12.     <h2>session 内容是 {{ session_content }}</h2>
  13.     <h2>登录用户名 :{{ username }}</h2>
  14.     <a href="/logout/">注销</a>
  15. </div>
  16. <script type="application/javascript" src="/static/js/jquery-2.2.1.min.js"></script>
  17. <script type="application/javascript" src="/static/plugins/bootstrap-3.3.5-dist/js/bootstrap.min.js"></script>
  18. </body>
  19. </html>


第二步 编辑app01应用下的views.py文件,编写代码逻辑部分

wKioL1bm4QnCtWaCAAAwVBjCprc461.png

views.py

  1. # /usr/bin/env python
  2. # coding:utf-8
  3. from django.shortcuts import render
  4. from django.shortcuts import redirect
  5. def login(request):
  6.     if request.method=="POST":
  7.         username=request.POST['username']
  8.         pwd=request.POST['passwd']
  9.         if username=='abc' and pwd=='123':
  10.             #设置session内部的字典内容
  11.             request.session['is_login']='true'
  12.             request.session['username']='abc'
  13.             #登录成功就将url重定向到后台的url
  14.             return redirect('/backend/')
  15.     #登录不成功或第一访问就停留在登录页面
  16.     return render(request,'login.html')
  17. def backend(request):
  18.     """
  19.     这里必须用读取字典的get()方法把is_login的value缺省设置为False,
  20.     当用户访问backend这个url先尝试获取这个浏览器对应的session中的
  21.     is_login的值。如果对方登录成功的话,在login里就已经把is_login
  22.     的值修改为了True,反之这个值就是False的
  23.     """
  24.     is_login=request.session.get('is_login',False)
  25.     #如果为真,就说明用户是正常登陆的
  26.     if is_login:
  27.         #获取字典的内容并传入页面文件
  28.         cookie_content=request.COOKIES
  29.         session_content=request.session
  30.         username=request.session['username']
  31.         return render(request,'backend.html',
  32.                       {
  33.             'cookie_content':cookie_content,
  34.             'session_content':session_content,
  35.             'username':username
  36.                       })
  37.     else:
  38.         """
  39.         如果访问的时候没有携带正确的session,
  40.         就直接被重定向url回login页面
  41.         """
  42.         return redirect('/login/')
  43. def logout(request):
  44.     """
  45.     直接通过request.session['is_login']回去返回的时候,
  46.     如果is_login对应的value值不存在会导致程序异常。所以
  47.     需要做异常处理
  48.     """
  49.     try:
  50.         #删除is_login对应的value值
  51.         del request.session['is_login']
  52.     except KeyError:
  53.         pass
  54.     #点击注销之后,直接重定向回登录页面
  55.     return redirect('/login/')


第三步,编辑mydjango目录下的urls.py文件。设置函数与页面的绑定关系

urls.py

  1. from django.conf.urls import url
  2. from django.contrib import admin
  3. from app01 import views
  4. urlpatterns = [
  5.     url(r'^admin/', admin.site.urls),
  6.     url(r'^login/', views.login),
  7.     url(r'^backend/', views.backend),
  8.     url(r'^logout/', views.logout),
  9. ]

wKiom1bm4D7AGoi8AADg0sOk10k285.png


最后打开浏览器直接访问/backend/页面的时候直接就被重定向到了/login/

wKioL1bm4Ynh_bOzAABPcTDBX40769.png


只有在输入了正确的用户名和密码之后才进入到了/backend/页面

wKiom1bm4UOjEwzlAAE9se9_78U441.png从上图中我们看到有一下几点:

1、login页面正确登录的话,后台页面可以获取到浏览器携带的cookie的。

2、第一行的sessionid其实就是cookie值

3、session的内容是加密的,从客户端获取不到session的内容

4、服务端可以通过预设的key值取出session的内容并打印到前段


从火狐浏览器里查看cookie

wKioL1bm5aLicB3pAAC_XkZOUds501.png


django的session默认是存储在数据库里的,我们再到数据库查看一下真正session内容

wKioL1bm5imRTMYYAABvKzZiJig955.png

wKiom1bm6EHiV1i0AADUm8yxkhs649.png


下面我们再来最后的总结一下cookie和session的知识点

一、操作Cookie


  获取cookie:request.COOKIES[key]


  设置cookie:response.set_cookie(key,value)


由于cookie保存在客户端的电脑上,所以,jquery也可以操作cookie。

  1. <script src='/static/js/jquery.cookie.js'></script>
  2. $.cookie("list_pager_num"30,{ path: '/' });


二、操作Session(session默认在服务器端保存15天)


  获取session:request.session[key]


  设置session:reqeust.session[key] = value


  删除session:del request.session[key]    

(这个删除其实就是把数据库的session_data更新为一个其他的值了,并没有立即删除)


  1. request.session.set_expiry(value)
  2. * 如果value是个整数,session会在些秒数后失效。
  3. * 如果value是个datatime或timedelta,session就会在这个时间后失效。
  4. * 如果value是0,用户关闭浏览器session就会失效。
  5. * 如果value是None,session会依赖全局session失效策略。

更多见:


  https://docs.djangoproject.com/en/1.9/topics/http/sessions/


  http://docs.30c.org/djangobook2/chapter14/


  https://docs.djangoproject.com/en/1.9/ref/settings/#settings-sessions