十一、Django的cookie和session

一、Django的cookie和session

一、会话

会话可以理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应。客户向某一服务器发出第一个请求开始,会话就开始了,直到客户关闭了浏览器会话结束。 

在一个会话的多个请求中,需要共享数据,就是会话跟踪技术。比如你在登陆银行主页,请求登录、请求取款、请求转账、请求还款...,在这个会话中,当前的用户信息必须在这个会话中是共享的,因为登录的是你,那么取款转账时一定是相对你的取款转账 。这就说明我们必须在一个会话过程中有共享数据的能力。 

在web中这种能力的实现就要依靠cookie和session 

二、cookie

  1. Cookie的由来

    HTTP协议是无状态的。就是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。

    客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态” ,因此就需要用到cookie

    用django,虽然写了许多的页面,但是用户可以不用登录也能看所有的网页,只需要知道网址就行,但为了安全机制,需要做个验证,无论访问哪个网址需要验证用户的身份;当用户登录后,要需要验证是否是登录的状态,不需要再重复登录,但是http是无状态的,此时就需要用到cookie了。

  2. 什么是Cookie

    cookie是浏览器的技术,Cookie具体指的是一段小信息,它是服务器发送出来存储在浏 览器上的一组组键值对,可以理解为服务端给客户端的一个小甜点,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

  3. Cookie的原理

    工作原理:浏览器访问服务端,带着一个空的cookie,然后由服务器产生内容,浏览器收到相应后保存在本地;当浏览器再次访问时,浏览器会自动带上Cookie,这样服务器就能通过Cookie的内容来判断这个是“谁”了。

  4. 网页下查看cookie

  1. cookie规范
  • Cookie大小上限为4KB;

  • 一个服务器最多在客户端浏览器上保存20个Cookie;

  • 一个浏览器最多保存300个Cookie,因为一个浏览器可以访问多个服务器。

      随着互联网技术发展,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等。
    

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

  1. cookie的传递

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

一个用户 —— 一个浏览器 —— 一个服务端

BS:统一接口,浏览器输入一个网址,就能打开一个网站

  1. Cookie的覆盖

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

三、django中操作cookie

Ctrl + Shift + del三个键来清除页面缓存和cookie

  1. 获取cookie

    request.COOKIE['key'] # 或者 request.COOKIE.get('key')

    request.get_signed_cookie(key, default=RAISE_ERROR, salt='', max_age=None)
    参数:
    default: 默认值
    salt: 加密盐
    max_age: 后台控制过期时间

  2. 设置cookie

    rep = HttpResponse(...) # 或 rep = render(request, ...)
    rep.set_cookie(key,value,...)
    return rep

    rep.set_signed_cookie(key,value,salt='加密盐', max_age=None, ...)
    参数:
    key, 键
    value='', 值
    max_age=None, 超时时间(给一个以秒为单位的数据,经过这个时间后失效)
    expires=None, 超时时间(给一个时间日期格式的数据,到那个时候自动失效)
    path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
    domain=None, Cookie生效的域名
    secure=False, https传输
    httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

  3. 删除cookie

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

  4. cookie的验证

  5. 比如,我们想自己设置一个cookie,键是k1,值是v1:
    def index(request):
    ret = HttpResponse('ok')
    ret.set_cookie('k1','v1')
    return ret
    结果在网页端开发工具的cookie可见,设置成功了:

  6. 然后通过对比我们自己设定的cookie值,如果有cookie的键k1对应的值是v1,就能访问制作的home页面
    home.html:

    这是home页面

    def home(request):
        is_login = request.COOKIES.get('k1')
        if is_login == 'v1':
            return render(request,'home.html')
        else:
            return HttpResponse('gun')
    

    出现问题:就是直接访问127.0.0.1:8000/home,也会直接拿到home页面,当我们在网页端查看cookie的时候,仍然有k1对应v1,这是因为缓存的机制,需要我们Ctrl + Shift + del三个键来清除页面缓存和cookie
    此时直接访问home页面,因为cookie中没有了键k1对应的值是v1,就拿不到home页面
    解决:需要先访问index路径,经过index视图函数,给cookie设置一个键值对k1:v1,然后再访问home页面,浏览器还是带着本地的cookie,此时就可以拿到home的页面了

  7. 登录的验证

需求:制作三个页面,一个登录,一个index页面,一个home页面,用户想访问index和home页面都必须先经过login页面

  1. 先配置路径
    from django.conf.urls import url
    from app01 import views

    urlpatterns = [
        url(r'^index/', views.index,name='index'),
        url(r'^home/', views.home,name='home'),
        url(r'^login/', views.login,name='login'),
    ]
    
  2. 制作三个页面
    home.html:

    这是home页面
    去往index页面

    index.html:
        <body>
        来到了index的页面
        <a href="/home/">返回home页面</a>
        </body>
        
    login.html:
        欢迎来到登陆的页面
        <form action="/login/" method="post">
            {% csrf_token %}
            用户名:<input type="text" name="uname">
            密码:<input type="password" name="pwd">
            <input type="submit">
        </form>
    
  3. 写视图函数
    from django.shortcuts import render,HttpResponse,redirect

    def login(request):
        if request.method == 'GET':
            return render(request,'login.html')
        else:
            username = request.POST.get('uname')
            password = request.POST.get('pwd')
            if username == 'yangzm' and password == '123':
                ret =  redirect('home')
                ret.set_cookie('is_login',True)
                return ret
            else:
                return redirect('login')
    
    def index(request):
        is_login = request.COOKIES.get('is_login')
        # print(is_login,type(is_login))     # True <class 'str'>
        if is_login == 'True':
            return render(request,'index.html')
        else:
            return redirect('login')
    
    def home(request):
        is_login = request.COOKIES.get('is_login')
        if is_login == 'True':
            return render(request,'home.html')
        else:
            return redirect('login')
    

    在login函数中,先返回一个登录界面,然后得到用户提交的数据判断,验证成功了就设置cookie的值,否则在返回登录页面重新登录
    在index、home函数中,判断cookie设置的值,验证成功就返回页面,否则重定向回到登录页面

  4. 视图函数 改进版——加装饰器
    from django.shortcuts import render,HttpResponse,redirect

    def logining(f):
        def inner(request,*args,**kwargs):
            is_login = request.COOKIES.get('is_login')
            if is_login == 'True':
                ret = f(request,*args,**kwargs)
                return ret
            else:
                return redirect('login')
        return inner
    
    def login(request):
        if request.method == 'GET':
            return render(request,'login.html')
        else:
            username = request.POST.get('uname')
            password = request.POST.get('pwd')
            if username == 'yangzm' and password == '123':
                ret =  redirect('home')
                ret.set_cookie('is_login',True)
                # ret.set_cookie('is_login',True,10) 设置超时函数10s,超过10scookie就失效了
                return ret
            else:
                return redirect('login')
    @logining
    def index(request):
        return render(request,'index.html')
    
    @logining
    def home(request):
        return render(request,'home.html')
    

四、session

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

Cookie虽然在一定程度上解决了 “保持状态” 的需求,但是cookie最大支持4096字节,而且cookie保存在客户端,可能别拦截或者盗取

比如我设置了三组的cookie值,都会在网页看得到:

session就解决了以上问题,即支持更多的字节,并且保存在服务端,有较高的安全性

给每个客户端的cookie分配一个唯一的id,这样用户在访问时,通过cookie,服务器就知道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密码”等等 

五、django中操作session

一个用户拿到session_id,只要没清除cookie,就还会有session_id,就不会生成一条新纪录了;

清除了cookie,session_id也没有了,此时再来访问就会新生成一条新的数据

一个用户 -- 一个浏览器 -- 对应一个session记录
  1. 设置值

    request.session['k1'] = 123
    request.session.setdefault('k1',123) # 存在则不设置

    自动生成随机字符串,将这个随机字符串和用户数据(加密后)和过期时间保存到了django-session表里面,帮你将这个随机字符串以sessionid:随机字符串的形式添加到cookie里面返回给浏览器(sessionid名字是可以改的)

    但是注意一个事情,django-session这个表,你不能通过orm来直接控制,因为你的models.py里面没有这个对应关系

  1. 取值

    request.session['k1']
    request.session.get('k1',None)

    request.session这句是帮你从cookie里面将sessionid的值取出来,将django-session表里面的对应sessionid的值的那条记录中的session-data字段的数据给你拿出来(并解密),get方法就取出k1这个键对应的值

  2. 删除值

    del request.session['k1'] # django-session表里面同步删除

  3. 登录验证

    def home(request):
    # is_login = request.session['is_login'] # 这么取值,找不到is_login这个键就会报错
    is_login = request.session.get('is_login')# 这样取值不会报错
    # print(is_login,type(is_login)) # True <class 'bool'>
    '''
    1.从cookie里面拿出了session_id:xxx这个随机字符串
    2.去django-session表里面查询对应的数据
    3.反解加密的用户数据,并获取用户需要的数据
    '''
    if is_login == True:

        return render(request,'home.html')
    else:
        return redirect('login')
    

    def login(request):
    if request.method == 'GET':
    return render(request,'login.html')
    else:
    username = request.POST.get('uname')
    password = request.POST.get('pwd')
    if username == 'yangzm' and password == '123':
    request.session['is_login'] = True
    request.session['username'] = 'yang'
    # 1.生成了session_id:随机字符串dsdggdf
    # 2.在cookie里面加上了一个键值对session_id:dsdggdf
    # 3.将用户的数据进行了加密,并保存到django-session表里面
    '''
    session_key session_data
    dsdggdf 用户数据加密后的字符串
    '''
    return redirect('home')
    else:
    return redirect('login')

加入退出功能:

url(r'^logout/', views.logout,name='logout'),

home.html:
    <div>
        <a href="/logout/">退出</a>
    </div>

def logout(request):
    request.session.flush()
    return redirect('login')
  1. 其他方法

    所有 键、值、键值对

    request.session.keys()
    request.session.values()
    request.session.items()

    会话session的key

    session_key = request.session.session_key 获取sessionid的值

    将所有Session失效日期小于当前日期的数据删除,将过期的删除

    request.session.clear_expired()

    检查会话session的key在数据库中是否存在

    request.session.exists("session_key") #session_key就是那个sessionid的值

    删除当前会话的所有Session数据

    request.session.delete()
      

    删除当前的会话数据并删除会话的Cookie。

    request.session.flush() #常用,清空所有cookie---删除session表里的这个会话的记录,
    这用于确保前面的会话数据不可以再次被用户的浏览器访问
    例如,django.contrib.auth.logout() 函数中就会调用它。

    设置会话Session和Cookie的超时时间

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

  2. 改session_id

    在settings里面设置:
    SESSION_COOKIE_NAME = 'niubi'

然后在网页查看cookie:

  1. Django中的Session配置

    1. 数据库Session
      SESSION_ENGINE = 'django.contrib.sessions.backends.db' # 引擎(默认)

    2. 缓存Session
      SESSION_ENGINE = 'django.contrib.sessions.backends.cache' # 引擎
      SESSION_CACHE_ALIAS = 'default' # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置

    3. 文件Session
      SESSION_ENGINE = 'django.contrib.sessions.backends.file' # 引擎
      SESSION_FILE_PATH = None # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()

    4. 缓存+数据库
      SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db' # 引擎

    5. 加密Cookie Session
      SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies' # 引擎

    其他公用设置项:
    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,默认修改之后才保存(默认)

posted on 2019-07-30 20:59  雨后清明  阅读(138)  评论(0编辑  收藏  举报

导航