zoukankan      html  css  js  c++  java
  • Django学习笔记(5)——cookie和session

    一,前言

    1.1,什么是会话跟踪技术

      在JavaWeb中,客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束。在一个会话的多个请求中共享数据,这就是会话跟踪技术。

      例如在一个会话中的请求如下(请求银行主页):

    • 请求登录(请求参数是用户名和密码)
    • 请求转账(请求参数与转账相关的数据)
    • 请求信誉卡还款(请求参数与还款相关的数据)

      在上面会话中,当前用户信息必须在这个会话中共享的,因为登录的是张三,那么在转账和还款时一定是相对张三的转账和还款!这就说明我们必须在一个会话过程中有共享数据的能力。

      在程序中,会话跟踪是很重要的事情。理论上,一个用户的所有请求都应该属于同一个会话,而另一个用户的所有请求则该属于另一个会话,二者不能混淆。例如,用户A在超市购买的任何商品都应该放在A的购物车内,不论是用户A什么时候购买的,这都是属于同一个会话,不能放在用户B或者用户C的购物车内,这不属于同一个会话。

    1.2,会话路径技术使用Cookie 或 session 完成

      我们知道HTTP协议是无状态协议,也就是说每个请求都会独立的! 无法记录前一次请求的状态。但是HTTP协议中可以使用Cookie来完成会话跟踪技术!

      在JavaWeb开发中,使用session来完成会话跟踪,session底层依赖Cookie技术。

    • cookie就是一段字符串,保存于本机电脑上
    • session保存于服务器,用来保存用户的会话信息,依赖于Cookie

      cookie是通过在客户端记录信息确定用户身份,Session是通过在服务端记录信息确定用户身份。

    1.3,cookie和session机制

      cookie机制采用的时在客户端保存状态的方案。作用就是为了解决HTTP协议无状态的缺陷所作的努力。

      session机制采用的是一种在客户端与服务端之间保持状态的解决方案。由于采用服务器端保持状态的方案在客户端也需要保持一个标识,所以session机制可能需要借助于cookie机制来达到保存标识的目的。session还提供了方便管理全局变量的方式。session是针对每一个用户的,变量的值保存在服务器上,用一个sessionID来区分哪个用户的session。

    1.4,cookie与session的实现原理

      上图很明显的展示了Django的session和cookie的实现原理。服务器会生成两份相同的cookie字符串,一份保存在本地,一份发向请求的浏览器。浏览器将会受到的cookie字符串保存下来,当下次再发请求时,会将信息与这段cookie一同发送到服务器,服务器得到这段cookie会与本地保存的那份判断是否相同,如果相同就表示用户已经登录成功,保存用户登录成功的状态。Django的session保存在数据库中的数据相当于一个大字典,key为cookie的字符串,value仍是一个字典,字典的key和value为用户设置的相关信息,这样就可以方便的存取session里面的信息。

    1.5,cookie和session内容

      cookie内容主要包括:key,value,过期时间,路径和域。路径和域一起构成了cookie的作用范围。

      cookie的使用由浏览器按照一定的规则在后台自动发送给服务器的,浏览器检查所在存储的cookie,如果某个cookie的作用范围大于等于将要请求的资源所在位置,将cookie附在请求资源的HTTP请求头上发给服务器。

      cookie的生命周期跟过期时间相关,如果不设置过期时间,成为会话cookie,保存在内存中,关闭浏览器窗口,cookie消失。如果设置过期时间,浏览器会把cookie写入硬盘,这些cookie仍然有效,知道超过设定的过期时间。

      存在硬盘上的cookie可以在同一个浏览器不同进程间共享,比如两个Chrome窗口。存在内存的,不同浏览器不同的处理方式。

      session内容,服务器使用类似Python字典的key value 的形式存储,存储session方式很多,数据库,缓存,文件,加密cookie,数据库加缓存。

    1.6,HTTP无状态性

      HTTP被设计为“无状态”,每次请求都处于相同的空间中。在一次请求和下一次情况之间没有任何状态保持,我们无法根据请求的任何方面(IP地址,用户代理等)来识别同一人的连续请求,所以HTTP协议不具备保存之前发送过的请求或响应的功能。

      协议对于事务处理没有记忆能力,对同一个URL请求没有上下文关系,每次的请求都是独立的,它的执行情况和结果与之前的请求和之后的请求时无直接关系的。它不会受前面的请求应答情况直接影响,也不会直接影响后面的请求应答情况。服务器中没有保存客户端的状态,客户端必须每次带上自己的状态去请求服务器。

      如果说每一一种机制用来处理无状态,那么就需要花费时间不停的进行身份验证,正是这样,HTTP引入了session和cookie,即保持了HTTP的无状态性,也使得HTTP的应用称为有状态的。

    二,Cookie概述

    2.1,什么叫 Cookie

      Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie是 key-value 结构,类似于一个python中的字典。随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。

          注意:cookie不能跨浏览器的,cookie中不能存在中文

      Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端!

    查看cookie

      我们使用Chrome浏览器,打开开发者工具。

     我们举个简单的例子。

      代码如下:

    modes.py

    from django.db import models
    
    # Create your models here.
    
    class UserInfo(models.Model):
    
        user = models.CharField(max_length=32)
        pwd = models.CharField(max_length=32)
    

      我们给UserInfo表中插入一条记录,比如用户名和密码都是123(方便起见)。

    views.py

    from django.shortcuts import render, HttpResponse,redirect
    
    # Create your views here.
    from cookie_demo.models import UserInfo
    
    def index(request):
        if request.method == 'POST':
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
    
            user = UserInfo.objects.filter(user=user, pwd=pwd).first()
            if user:
                # 登录成功
                '''
                :return HttpResponse()
                :return render()
                :return redirect()
                
                这三个都返回的是HTTPResponse,只不过render 和redirect 将其封装了
                
                '''
                response = HttpResponse("OK")
                response.set_cookie('is_login', True)
                return response
    
            else:
                pass
    
        return render(request, 'cookie/index.html')
    

      

    index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="user"></p>
        <p>密码:<input type="password" name="pwd"></p>
        <input type="submit" value="submit">
    
    </form>
    
    </body>
    </html>
    

       我们输入一个正确的用户名和密码,我们在前端cookie可以看到其信息:

      在响应头,我们也可以看到其信息:

     2.2,HTTP的Cookie规范

    • Cookie大小上限为4KB;
    • 一个服务器最多在客户端浏览器上保存20个Cookie;
    • 一个浏览器最多保存300个Cookie

      上面的数据只是HTTP的Cookie规范,但是在浏览器大战的今天,一些浏览器为了打败对手,为了展示自己的能力起见,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等!但也不会出现将你的硬盘占满的可能!

      注意:不同浏览器之间是不共享Cookie的,也就是说在你使用IE访问服务器的时候,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。

    2.3,Cookie的用途

    • 服务器使用Cookie来跟踪客户端状态
    • 保存购物车
    • 显示上次登录名

    2.4,Cookie与HTTP头

      Cookie是通过HTTP请求和响应头在客户端和服务器端传递的:

    • Cookie:

        请求头,客户端发送给服务器端;

        格式:Cookie:a=A;b=B;c=C。即多个Cookie用分号离开;

    • Set-Cookie:

        响应头,服务器端发送给客户端。

        一个Cookie对象一个Set-Cookie:

        Set-Cookie:a=A

        Set-Cookie:b = B

        Set-Cookie:c=C

    2.5,Cookie的覆盖

      如果服务器端发送重复的Cookie,那么会覆盖原有的Cookie。

      cookies是浏览器为Web服务器存储的一小段信息。每次浏览器从某个服务器请求页面时,它向服务器会送之前收到的cookies,它保存在浏览器下的某个文件夹下。

      如果服务器端发送重复的Cookie那么会覆盖原有的Cookie,例如客户端的第一个请求服务器端发送的Cookie是:Set-Cookie:a=A;第二请求服务器端发送的是:Set-Cookie:a=AA,那么客户端只留下一个Cookie,即:a=AA。

    2.6,Cookie 的生命周期

      cookie不只有name和value,Cookie还有生命,所谓生命就是Cookie在客户端的有效时间,可以通过setMaxAge(int) 来设置Cookie的有效时间。以秒为单位。不设置默认为关闭窗口,Cookie结束。

    • cookie. setMaxAge(-1):cookie的maxAge属性的默认值就是-1,表示只在浏览器内存中存活。一旦关闭浏览器窗口,那么cookie就会消失。
    • cookie.setMaxAge(60*60):表示cookie对象可存活1小时。当生命大于0时,浏览器会把Cookie保存到硬盘上,就算关闭浏览器,就算重启客户端电脑,cookie也会存活1小时;
    • cookie.setMaxAge(0):cookie生命等于0是一个特殊的值,它表示cookie被作废!也就是说,如果原来浏览器已经保存了这个Cookie,那么可以通过Cookie的setMaxAge(0)来删除这个Cookie。无论是在浏览器内存中,还是在客户端硬盘上都会删除这个Cookie。

    过期时间

      cookie 可以有过期时间,这样浏览器就知道什么时候可以删除cookie了。如果cookie没有设置过期时间,当用户关闭浏览器的时候,cookie就自动过期了。我们可以改变SESSION_EXPIRE_AT_BROWSER 的设置来控制session框架的这一行为。缺省情况下,SESSION_EXPIRE_AT_BROWSER 设置为False,这样,会话cookie可以在用户浏览器中保持有效达SESSION_COOKIE_AGE 秒(缺省设置是两周,即1209600秒)。如果你不想用户每次打开浏览器都必须重新登录的话,用这个参数来帮助你。如果SESSION_EXPIRE_AT_BROWSER_CLOSE 设置为 True ,当浏览器关闭时,Django会使cookie失效。

        SESSION_COOKIE_AGE :设置cookie在浏览器中存活的时间

      在settings.py中添加:

     

    2.7,Django中的cookie语法

      cookies是一种数据存储技术,是将一段文本保存在客户端(浏览器)的一种技术,并且可以长时间的保存。

    1,设置cookie

    rep = HttpResponse(...) 或 rep = render(request, ...) 或 rep = redirect()  
    rep.set_cookie(key,value,...)
    rep.set_signed_cookie(key,value,salt='加密盐',...)
    

      普通设置:

    obj.set_cookie('tile' , 'name' , expires = value , path = '/')
    

      加盐设置(普通cookie是明文传输的,可以直接在客户端直接打开,所以需要加盐,解盐之后才能查看):

    obj.set_signed_cookie('k' , 'v' , salt = 'name' )
    

      我们可以查看源码,发现HttpResponse() , render(),redirect() 都返回的是HttpResponse。

    2,cookie参数介绍:

                obj.set_cookie('tile', 'james', expires=value ,path='/',
                               domain=None, secure=False, httponly=False)
    

      参数:

    • 1,max_age = 1 : cookie生效的时间,单位是秒
    • 2,expires:具体过期日期
    • 3,path = '/' :  指定哪个url 可以访问到cookie,‘/’ 表示所有,即 path = '/'
    • 4,domain = None(None代表当前域名):指定哪个域名以及它下面的二级域名(子域名)可以访问这个cookie
    • 5,secure = False :https安全相关
    • 6,httponly = False:限制只能通过HTTP传输,JS无法在传输中获取和修改。
    class HttpResponseBase:
        def set_cookie(self, key, #键
            value = '',     #值
          max_age = None, #超长时间cookie需要延续的时间(以秒为单位)如果参数
                            #是 None,这个cookie会延续到浏览器关闭为止。
          expires = None, #超长时间,expires默认None, cookie失效的实际日期 / 时间。
          path = '/',     #Cookie生效的路径,浏览器只会把cookie回传给带有该路径的页面,
                            # 这样可以避免将 cookie传给站点中的其他的应用。
                            # / 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
                    
            domain = None,  # Cookie生效的域名你可用这个参数来构造一个跨站cookie。
                            # 如, domain = ".example.com"所构造的cookie对下面这些站点都是可读的:
                            # www.example.com 、 www2.example.com和an.other.sub.domain.example.com 。
                            #如果该参数设置为None ,cookie只能由设置它的站点读取。secure = False, 
                           # 如果设置为True ,浏览器将通过HTTPS来 回传cookie。
          httponly = False #只能http协议传输,无法被JavaScript获取
                            # (不是绝对,底层抓包可以获取到也可以被覆盖)
                  ): pass
    

      

    3,获取cookie

      普通获取:

    request.COOKIES.get('k')
    

      加盐获取:

    cookies = request.get_signed_cookie('k' , salt = 'name' )
    

      

    4,删除cookie

    response.delete_cookie("cookie_key",path="/",domain=name)
    

      代码:

    def  logout(request):
        rep = redirect("/login/")
        #  删除用户浏览器上之前设置的user  cookie的值
        rep.delete_cookie("user")
        return  rep
    

      

    5,尝试给每个视图函数装饰cookie认证功能

    from django.shortcuts import render,redirect,HttpResponse
    import datetime
    from until import mysqlhelper
    
    # Create your views here.
    
    def cookie_auth(func):
        def weaper(request, *args, **kwargs):
            cookies = request.get_signed_cookie('k', salt='james')
            if cookies == 'v':
                return func(request)
            else:
                return HttpResponse("NG")
        return weaper
    
    now = datetime.datetime.utcnow()
    delta = datetime.timedelta(seconds=10)
    
    def login(request):
        if request.method == 'GET':
            return render(request, 'login.html')
        else:
            username = request.POST.get('N')
            password = request.POST.get('P')
            if username == 'james' and password == '123':
                obj = redirect('/modal')
                # obj.set_cookie("tile", "james", max_age = 1,, )
                value = now + delta
                obj.set_cookie('tile', 'james', expires=value ,path='/',
                               domain=None, secure=False, httponly=False)
                obj.set_signed_cookie('k', 'v', salt='james', )
                return obj
            else:
                return render(request, 'login.html')
    def test(request):
        return render(request, 'layout.html')
    
    @cookie_auth
    def modal(request):
        sql = '''
        SELECT  teacher.id as tid,teacher.`name`as tname,class.title FROM day64.teacher 
        LEFT JOIN teacher_class ON day64.teacher.id=day64.teacher_class.tid
        LEFT JOIN day64.class ON day64.teacher_class.cid=day64.class.id;
        '''
        teacher_list = mysqlhelper.get_list(sql, [])
        res = {}
        for row in teacher_list:
            tid = row['tid']
            if tid in res:
                res[tid]['titles'].append(row['title'])
            else:
                res[tid] = {'tid':row["tid"],'tname':row["tname"],'titles':[row["title"],]}
    
        class_list=mysqlhelper.get_list("SELECT id ,title FROM day64.class" ,[])
        return render(request,'modal.html',{"list":res.values(),"class_list":class_list} )
    

      

    2.8,实例:保存上次访问时间

      我们要做的就是显示上次访问时间。

      views.py

    from django.shortcuts import render, HttpResponse,redirect
    
    # Create your views here.
    from cookie_demo.models import UserInfo
    
    def login(request):
        if request.method == 'POST':
            user = request.POST.get('user')
            pwd = request.POST.get('pwd')
    
            user = UserInfo.objects.filter(user=user, pwd=pwd).first()
            if user:
                # 登录成功
                response = HttpResponse("OK")
                response.set_cookie('is_login', True)
    
                import datetime
                date = datetime.datetime(year=2019, month=5, day=28, hour=9, minute=17)
                response.set_cookie('username', user.user,expires=date)
                return response
    
            else:
                pass
    
        return render(request, 'cookie/login.html')
    
    def index(request):
        print('index: ', request.COOKIES)
        is_login = request.COOKIES.get('is_login')
    
        if is_login:
            username = request.COOKIES.get('username')
            import datetime
            now = datetime.datetime.now().strftime('%Y-%m-%d %H:%M:%S')
    
            last_time = request.COOKIES.get('last_visit_time', "")
            response = render(request, 'cookie/index.html', {'username': username, 'last_time': last_time})
            response.set_cookie('last_visit_time', now)
            return response
        else:
            return redirect('/cookie/login/')
    

      index.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
    <h3>Hi, {{ username }}</h3>
    <p>上次登录时间: {{ last_time }}</p>
    
    </body>
    </html>
    

      login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>index</title>
    </head>
    <body>
    
    <form action="" method="post">
        {% csrf_token %}
        <p>用户名:<input type="text" name="user"></p>
        <p>密码:<input type="password" name="pwd"></p>
        <input type="submit" value="submit">
    
    </form>
    
    </body>
    </html>
    

      效果:

    2.9,实例:Cookie版登陆校验

    views视图代码:

    from django.shortcuts import render, HttpResponse, redirect
    import datetime
    # Create your views here.
    
    # 登录验证装饰器
    def login_auth(func):
        def inner(request, *args, **kwargs):
            # 获取请求的全路径
            url = request.get_full_path()
            # /shopping/?nana=ppp
            # 服务器先拿到cookie,如果拿到则直接跳转到shopping或者order视图页面
            is_login = request.COOKIES.get('is_login')
            # xxx = request.get_signed_cookie('xxx' ,salt='123')
            # 拿到cookie 判断是不是登录状态
            if is_login:
                # 是登录状态直接调用被装饰的函数,返回我们想要的页面
                ret = func(request, *args, **kwargs)
            else:
                # 服务端如果拿不到正确的cookie就会重定向了login这个页面,但是带了一些参数
                return redirect('/login/?next=%s'%url)
            # 当清楚浏览器缓存是直接登录http://127.0.0.1:8000/shopping/,会跳转到登录页面
            # 并且在url后面拼上http://127.0.0.1:8000/login/?next=/shopping/
            # 127.0.0.1:8000/login/?next=/shopping/?nana=ppp
            return ret
        return inner
    
    def login(request):
        if request.method == 'POST':
            # 装饰器中redirect('/login/?next=%s'%url)通过get就可以拿到next的值
            # url = request.GET.get('name')
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'james' and password == '123':
                # 登录成功后跳转到该页面
                # obj = redirect(url)
                obj = HttpResponse("登录成功")
                # 当我们不指定path时,被装饰的视图函数页面只登录后都可以直接被访问,而不需要重新登录
                obj.set_cookie('is_login', True)
                # 浏览器只会把cookie会传给带有该路径的页面
                # 也就说当我们登录成功后,访问shopping页面时可以直接登录
                # obj.set_cookie('is_login', True, path='/shopping/')
                # 但是我们访问order页面时,仍然会跳到登录页面让我们重新登录
                now = datetime.datetime.now().strftime('%Y-%m-%d %X')
                # 设置cookie,在浏览器的请求头中的cookie中我们可以看到我们设置的额cookie
                # 并将登录时间也写到cookie中
                obj.set_cookie('last_time', now)
                # 在浏览器中打开可以看到一个key
                obj.set_cookie('username','james')
                obj.set_cookie('password','123')
                # 获取cookie,并对cookie进行加盐,加盐后的123 是进行加密的遗传字符吗
                obj.set_signed_cookie('james','durant',salt='123')
                # 登录成功后对其进行重定向
                return obj
            else:
                obj = HttpResponse("登录失败")
                return obj
        return render(request, 'login.html')
    
    # 退出登录
    def logout(request):
        obj = HttpResponse("注销成功")
        # 登录成功获得服务端发送来的cookie,删除cookie,
        # 这样我么在浏览器中在输入 http://127.0.0.1:8000/shopping/
        # J就会在此跳到登录页面让我门重新登录
        return obj
    
    # 购物页面
    def shopping(request):
        return render(request, 'shopping.html', locals())
        # locals()用法:locals()可以直接将函数中所有变量全部传给模板
        # 当然这可能会传递一些多余的参数,有点浪费内存的嫌疑
    
        # 登录成功后再请求shopping页面,在请求头就可以看到cookie中带有键值对的形式:
        # Cookie: csrftoken = ybQexReWXIWaO0If0p0I7NubfBSvjUlSfR2EWWX8eKCwXbL8lDo4Kk3ar6Nbr5ZR;
        # last_time = "2018-09-13 18:13:17";
        # name = james;
        # pwd = 123;
        # xxx = xxxxxx:1g0Ocf: 1kRB9Q0FVXlVzstrRbm4fJ61eF0
    
    # 订单页面
    @login_auth
    def order(request):
        return render(request, 'order.html', locals())
    

      

    url路由配置

    from django.contrib import admin
    from django.conf.urls import url
    # 需要先导入对应的app的views文件
    from cookieapp import views
    
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        url(r'^login/', views.login),
        url(r'^order/', views.order),
        url(r'^shopping/',views.shopping),
        url(r'^logout/', views.logout),
    ]
    

      

    template模板代码

      login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <form action="" method="POST">
            <p>用户名:<input type="text" name="username"></p>
            <p>密码:  <input type="password" name="password"></p>
            <input type="submit">
        </form>
    
    
    </body>
    </html>
    

      

    shopping.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <h1>购物车页面</h1>
    
    </body>
    </html>
    

      

    order.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <H1>订单页面</H1>
    
    </body>
    </html>
    

      

    结果展示:(登陆页面:127.0.0.1:8000/login.login)

    登陆成功:

    cookie展示

     

    三,session概述

      session就是在服务器端的“Cookie”,将用户数据保存在服务器端,远比保存在用户端要安全,方便和快捷的多。Session依赖于Cookie,但是与Cookie不同的地方就是在于session将所有的数据都放在服务器端,用户浏览器的cookie中只会保存一个非明文的识别信息,比如哈希值。

      Session是服务器端技术,利用这个技术,服务器在运行时可以为每一个用户的浏览器创建一个其独享的session对象,由于session为用户浏览器独享,所以用户在访问服务器的web资源时,可以把各自的数据放在各自的session中,当用户再去访问该服务器中的其他web资源时,其他web资源再从用户各自的session中取出数据为用户服务。

      Django的Session机器会向请求的浏览器发送cookie字符串。同时也会保存在本地一份,用来验证浏览器登录是否为同一用户。他存在于服务器,Django默认会把session存入数据库中。

      Session依赖于Cookie,如果浏览器不能保存cookie,那么session就失效了。因为他需要浏览器的cookie和session做对比。session就是用来在服务器端保存用户的会话状态。

    3.1,Django中session语法

    class backends.base.SessionBase
            # 这是所有会话对象的基类,包含标准的字典方法:
            __getitem__(key)
                Example: fav_color = request.session['fav_color']
            __setitem__(key, value)
                Example: request.session['fav_color'] = 'blue'
            __delitem__(key)
                Example: del request.session['fav_color']  # 如果不存在会抛出异常
            __contains__(key)
                Example: 'fav_color' in request.session
            get(key, default=None)
                Example: fav_color = request.session.get('fav_color', 'red')
            pop(key, default=__not_given)
                Example: fav_color = request.session.pop('fav_color', 'blue')
    

      类似于字典数据类型的内置方法

            keys()
            items()
            setdefault()
            clear()
     
     
            # 它还有下面的方法:
            flush()
                # 删除当前的会话数据和会话cookie。经常用在用户退出后,删除会话。
     
            set_test_cookie()
                # 设置一个测试cookie,用于探测用户浏览器是否支持cookies。由于cookie的
    工作机制,你只有在下次用户请求的时候才可以测试。
    
            test_cookie_worked()
                # 返回True或者False,取决于用户的浏览器是否接受测试cookie。你必须在之
    前先调用set_test_cookie()方法。
    
            delete_test_cookie()
                # 删除测试cookie。
    
            set_expiry(value)
                # 设置cookie的有效期。可以传递不同类型的参数值:
            • 如果值是一个整数,session将在对应的秒数后失效。例如request.session.
    set_expiry(300) 将在300秒后失效.
            • 如果值是一个datetime或者timedelta对象, 会话将在指定的日期失效
            • 如果为0,在用户关闭浏览器后失效
            • 如果为None,则将使用全局会话失效策略
            失效时间从上一次会话被修改的时刻开始计时。
     
            get_expiry_age()
                # 返回多少秒后失效的秒数。对于没有自定义失效时间的会话,这等同于SESSION_COOKIE_AGE.
                # 这个方法接受2个可选的关键字参数
            • modification:会话的最后修改时间(datetime对象)。默认是当前时间。
            •expiry: 会话失效信息,可以是datetime对象,也可以是int或None
     
            get_expiry_date()
                # 和上面的方法类似,只是返回的是日期
     
            get_expire_at_browser_close()
                # 返回True或False,根据用户会话是否是浏览器关闭后就结束。
     
            clear_expired()
                # 删除已经失效的会话数据。
            cycle_key()
                # 创建一个新的会话秘钥用于保持当前的会话数据。django.contrib.auth.login() 
    会调用这个方法
    

      

    • 获取session:request.session[key]
    • 设置session:request.session[key] = value
    • 删除session:del  request[key]
    1、设置Sessions值
              request.session['session_name'] ="admin"
    
    2、获取Sessions值
              session_name = request.session["session_name"]
    
    3、删除Sessions值
              del request.session["session_name"]
    
    4、flush()
         删除当前的会话数据并删除会话的Cookie。
         这用于确保前面的会话数据不可以再次被用户的浏览器访问
    
    5、get(key, default=None)
      fav_color = request.session.get('fav_color', 'red')  
    
    6、pop(key)
      fav_color = request.session.pop('fav_color')  
    
    7、keys()
    
    8、items()  
    
    9、setdefault()  
    
    10 用户session的随机字符串
    
    

      

    用户session的随机字符串举例:

    request.session.session_key
    
    # 将所有Session失效日期小于当前日期的数据删除
    request.session.clear_expired()
    
    # 检查 用户session的随机字符串 在数据库中是否
    request.session.exists("session_key")
    
    # 删除当前用户的所有Session数据
    request.session.delete("session_key")
    
    request.session.set_expiry(value)
    *如果value是个整数,session会在些秒数后失效。
    *如果value是个datatime或timedelta,session就会在这个时间后失效。
    *如果value是0, 用户关闭浏览器session就会失效。
    *如果value是None, session会依赖全局session失效策略。
    

      

    3.2,session配置

    Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。
    
    a. 配置 settings.py
    
        SESSION_ENGINE = 'django.contrib.sessions.backends.db'   # 引擎(默认)
    
        SESSION_COOKIE_NAME = "sessionid"                       
    # Session的cookie保存在浏览器上时的key,即:sessionid=随机字符串(默认)
    
        SESSION_COOKIE_PATH = "/"                               
    # Session的cookie保存的路径(默认)
    
        SESSION_COOKIE_DOMAIN = None                            
     # Session的cookie保存的域名(默认)
    
        SESSION_COOKIE_SECURE = False                            
    # 是否Https传输cookie(默认)
    
        SESSION_COOKIE_HTTPONLY = True                           
    # 是否Session的cookie只支持http传输(默认)
    
        SESSION_COOKIE_AGE = 1209600                             
    # Session的cookie失效日期(2周)(默认)
    
        SESSION_EXPIRE_AT_BROWSER_CLOSE = False                  
    # 是否关闭浏览器使得Session过期(默认)
    
        SESSION_SAVE_EVERY_REQUEST = False                       
    # 是否每次请求都保存Session,默认修改之后才保存(默认)
    

      

    3.3,session的作用

      session下次通过cookie中的sessionID(键)获取用户信息值(值)

    1,会话保持,记住用户的登录状态(WEB网站,分布式架构)

    2,避免了敏感信息保存在客户端,防止客户端修改cookie信息(和cookie的区别)

    session的过期时间

      session的过期时间:django默认设置是2周 ,如果session过期,浏览器再携带之前的cookie就不能免登陆了。因为cookie已经失效了。

      前端:如果超出了session的过期时间,那么浏览器会自动将对应的cookie删除掉

      后端:django没有对过期的session做任何处理

    如何删除后台保留的一些过期的session信息

    python manage.py clearsessions
    

      当然,如果用户在过期时间内主动退出登录,那么django会将该用户对应的session数据给删除掉  (request.session.flush())

      但是如果用户在登录完以后没有主动退出,并且超出了过期时间,用户需要重新登录,但django中的过期session是不清除的,需要定期清理过期的session数据。

    3.4,session ID的作用

      当客户端第一次请求session时,服务器端会为客户端创造一个session对象,并且生成一个session ID (通过加密算法)。然后保存在cookie中,当用户再次登录时,客户端通过cookie,将session ID传到服务器,去和服务器中的session ID进行比对,寻找这个session,然后根据查找结果执行对应的操作。

      因为session ID 是保存在cookie中,而cookie是存在于客户端,所以session ID 并不安全。

      为了避免session ID 被盗,我们可以这样做:

    • 1,敏感操作需要用户输入密码来进行二次认证
    • 2,网站HTTPS化,提高消息传递过程中的安全系数
    • 3,用户使用一个密钥对参数进行hash,这样即使cookie被盗取,也会因为没有密钥而无法获取sessionID。

    3.5,session的保存方式

      Session是大多数网站都需要具备的功能,Django为我们提供了一个通用的session框架,并且可以使用多种session数据的保存方式:

    • 保存在数据库内
    • 保存到缓存
    • 保存到文件内
    • 保存到cookie内

      通常情况下,没有特别需求的话,请使用保存在数据库内的方式,尽量不要保存在cookie内。

      django的session框架支持匿名会话,封装了cookies的发送和接收过程。cookie包含一个会话ID而不是数据本身(除非你使用的是基于后端的cookie)。

      django的会话框架完全的,唯一的基于cookie。它不像PHP一样,把会话的ID放在URL中,那样不仅使得URL变得丑陋,而且使得你的网站易于受到通过“Referer”头部进行窃取会话ID的攻击。

    3.6,session流程解析

      session的应用要依赖于cookie(session就是cookie的变种)

    1,每次用户第一次访问服务端,把用户的唯一字符串session_id加到cookie里面发送给客户端;

      当用户登录之后,生成一个字典{key : value},将字典存入session,key是自动生成的一段字符串表示,返回cookie,value是一个自定义格式的字典。

    2,服务器端保存随机字符串(sessionID :{用户信息}) 服务端

      当我们在django中用到session时,cookie由服务端随机生成,写到浏览器的cookie中。每个浏览器都有自己的cookie值,是session寻找用户信息的唯一标识。每个浏览器请求到后台接受的request.session 等价于在1中的session字典key (cookie)对应的value。

     3,session的好处就是客户端只有cookie的值,但是始终没有用户信息。

      用法:request.session.get('k1')    request.session['k1'] = 'v1'

      session依赖于cookie,cookie保存在浏览器。session保存在服务器 端。

    3.7,示例

      注意:这里需要注意在session中,我们可以设置多个key:value的值,方便我们做很多事情,比如判断哪个用户:

      如果用户登录后,那么他肯定有一个cookie,而当他访问购物车的时候,怎么判断是哪个用户呢?我们可以在session设置,当用户登录的时候,我们把用户名增加到session中,那么用户携带cookie访问的时候,我们就能判断是哪个用户来访问的。

    比如下面的对应关系:

    user1

    cookie : 001
    

      

    server session(举例格式)

    {session:001 {'IS_LOGIN':'True',username:'james'}}
    

      

    3.7.1,一段简单的Django中实现session的代码,判断用户是否已经成功登陆

    from django.shortcuts import render,redirect,HttpResponse
    
    # Create your views here.
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'james' and password == '123':
                # 设置session
                request.session['IS_Login'] = True
                return redirect('/app01/home')
        
        return render(request, 'login.html')
    
    def home(request):
        # 获取session
        is_login = request.session.get("IS_LOGIN", False)
        if is_login:
            return HttpResponse('order')
        else:
            return redirect('/app01/login/')
    

      

    3.7.2 在视图中使用session

    def session_test(request):
        # 设置session值,会将其存到db.sqlite数据库中的django_session表中
        # 每发送一次请求就会在django_session表中添加一条记录
        request.session['username'] = 'james'
        request.session['is_login'] = True
        '''
        1,生成一个随机字符串
        2,把随机字符串以cookie的形式写回给浏览器
        3,会在数据库中存{'随机字符串': {'username' : 'james' , 'is_login': True}
        '''
        return HttpResponse("ok")
    
    def get_session(request):
        # 在浏览器中输入路由地址就会访问访问该视图函数
        # 获取session值,但是一定要先获取session值,否则获取session时会报错
        # name=request.session['username']
        # is_login=request.session['is_login']
        # print(name)
        # print(is_login)
        # session取值的两种方式,字典key或者get进行取值
        # request.session['k1']
        # request.session.get('k1', None)
        # 设置session的值
        # request.session['k1'] = 123
    
        # name=request.session.setdefault('username', 123)
        # 如果session中的username有值就不会设置,无值则进行设置
        # print(name)      #-----123
        # del request.session['k1']
        # 通过key将session的值进行删除
        # print(request.session.session_key)
        # 取出表django_session表中session_key字段对应的值
        # 将所有Session失效日期小于当前日期的数据删除
        # request.session.clear_expired()
        # 判断session表中session_key字段的值是否存在,返回值为布尔值
        # print(request.session.exists("b16mh23xajc2u69vazvivf8ruo4ilumi"))
        # 会删除数据库的session表中的session的记录,但是浏览器中的session id还在
        # request.session.delete()
        # 删除当前的会话数据并删除会话的Cookie。
        # 通常用它,他会把数据库以及浏览器会话中的session id都删除
        # (调用视图函数test可以看到效果的确是已经被删除)
    
        request.session.flush()
        return HttpResponse("OK")
    

      flush()方法是比较安全的一种做法,而且一次性将session中的所有内容全部清空,确保不留后患,但是也有不好的地方,那就是如果你在session中夹带了一点“私货”,会被一并删除,这一点一定要注意。

      比如登出视图函数:

    def logout(request):
        if not request.session.get('is_login', None):
            # 如果本来就未登录,也就没有登出一说
            return redirect("/index/")
        request.session.flush()
        # 或者使用下面的方法
        # del request.session['is_login']
        # del request.session['user_id']
        # del request.session['user_name']
        return redirect("/index/")
    

      

    3.7.3 在视图函数中使用装饰器装饰CBV

    from django.utils.decorators import  method_decorator
    #  在视图函数中装饰类 需要先导入method_decorator模块
    from django.views import View
    
    # 在类上加装饰器需要指定name的值,也就是要指定装饰类内的那个函数
    # 当我们登录成功后就会直接跳转到我们要登录的页面
    # @method_decorator(login_auth, name='post')
    # @method_decorator(login_auth, name='get')
    
    class MyOrder(View):
        # 将装饰器传入进去
        # @method_decorator(login_auth)
        # 我们可以重写dispatch函数来实现
        def dispatch(self, request, *args, **kwargs):
            # 我们可以重写dispatch函数来实现类似于装饰器的效果
            # dispatch 内部根据反射来实现函数执行
            # 集成父类view的属性
            ret = super().dispatch(request, *args, **kwargs)
            return ret
        # 在cbv上加装饰器,需要用method_decorator修饰一下
        @method_decorator(login_auth)
        def get(self, request):
            return HttpResponse('get')
        def post(self,request):
            return HttpResponse('post')
        
    '''
    1 导入from django.utils.decorators import method_decorator
    2 加载get,post,dispatch方法上:@method_decorator(login_auth)
    3 加在类上:@method_decorator(login_auth,name='get')
    '''
    

      

    四,cookie + session

    1,cookie引入session

      cookie看似解决了HTTP(短连接,无状态)的会话保持问题,但把全部用户数据保存在客户端,存在安全隐患。

      于是cookie+session出现了,我们,我们可以把关于用户的数据保存在服务端,在客户端cookie里加一个sessionID(随机字符串)。

      基于以上原因:cookie+session组成就成立了,并且结束了单单使用cookie做会话保持的方式。

    2,Session和Cookie的好处

      使用Session和Cookie的好处:Cookie可以理解为一个身份证ID,你只要拿着他去和Server端进行通信,如果你没有这个ID,那么server端也不知道你是谁。

      举个例子:我在写博客的时候,在做Cookie和Session的实验,把Cookie删掉了,当我保存的时候直接给我提出来了,为什么呢?就是因为server端不知道我是谁了,因为我已经没有秘钥了。

      所以,只要Session和Cookie任意一方失效,就可以理解为:Cookie失效相当于身份证ID过期,需要重新认证才可以继续使用。Session失效就相当于银行里的数据标识此ID无效,也需要重新申请。

    3,cookie+session 的工作流程

    1,当用户来访问服务端的时候,服务端生成一个随机字符串;

    2,当用户登录成功后,把{sessionID : 随机字符串} 组织成键值对 加到cookie里发送给用户;

    3,服务器以发送给客户端cookie中的随机字符串做键,用户信息做值,保存用户信息;

     

    代码梳理

    用户登录的两种方式:

    1,使用login() 和logout()这两个内置函数实现登录和退出;缺点就是用户的登录时在操作同一个request.user。导致同一台电脑上不能同时登录两个用户;

    2,如果同一台电脑的同一个网站,登录多个账号,为了防止串号,不能再使用login() 和logout()函数了,可以通过session和cookie来实现这个需求;

    1,login.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    </head>
    <body>
    
        <form action="login.html" method="post">
            <input type="text" name="username">
            <input type="password" name="pwd">
            <input type="submit" value="submit">
        </form>
    
    </body>
    </html>
    

      

    2,home.html

    <!DOCTYPE html>
    <html lang="en">
    <head>
        <meta charset="UTF-8">
        <title>Title</title>
    
        <style>
            .header{
                height: 48px;
            }
        </style>
    
    </head>
    <body>
    
        <div class="header">
            <div style="float: right;">{{ username }}</div>
            <div style="float:right;"><a href="logout.html">注销</a></div>
        </div>
    
        <div style="height: 500px; background-color: #ddd"></div>
    
    </body>
    </html>
    

      

    3,view.py

    from django.shortcuts import render,redirect,HttpResponse
    
    # Create your views here.
    
    def login(request):
        if request.method == 'POST':
            username = request.POST.get('username')
            password = request.POST.get('password')
            if username == 'james' and password == '123':
                # 设置session
                request.session['IS_Login'] = True
                request.session['USERNAME'] = 'james'
                return redirect('/Manytable/home/')
            elif username == 'durant' and password == '123':
                request.session['IS_LOGIN'] = True
                request.session['USERNAME'] = 'durant'
                return redirect('/Manytable/home/')
    
        return render(request, 'Manytable/login.html')
    
    def home(request):
        # 获取session
        is_login = request.session.get("IS_LOGIN", False)
        if is_login:
            username = request.session.get("USERNAME", False)
            return render(request, 'Manytable/home.html', {'username':username})
            # return HttpResponse('order')
        else:
            return redirect('/Manytable/login/')
    

      

    4,mysite/urls.py

    from django.contrib import admin
    from django.urls import path
    from django.conf.urls import url
    # 需要先导入对应的app的views文件
    
    from Manytable import views
    
    # admin 后台的路由,先注释掉
    urlpatterns = [
        url(r'^admin/', admin.site.urls),
        # 你的路由,重点是引号中的正则表达式和后面的业务逻辑函数
        url(r'^login/',views.login),
        url(r'^index/',views.home),
    ]
    

      

    5,格式如下:

     作业练习

    1,登录案例

    需要的页面:
    #login.html:登录页面,提供登录表单;
    
    #index1.html:主页,显示当前用户名称,如果没有登录,显示您还没登录;
    
    #index2.html:主页,显示当前用户名称,如果没有登录,显示您还没登录;
    

      思考:如果第二个人在同一个浏览器上登录,Django-session表会怎么样呢?

    2,验证码案例

      验证码可以去识别发出请求的是人还是程序!当然,如果聪明的程序可以去分析验证码图片!但是分析图片也不是一件容易的事情,因为一般验证码图片都会带有干扰线,人都看不清,那么程序一定分析不出来。

    参考文献:https://www.cnblogs.com/chenchao1990/p/5283725.html

    https://blog.csdn.net/qq_32446743/article/details/79482536

    https://www.jianshu.com/p/59cb3ecd81a4

    https://www.cnblogs.com/sui776265233/p/9643055.html

  • 相关阅读:
    中南大学ACM12月月赛第二场热身赛解题报告
    中南大学ACM12月月赛第二场热身赛在本周日(2011年11月20日)举行
    IPv4 and IPv6
    Java and IPV6
    IPv6 and Java
    poj3385
    poj3390
    poj3226
    poj3767
    poj3497
  • 原文地址:https://www.cnblogs.com/wj-1314/p/10496253.html
Copyright © 2011-2022 走看看