zoukankan      html  css  js  c++  java
  • session和cookie

    session和cookie

     

    一. 概念理解
    你可能有留意到当你浏览网页时,会有一些推送消息,大多数是你最近留意过的同类东西,比如你想买桌子,上淘宝搜了一下,结果连着几天会有各种各样的桌子的链接。这是因为
    你浏览某个网页的时候,WEB 服务器会先送一些资料放在你的计算机上,类似于你打的文字,选的一些东西什么的,Cookie 会帮你都纪录下来。当下次你再光临同一个网站,WEB
    服务器会先看看有没有它上次留下的 Cookie 资料,有的话,就会依据 Cookie里的内容来判断使用者,送出特定的网页内容给你。 Cookie 的使用很普遍,许多有提供个人化服务的
    网站,都是利用 Cookie来辨认使用者,以方便送出使用者量身定做的内容。
    然而,cookie是什么呢?session又是什么?
    先来了解几个概念。
      1、无状态的HTTP协议:
    协议是指计算机通信网络中两台计算机之间进行通信所必须共同遵守的规定或规则,超文本传输协议(HTTP)是一种通信协议,它允许将超文本标记语言(HTML)文档从Web服务器
    传送到客户端的浏览器。
    HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要建立新的连接。这就意味着服务器无法从连接上跟踪会话。
      2、会话(Session)跟踪:
      会话,指用户登录网站后的一系列动作,比如浏览商品添加到购物车并购买。会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术
         是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。
    二. Cookie
      由于HTTP是一种无状态的协议,服务器单从网络连接上无从知道客户身份。用户A购买了一件商品放入购物车内,当再次购买商品时服务器已经无法判断该购买行为是属于用户A的
      会话还是用户B的会话了。怎么办呢?就给客户端们颁发一个通行证吧,每人一个,无论谁访问都必须携带自己通行证。这样服务器就能从通行证上确认客户身份了。这就是Cookie
      的工作原理。
      Cookie实际上是一小段的文本信息。客户端请求服务器,如果服务器需要记录该用户状态,就使用response向客户端浏览器颁发一个Cookie。客户端会把Cookie保存起来。
      当浏览器再请求该网站时,浏览器把请求的网址连同该Cookie一同提交给服务器。服务器检查该Cookie,以此来辨认用户状态。服务器还可以根据需要修改Cookie的内容。
      1、cookie的内容主要包括:名字,值,过期时间,路径和域。路径与域一起构成cookie的作用范围。
    1)Name 和 Value 属性由程序设定,默认值都是空引用。
    2)Domain属性的默认值为当前URL的域名部分,不管发出这个cookie的页面在哪个目录下的。
    3)Path属性的默认值是根目录,即 ”/” ,不管发出这个cookie的页面在哪个目录下的。可以由程序设置为一定的路径来进一步限制此cookie的作用范围。
    4)Expires 属性,这个属性设置此Cookie 的过期日期和时间。
    
    1 HttpCookie cookie = new HttpCookie("MyCook");//初使化并设置Cookie的名称 2 DateTime dt = DateTime.Now; 3 TimeSpan ts = new TimeSpan(0, 0, 1, 0, 0);//过期时间为1分钟 4 cookie.Expires = dt.Add(ts);//设置过期时间 5 cookie.Values.Add("userid", "value"); 6 cookie.Values.Add("userid2", "value2"); 7 Response.AppendCookie(cookie);
    
    2、Path和Domain属性
    --path:  
       如果http://www.china.com/test/index.html 建立了一个cookie,那么在http://www.china.com/test/目录里的所有页面,以及该目录下面任何子目录里
       的页面都可以访问这个cookie。这就是说,在http://www.china.com/test/test2/test3 里的任何页面都可以访问http://www.china.com/test/index.html
       建立的cookie。但是,如果http://www.china.com/test/ 需要访问http://www.china.com/test/index.html设置的cookes,该怎么办?
       这时,我们要把cookies的path属性设置成“/”。在指定路径的时候,凡是来自同一服务器,URL里有相同路径的所有WEB页面都可以共享cookies。
    --Domain:
       比如: http://www.baidu.com/xxx/login.aspx 页面中发出一个cookie,Domain属性缺省就是www.baidu.com ,可以由程序设置此属性为需要的值。  
       值是域名,比如www.china.com。这是对path路径属性的一个延伸。如果我们想让 www.china.com能够访问bbs.china.com设置的cookies,该怎么办? 我们可以把
       domain属性设置成“china.com”, 并把path属性设置成“/”。
      3、会话Cookie和持久Cookie
    若不设置过期时间,则表示这个cookie的生命期为浏览器会话期间,关闭浏览器窗口,cookie就消失。这种生命期为浏览器会话期的cookie被称为会话cookie。会话cookie一般不存储在
    硬盘上而是保存在内存里,当然这种行为并不是规范规定的。
    若设置了过期时间,浏览器就会把cookie保存到硬盘上,关闭后再次打开浏览器,这些cookie仍然有效直到超过设定的过期时间。存储在硬盘上的cookie可以在浏览器的不同进程间共享。
    这种称为持久Cookie。 
      4、Cookie具有不可跨域名性
    就是说,浏览器访问百度不会带上谷歌的cookie。
    三. Session
      Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录
      在服务器上。这就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。
      每个用户访问服务器都会建立一个session,那服务器是怎么标识用户的唯一身份呢?事实上,用户与服务器建立连接的同时,服务器会自动为其分配一个SessionId。
      1、两个问题:
    1)什么东西可以让你每次请求都把SessionId自动带到服务器呢?显然就是cookie了,如果你想为用户建立一次会话,可以在用户授权成功时给他一个唯一的cookie。当一个
    用户提交了表单时,浏览器会将用户的SessionId自动附加在HTTP头信息中,(这是浏览器的自动功能,用户不会察觉到),当服务器处理完这个表单后,将结果返回给SessionId
    所对应的用户。试想,如果没有 SessionId,当有两个用户同时进行注册时,服务器怎样才能知道到底是哪个用户提交了哪个表单呢。
    2)储存需要的信息。服务器通过SessionId作为key,读写到对应的value,这就达到了保持会话信息的目的。
      2、session的创建:
    当程序需要为某个客户端的请求创建一个session时,服务器首先检查这个客户端的请求里是否已包含了sessionId,如果已包含则说明以前已经为此客户端创建过session,服务
    器就按照sessionId把这个session检索出来使用(检索不到,会新建一个),如果客户端请求不包含sessionId,则为此客户端创建一个session并且生成一个与此session相关
    联的sessionId,sessionId的值是一个既不会重复,又不容易被找到规律以仿造的字符串,这个sessionId将被在本次响应中返回给客户端保存。
      3、禁用cookie:
      如果客户端禁用了cookie,通常有两种方法实现session而不依赖cookie。
    1)URL重写,就是把sessionId直接附加在URL路径的后面。
    2)表单隐藏字段。就是服务器会自动修改表单,添加一个隐藏字段,以便在表单提交时能够把session id传递回服务器。比如: 
    <form name="testform" action="/xxx"> 
    <input type="hidden" name="jsessionid" value="ByOK3vjFD75aPnrF7C2HmdnV6QZcEbzWoWiBYEnLerjQ99zWpBng!-145788764"> 
    <input type="text"> 
    </form> 
      4、Session共享:
    对于多网站(同一父域不同子域)单服务器,我们需要解决的就是来自不同网站之间SessionId的共享。由于域名不同(aaa.test.com和bbb.test.com),而SessionId又分别储存
    在各自的cookie中,因此服务器会认为对于两个子站的访问,是来自不同的会话。解决的方法是通过修改cookies的域名为父域名达到cookie共享的目的,从而实现SessionId的共
    享。带来的弊端就是,子站间的cookie信息也同时被共享了。  
    四. 总结
    1、cookie数据存放在客户的浏览器上,session数据放在服务器上。
    2、cookie不是很安全,别人可以分析存放在本地的cookie并进行cookie欺骗,考虑到安全应当使用session。
    3、session会在一定时间内保存在服务器上。当访问增多,会比较占用你服务器的性能,考虑到减轻服务器性能方面,应当使用cookie。
    4、单个cookie保存的数据不能超过4K,很多浏览器都限制一个站点最多保存20个cookie。
    5、可以考虑将登陆信息等重要信息存放为session,其他信息如果需要保留,可以放在cookie中。
    理论

    cookie和Django中操作cookie

     

    cookie

     

    • cookie的由来

    HTTP协议是无状态的。

    无状态的意思是每次请求都是独立的,它的执行情况和结果与前面的请求和之后的请求都无直接关系,

    它不会受前面的请求响应情况直接影响,也不会直接影响后面的请求响应情况。

    一句有意思的话来描述就是人生只如初见,对服务器来说,每次的请求都是全新的。

    状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会

    话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。

    • 什么是cookie

      cookie具体指的是一段小信息,他它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服

      务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

    • cookie的原理

      cookie的工作原理是:由服务器产生内容,浏览器收到请求后保存到本地;当浏览器再次访问时,浏

      览器会自动带上cookie,这样服务器就能通过cookie的内容来判断这个是“谁了”。

    • 查看cookie

      开发者工具->Network->Cookies

     

    Django中操作cookie

     

    • 获取cookie

      request.COOKIES['key']
      request.get_signed_cookie('key', default=RAISE_ERROR, salt='', max_age=None)
      • get_segned_cookie方法的参数:

        • default:默认值

        • salt:加密盐

        • max_age:后台控制过期时间

    • 设置cookie

      req = HrttpRequest(...)
      req = render(request, ...)

      req.set_cookie(key, values, ...)
      req.set_signed_cookie(key, value, salt='加密盐', ...)
      • 参数

        • key:键

        • value="":值

        • max_age=None:超时时间

        • expires=None, 超时时间(IE requires expires, so set it if hasn't been already.)

        • path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问

        • domain=None:cookie生效的域名

        • secure=False:https传输

        • httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也

          可以被覆盖)

    • 删除cookie

      def logout(request):
         req = redirect("/login/")
         req.delete_cookie("user")  # 删除用户浏览器上之前设置的user的cookie值
      • cookie版登录校验

        def check_login(func):
           @wraps(func)
           def inner(request, *args, **kwargs):
               next_url = request.get_full_path()
               if request.get_signed_cookie("login", salt="SSS", default=None) == "yes":
                   # 已经登录的用户...
                   return func(request, *args, **kwargs)
               else:
                   # 没有登录的用户,跳转刚到登录页面
                   return redirect("/login/?next={}".format(next_url))
           return inner


        def login(request):
           if request.method == "POST":
               username = request.POST.get("username")
               passwd = request.POST.get("password")
               if username == "xxx" and passwd == "dashabi":
                   next_url = request.GET.get("next")
                   if next_url and next_url != "/logout/":
                       response = redirect(next_url)
                   else:
                       response = redirect("/class_list/")
                   response.set_signed_cookie("login", "yes", salt="SSS")
                   return response
           return render(request, "login.html")

         

     

    session和Django中操作session

     

    session

     

    • session的由来

      Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及

      Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并

      且他保存在服务器,有较高的安全性。这就是Session。

      问题来了,基于HTTP协议的无状态特征,服务器根本就不知道访问者是“谁”。那么上述的Cookie就

      起到桥接的作用。

      我们可以给每个客户端的Cookie分配一个唯一的id,这样用户在访问时,通过Cookie,服务器就知

      道来的人是“谁”。然后我们再根据不同的Cookie的id,在服务器上保存一段时间的私密资料,如“账号密

      码”等等。

      总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形

      式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密

      的信息以及超过4096字节的文本。

      另外,上述所说的Cookie和Session其实是共通性的东西,不限于语言和框架

    Django中操作session

     

    # 获取、设置、删除session中数据
    request.session['k1']
    request.session.get('k1', None)
    request.session['k1'] = 123
    request.session.setdefault('k1', 123)  # 存在就不设置
    del request.session['k1']

    # 所有 键、值、键值对
    request.session.keys()
    request.session.values()
    request.session.items()
    request.session.iterkeys()
    request.session.itervalues()
    request.session.iteritems()

    # 回话session的key
    request.session.session_key

    # 将所有session失效日期小于当前日期的数据删除
    request.session.clear_expired()

    # 检查会话session的key在数据库中是否存在
    request.session.exists("session_key")

    # 删除当前会话的所有Session数据
    request.session.delete()
      
    # 删除当前的会话数据并删除会话的Cookie。
    request.session.flush()
       这用于确保前面的会话数据不可以再次被用户的浏览器访问
       例如,django.contrib.auth.logout() 函数中就会调用它。

    # 设置会话Session和Cookie的超时时间
    request.session.set_expiry(value)
       * 如果value是个整数,session会在些秒数后失效。
       * 如果value是个datatime或timedelta,session就会在这个时间后失效。
       * 如果value是0,用户关闭浏览器session就会失效。
       * 如果value是None,session会依赖全局session失效策略。
    • session版登录验证

      from functools import wraps


      def check_login(func):
         @wraps(func)
         def inner(request, *args, **kwargs):
             next_url = request.get_full_path()
             if request.session.get("user"):
                 return func(request, *args, **kwargs)
             else:
                 return redirect("/login/?next={}".format(next_url))
         return inner


      def login(request):
         if request.method == "POST":
             user = request.POST.get("user")
             pwd = request.POST.get("pwd")

             if user == "alex" and pwd == "alex1234":
                 # 设置session
                 request.session["user"] = user
                 # 获取跳到登陆页面之前的URL
                 next_url = request.GET.get("next")
                 # 如果有,就跳转回登陆之前的URL
                 if next_url:
                     return redirect(next_url)
                 # 否则默认跳转到index页面
                 else:
                     return redirect("/index/")
         return render(request, "login.html")


      @check_login
      def logout(request):
         # 删除所有当前请求相关的session
         request.session.delete()
         return redirect("/login/")


      @check_login
      def index(request):
         current_user = request.session.get("user", None)
         return render(request, "index.html", {"user": current_user})

       

    • Django中的settings配置

      Django中默认支持session,其内部提供了5种类型的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,默认修改之后才保存(默认)

      Django中Session相关设置

       

     

  • 相关阅读:
    C#异常断电后重新启动项目出现配置未初始化错误
    TFS: 解决The build agent error
    删除TFS中的项目
    将现有项目添加到TFS中
    Typora开启行内公式
    Markdown上下标内容多于一项
    小甲鱼python基础教程飞机大战源码及素材
    Git 将本地库添加到远程仓库
    C# float与UInt16互转
    C++的重载流输出运算符
  • 原文地址:https://www.cnblogs.com/xiao-xue-di/p/9780350.html
Copyright © 2011-2022 走看看