zoukankan      html  css  js  c++  java
  • 十一、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,默认修改之后才保存(默认)

  • 相关阅读:
    kubernetes系列(十四)
    kubernetes系列(十三)
    kubernetes系列(十二)
    kubernetes系列(十一)
    kubernetes系列(十)
    kubernetes系列(九)
    kubernetes系列(八)
    MySQL命令(其三)
    MySQL操作命令(其二)
    MySQL命令(其一)
  • 原文地址:https://www.cnblogs.com/yangzm/p/11272746.html
Copyright © 2011-2022 走看看