GVKun编程网logo

Django组件-cookie和session(django的cookie和session)

15

如果您想了解Django组件-cookie和session的相关知识,那么本文是一篇不可错过的文章,我们将对django的cookie和session进行全面详尽的解释,并且为您提供关于12Djang

如果您想了解Django组件-cookie和session的相关知识,那么本文是一篇不可错过的文章,我们将对django的cookie和session进行全面详尽的解释,并且为您提供关于12 Django之Cookie和Session、63 Django -- cookie和session、cookie和session django中间件、Django - cookie和session的有价值的信息。

本文目录一览:

Django组件-cookie和session(django的cookie和session)

Django组件-cookie和session(django的cookie和session)

会话跟踪技术

先了解一下什么是会话!把会话理解为客户端与服务器之间的一次会晤,在一次会晤中可能会包含多次请求和响应。例如你给10000打个电话,你就是客户端,而10000服务人员就是服务器了。从双方接通电话那一刻起,会话就开始了,到某一方挂断电话表示会话结束。在通话过程中,你会向10000发出多个请求,那么这多个请求都在一个会话中。
会话路径技术使用Cookie或session完成

HTTP协议是无状态协议,也就是说每个请求都是独立的!无法记录前一次请求的状态。但HTTP协议中可以使用Cookie来完成会话跟踪!在Web开发中,使用session来完成会话跟踪,session底层依赖Cookie技术。

Cookie概述

Cookie翻译成中文是小甜点,小饼干的意思。在HTTP中它表示服务器送给客户端浏览器的小甜点。其实Cookie是key-value结构,类似于一个python中的字典。随着服务器端的响应发送给客户端浏览器。然后客户端浏览器会把Cookie保存起来,当下一次再访问服务器时把Cookie再发送给服务器。 Cookie是由服务器创建,然后通过响应发送给客户端的一个键值对。客户端会保存Cookie,并会标注出Cookie的来源(哪个服务器的Cookie)。当客户端向服务器发出请求时会把所有这个服务器Cookie包含在请求中发送给服务器,这样服务器就可以识别客户端了!

Cookie规范

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

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

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

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

django中的cookie语法
设置cookie:

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

获取cookie:

request.COOKIES

删除cookie:

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

 

session

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

django中session语法

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的随机字符串
        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失效策略。

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,默认修改之后才保存(默认)

12 Django之Cookie和Session

12 Django之Cookie和Session

一、什么是Cookie

  

Cookie的由来

    大家都知道HTTP协议是无状态的。

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

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

    状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。

              并且还有一个问题就是,你登陆我的网站的时候,我没法确定你是不是登陆了,之前我们学的django,虽然写了很多页面,但是用户不用登陆都是可以看所有网页的,只要他知道网址就行,但是我们为了自己的安全机制,我们是不是要做验证啊,访问哪一个网址,都要验证用户的身份,但是还有保证什么呢,用户登陆过之后,还要保证登陆了的用户不需要再重复登陆,就能够访问我网站的其他的网址的页面,对不对,但是http无状态啊,怎么保证这个事情呢?此时就要找cookie了。

  什么是Cookie

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

  Cookie的原理

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

  查看Cookie

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

  

  cookie图解

    

  

  Cookie规范 

  •  Cookie大小上限为4KB; 
  •  一个服务器最多在客户端浏览器上保存20个Cookie; 
  •  一个浏览器最多保存300个Cookie,因为一个浏览器可以访问多个服务器。

    上面的数据只是HTTP的Cookie规范,但在浏览器大战的今天,一些浏览器为了打败对手,为了展现自己的能力起见,可能对Cookie规范“扩展”了一些,例如每个Cookie的大小为8KB,最多可保存500个Cookie等!但也不会出现把你硬盘占满的可能! 
注意,不同浏览器之间是不共享Cookie的。也就是说在你使用IE访问服务器时,服务器会把Cookie发给IE,然后由IE保存起来,当你在使用FireFox访问服务器时,不可能把IE保存的Cookie发送给服务器。

  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  

  Cookie的覆盖 

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

二、Django操作Cookie

  Ctrl + Shift + del三个键来清除页面缓存和cookie,将来这个操作你会用的很多。

  获取Cookie

request.COOKIES[''key'']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='''', max_age=None)

    参数:

      default: 默认值

      salt: 加密盐

      max_age: 后台控制过期时间

  设置Cookie

rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.set_signed_cookie(key,value,salt=''加密盐'', max_age=None, ...)

    参数:

      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获取(不是绝对,底层抓包可以获取到也可以被覆盖)

    set_cookie方法源码

class HttpResponseBase:

        def set_cookie(self, key,                 键
                     value='''',            值
                     max_age=None,        超长时间 ,有效事件,max_age=20意思是这个cookie20秒后就消失了,默认时长是2周,这个是以秒为单位的
                              cookie需要延续的时间(以秒为单位)
                              如果参数是\ None`` ,这个cookie会延续到浏览器关闭为止。

                     expires=None,        超长时间,值是一个datetime类型的时间日期对象,到这个日期就失效的意思,用的不多
                                 expires默认None ,cookie失效的实际日期/时间。 
                                

                     path=''/'',           Cookie生效的路径,就是访问哪个路径可以得到cookie,''/''是所有路径都能获得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

  删除Cookie

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

  jQuery操作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

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

 

    

  Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。

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

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

  总结而言:Cookie弥补了HTTP无状态的不足,让服务器知道来的人是“谁”;但是Cookie以文本的形式保存在本地,自身安全性较差;所以我们就通过Cookie识别不同的用户,对应的在Session里保存私密的信息以及超过4096字节的文本。

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

四、Django操作Session

Django中Session相关方法

   注意:这都是django提供的方法,其他的框架就需要你自己关于cookie和session的方法了。
# 获取、设置、删除Session中数据
#取值 request.session[''k1''] request.session.get(''k1'',None) #request.session这句是帮你从cookie里面将sessionid的值取出来,将django-session表里面的对应sessionid的值的那条记录中的session-data字段的数据给你拿出来(并解密),get方法就取出k1这个键对应的值

#设置值 request.session[''k1''] = 123 request.session.setdefault(''k1'',123) # 存在则不设置
#帮你生成随机字符串,帮你将这个随机字符串和用户数据(加密后)和过期时间保存到了django-session表里面,帮你将这个随机字符串以sessionid:随机字符串的形式添加到cookie里面返回给浏览器,这个sessionid名字是可以改的,以后再说
#但是注意一个事情,django-session这个表,你不能通过orm来直接控制,因为你的models.py里面没有这个对应关系
#删除值
del request.session[''k1'']  #django-session表里面同步删除


# 所有 键、值、键值对
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失效策略。

  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})

   问题:同一个浏览器上,如果一个用户已经登陆了,你如果在通过这个浏览器以另外一个用户来登陆,那么到底是第一个用户的页面还是第二个用户的页面,有同学是不是懵逼了,你想想,一个浏览器和一个网站能保持两个用户的对话吗?你登陆一下博客园试试,第一个用户登陆的时候,没有带着sessionid,第二个用户登陆的时候,带着第一个用户的sessionid,这个值在第二个用户登陆之后,session就被覆盖了,浏览器上的sessionid就是我第二个用户的了,那么你用第一个用户再点击其他内容,你会发现,看到的都是第二个用户的信息(注意:公众都能访问的a标签不算)。还有,你想想是不是你登陆一次就在django-session表里面给你添加一条session记录吗?为什么呢?因为你想,如果是每个用户每次登陆都添加一条sesson的记录,那么这个用户一年要登陆多少次啊,那你需要记录多少次啊,你想想,所以,你每次登陆的时候,都会将你之前登陆的那个session记录给你更新掉,也就是说你登陆的时候,如果你带着一个session_id,那么不是新添加一条记录,用的还是django-session表里面的前面那一次登陆的session_key随机字符串,但是session_data和expire_date都变了,也就是说那条记录的钥匙还是它,但是数据变了,有同学又要问了,那我过了好久才过来再登陆的,那个session_id都没有了啊怎么办,你放心,你浏览器上的session_id没有了的话,你django-session表里的关于你这个用户的session记录肯定被删掉了。再想,登陆之后,你把登陆之后的网址拿到另外一个浏览器上去访问,能访问吗?当然不能啦,另外一个浏览器上有你这个浏览器上的cookie吗,没有cookie能有session吗?如果你再另外一个浏览器上又输入了用户名和密码登陆了,会发生什么事情,django-session表里面会多一条记录,记着,一个网站对一个浏览器,是一个sessionid的,换一个浏览器客户端,肯定会生成另外一个sessionid,django-session表里面的session_key肯定不同,但是session_data字段的数据肯定是一样的,当然了,这个还要看人家的加密规则。

  Django中的Session配置

    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,默认修改之后才保存(默认)

 

  CBV中加装饰器相关

    CBV实现的登录视图

class LoginView(View):

    def get(self, request):
        """
        处理GET请求
        """
        return render(request, ''login.html'')

    def post(self, request):
        """
        处理POST请求 
        """
        user = request.POST.get(''user'')
        pwd = request.POST.get(''pwd'')
        if user == ''alex'' and pwd == "alex1234":
            next_url = request.GET.get("next")
            # 生成随机字符串
            # 写浏览器cookie -> session_id: 随机字符串
            # 写到服务端session:
            # {
            #     "随机字符串": {''user'':''alex''}
            # }
            request.session[''user''] = user
            if next_url:
                return redirect(next_url)
            else:
                return redirect(''/index/'')
        return render(request, ''login.html'')

 

    要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:

    from django.utils.decorators import method_decorator

      1. 加在CBV视图的get或post方法上

from django.utils.decorators import method_decorator


class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")
    
    @method_decorator(check_login)
    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

 

      2. 加在dispatch方法上

from django.utils.decorators import method_decorator


class HomeView(View):

    @method_decorator(check_login)
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

      因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。

 

      3. 直接加在视图类上,但method_decorator必须传 name 关键字参数

        如果get方法和post方法都需要登录校验的话就写两个装饰器。

from django.utils.decorators import method_decorator

@method_decorator(check_login, name="get")
@method_decorator(check_login, name="post")
class HomeView(View):

    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

    补充

      CSRF Token相关装饰器在CBV只能加到dispatch方法上,或者加在视图类上然后name参数指定为dispatch方法。

      备注:

        csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。

        csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。

from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator


class HomeView(View):

    @method_decorator(csrf_exempt)
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

      或者

from django.views.decorators.csrf import csrf_exempt, csrf_protect
from django.utils.decorators import method_decorator


@method_decorator(csrf_exempt, name=''dispatch'')
class HomeView(View):
   
    def dispatch(self, request, *args, **kwargs):
        return super(HomeView, self).dispatch(request, *args, **kwargs)

    def get(self, request):
        return render(request, "home.html")

    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")

 

63 Django -- cookie和session

63 Django -- cookie和session

[TOC]

1. 装饰器

装饰器中加入funtools.wraps装饰,能够保留函数的元数据(函数名、注释)

import functools

def wrapper(f):
	@functools.wraps(f)
    def inner(*args,**kwargs):
        """
        这是inner函数
        """
        return f(*args, **kwargs)
    return inner

def index(a1, a2):
    """
    这是index函数
    """
    return a1+a2

print(index.__name__)	# index
print(index.__doc__)	# 这是index函数

2. Django生命周期

请求进入Django前,有一个WSGI,能够接收请求,并将请求信息封装。

WSGI(Web Server Gateway Interface)就是一种规范,称为web服务网关接口,它定义了使用Python编写的web应用程序与web服务器程序之间的接口格式,实现web应用程序与web服务器程序间的解耦。

常用服务器:wsgiref/uwsgi ,本质是一个socket服务端。

过程:

​ 客户端发来一个请求,WSGI进行接收,并且将那个请求信息封装,然后经过路由系统进行路由匹配,到达视图views,进行业务逻辑处理,进行相应的orm操作以及模板的渲染。最后通过WSGI发送到客户端。

3. cookie

​ 背景:前面学的django,虽然写了很多页面,但是用户不用登陆都是可以看所有网页的,只要他知道网址就行,但是为了自己的安全机制,需要要做验证,访问哪一个网址,都要验证用户的身份,但是还有保证什么呢,用户登陆过之后,还要保证登陆了的用户不需要再重复登陆,就能够访问我网站的其他的网址的页面。但是http无状态啊,怎么保证这个事情呢?此时就要借助cookie了。

​ 定义:cookie是浏览器的技术,Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对,下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。

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

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

Django获取cookie

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

request.COOKIES[''key'']
request.COOKIES.get(''key'')		# 常用

Django设置cookie

def index(request):
    #data = HttpResponse(''字符串'')
    #data = redirect(''路径'')
    data = render(request, ''index.html'')
    data.set_cookie(''key'',values)
    return data

参数:

key		# 键

value=''''	# 值

max_age=None	# 超时时间(失效时间),max_age=20意思是这个cookie20秒后就消失;参数是None ,会延续到浏览器关闭为止。


expires=None	# 超时时间,值是一个datetime类型的时间日期对象,到这个日期就失效的意思

path=''/''	# Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问;''''只能被当前页面访问;''/index/''能被index以及其子路径访问。

domain=None		#Cookie生效的域名

secure=False	# 如果设置为 True ,浏览器将通过HTTPS来回传cookie。

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

通过js设置cookie

document.cookie=''key=yan;path=/''	# js设置

$.cookie(''key'',''yan'', {path:''/''})	# jquery设置

注意:path不同会导致设置不同.

Django删除cookie

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

示例:cookie版登陆校验示例:

views.py文件:

from django.shortcuts import render, HttpResponse, redirect

# Create your views here.
from app01 import models


def login(request):
    """
    用户登录
    :param request:
    :return:
    """
    if request.method == ''GET'':
        return render(request, ''login.html'')

    # 获取登录的用户名和密码
    user = request.POST.get(''user'')
    pwd = request.POST.get(''pwd'')
    
    # 判断用户名与密码是否存在
    user_obj = models.UserInfo.objects.filter(username=user,password=pwd).first()
    
    # 用户登录成功
    if user_obj:
        
        data = redirect(''/index/'')
        data.set_cookie(''xx'', user)
        return data
    # 失败
    return render(request, ''login.html'', {''error'': ''用户名或密码错误''})


def index(request):
    """
    登录成功后跳转的页面
    :param request:
    :return:
    """
    user = request.COOKIES.get(''xx'')
    if not user:
        return render(request, ''login.html'')
    return render(request, ''index.html'', {''user'': user}

应用场景

​ 用户认证、投票、每页默认显示数据

4. session

​ 背景:Cookie虽然在一定程度上解决了“保持状态”的需求,但是由于Cookie本身最大支持4096字节,以及Cookie本身保存在客户端,可能被拦截或窃取,因此就需要有一种新的东西,它能支持更多的字节,并且他保存在服务器,有较高的安全性。这就是Session。

原理过程:session是一种存储数据的方式,依赖于cookie。实现本质: 用户向服务端发送请求,服务端做两件事:一生成随机字符串;二为此用户开辟一个独立的空间来存放当前用户独有的值。视图函数中的业务操作处理完毕后,给用户响应,在响应时会将随机字符串存储到用户浏览器的cookie中。

强调:session中的数据是根据用户相互隔离.

Django设置session值:可以设置多个

request.session[''k1''] = 123        
request.session[''k2''] = 456 

Django取session值

request.session[''k1'']        
request.session.get(''k2'')		# 常用 

Django删除session值

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

request.session.flush()	# 清除session、cookie,多用于退出登录

其他操作

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

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

# 会话session的key
session_key = request.session.session_key  获取sessionid的值(随机字符串)

django的session存储位置,配置文件

默认存放在数据库中

小系统:默认放在数据库即可。

大系统:缓存(redis)

文件:

SESSION_ENGINE = ''django.contrib.sessions.backends.file''  # 引擎
SESSION_FILE_PATH = ''/文件夹/''

缓存(内存)

SESSION_ENGINE = ''django.contrib.sessions.backends.cache'' SESSION_CACHE_ALIAS = ''default''

CACHES = {''default'': {''BACKEND'': ''django.core.cache.backends.locmem.LocMem Cache'',        ''LOCATION'': ''unique-snowflake'',}}

缓存(redis)

SESSION_ENGINE = ''django.contrib.sessions.backends.cache'' SESSION_CACHE_ALIAS = ''default'' CACHES = { "default": {"BACKEND": "django_redis.cache.RedisCache",        	"LOCATION": "redis://127.0.0.1:6379", 
	"OPTIONS": {"CLIENT_CLASS": "django_redis.client.DefaultClient", 			   		"CONNECTION_POOL_KWARGS": {"max_connections": 100}
	# "PASSWORD": "密码",}}}

扩展

django和session相关的配置

SESSION_COOKIE_NAME = "sessionid"  # Session的cookie保存在浏览器上时的key,即: sessionid=随机字符串

SESSION_COOKIE_DOMAIN = None  
# api.baidu.com /www.baidu.com/ xxx.baidu.com  域名

SESSION_COOKIE_PATH = "/"  # Session的cookie 保存的路径

SESSION_COOKIE_HTTPONLY = True  # 是否 Session的cookie只支持http传输,js不能修改

SESSION_COOKIE_AGE = 1209600  # Session的 cookie失效日期(默认2周)

SESSION_EXPIRE_AT_BROWSER_CLOSE = False  # 是否关闭浏览器使得Session过期

SESSION_SAVE_EVERY_REQUEST = False  # 是否每 次请求都保存Session,默认修改之后才保存

django中的session设置过期时间

SESSION_COOKIE_AGE = 1209600  # Session的 cookie失效日期(2周)

示例:使用装饰器,减少代码重复。

views.py文件

def login(request):
    """
    用户登录
    :param request:
    :return:
    """
    if request.method == ''GET'':
        return render(request, ''login.html'')

    # 获取登录的用户名和密码
    user = request.POST.get(''user'')
    pwd = request.POST.get(''pwd'')

    # 判断用户名于密码是否存在
    user_obj = models.UserInfo.objects.filter(username=user,password=pwd).first()

    # 用户登录成功
    if user_obj:
        request.session[''user_name''] = user_obj.username
        request.session[''user_id''] = user_object.pk
        return redirect(''/index/'')
    return render(request, ''login.html'', {''error'': ''用户名或密码错误''})


def auth(func):
    def inner(request, *args, **kwargs):

        name = request.session.get(''user_name'')
        if not name:
            return redirect(''/login/'')
        return func(request, *args, **kwargs)
    return inner

@auth
def index(request):
    """
    登录成功后跳转的页面
    :param request:
    :return:
    """
    return render(request, ''index.html'')

应用场景

​ 用户认证、短信验证过期、权限管理

5. cookie和session的区别

cookie是存储在客户端浏览器上的键值对,发送请求时浏览器会自动携带. 
session是一种存储数据方式,基于cookie实现,将数据存储在服务端(django默认存储到数据库).其本质是: 用户向服务端发送请求,服务端做两件事:生成随机字符 串;为此用户开辟一个独立的空间来存放当前用户独有的值.  
在空间中如何想要设置值:        
request.session[''x1''] = 123        
request.session[''x2''] = 456    
在空间中取值:        
request.session[''x2'']        
request.session.get(''x2'')    
视图函数中的业务操作处理完毕,给用户响应,在响应时会 将随机字符串存储到用户浏览器的cookie中. 

cookie和session django中间件

cookie和session django中间件

[TOC]

一、cookie和session

1. 为什么要有cookie和session

  • 目的是为了保存客户端的用户状态
  • http协议是无状态的

二、cookie

1. 什么是cookie

  • 简单来说,cookie就是保存在客户端浏览器上的键值对
  • 浏览器中保存的cookie即这些键值对是由服务端设置的,再保存到客户端浏览器上。浏览器有权禁止cookie的写入(就是浏览器不保存cookie)

2. django中关于cookie的使用

(1)后端设置cookie

  • 之前在django后端的视图层中,视图函数最后返回的都是HttpResponse对象,但现在,我们操作cookie,则需要使用HttpResponse对象来设置cookie
  • 通过HttpResponse对象.set_cookie(''key'',''value'')语句来设置cookie
  • 实例:在登陆成功时设置cookie
def login(request):
	if request.method == ''POST'':
        username = request.POST.get(''username'')
        password = request.POST.get(''password'')
        if username == ''jason'' and password == ''123'':
            # 登录成功
            old_path = request.GET.get(''next'')  # 登陆成功后要跳转的url(使用登陆认证装饰器在登陆的url后面携带get请求参数——》 ?next=url)
            if old_path:  # 防止用户直接访问的login页面
                obj = redirect(old_path)
            else:
                obj = redirect(''/home/'')  # 默认跳转到首页 当用户没有想要访问的网址
            obj.set_cookie(''whoami'',''jason'')  # 告诉浏览器保存一个键值对
            return obj
    return render(request,''login.html'')

(2)后端获取cookie

  • 通过request.COOKIES.get(key)语句来获取cookie

  • 实例:设计登陆认证装饰器

from functools import wraps  
def login_auth(func):
    @wraps(func)  # wraps作用是 修复被装饰的函数
    def inner(request,*args,**kwargs):
        # 判断当前用户是否登录
        # print(''request.path_info:'',request.path_info)  # 只获取url
        # print(''request.get_full_path():'',request.get_full_path())  # url+get请求的参数
        if request.COOKIES.get(''whoami''):
            res = func(request,*args,**kwargs)
            return res
        else:
            target_path = request.path_info
            return redirect(''/login/?next=%s''%target_path)
    return inner

(3)设置cookie的超时时间

  • cookie的超时时间是指该cookie在浏览器上能够保存的时间,从该cookie在浏览器上出现开始计算。
  • 设置语法:
    • HttpResponse对象.set_cookie(''key'',''value'',max_age=n)
    • HttpResponse对象.set_cookie(''key'',''value'',expires=n)
      • 最后的一个参数都是设置超时时间,并且都是以秒为单位
      • 区别:如果你要给IE浏览器设置cookie的超时时间,你只能用expires

(4)删除cookie

  • 删除cookie会让浏览器立马清楚其保存的响应的键值对

  • 删除语法:HttpResponse对象.delete_cookie(key)

  • 实例:登出/注销功能

@login_auth
def logout(request):
    obj = redirect(''/home/'')
    obj.delete_cookie(''whoami'')
    return obj

三、session

1. 什么是session

  • session是保存在服务端上的键值对,在客户端的cookie中也保留一个session的键。
  • session的工作机制需要依赖于cookie
    • 客户端浏览器上的cookies的其中之一的一个键值对是sessionid:session的键生产的随机字符串
  • session的键其实是世界上唯一的一个字符串,值是我们自定义的一些数据。虽然在我们设置session时,自己给出了一个任意的字符串当做session的key,但是django后端会自动将该key转变成一个世界上唯一的字符串,并且还将这个key对应的值进行加密,最后默认保存在数据库django_session表中(当然也可以通过修改一些设置,让session保存在其他本地文本文件中或内存中)。

2. django中关于session的使用

(1) 设置session

  • 设置session语法:request.session[key] = value

    • 第一次设置的时候可能会报错,是因为你没有执行数据库迁移命令生成django需要用到的一些默认表(django_session)
  • django默认的session失效时间是14天

  • 当执行request.session[key] = value这句语句时发生的事:

    1. djang内部自动帮你调用算法生成一个随机的字符串作为session的key,并把该key对应的值进行加密
    2. 在django_session表中添加数据(数据保存方式: 随机字符串 加密后的数据 失效时间)
    3. 将产生的随机字符串返回给客户端浏览器 让浏览器保存
  • 注意:一个项目中,其数据库的django_session表中,无论有多少个session,通过同一种浏览器设置的session只会保存在一行记录中。不同浏览器设置的session才会保存在不同的行中。

(2)获取session

  • 语法:request.session.get(key)key是我们之前设置session时,指定的key,不是生成的那个随机字符串。
  • 当执行request.session.get(key)时发生的事:
    1. django内部会自动去请求头里面获取cookie
    2. 拿着sessionid所对应的随机字符串去django_sessoion表中一一比对
    3. 如果比对上了,会将随机字符串对应的数据获取出来,自动放入request.session中供程序员调用,如果没有就是一个空字典

(3)设置失效时间

  • 语法:request.session.set_expiry(value)

    • 如果value是个整数,session会在些秒数后失效。
    • 如果value是个datatime或timedelta,session就会在这个时间后失效。
    • 如果value是0,用户关闭浏览器session就会失效。
    • 如果value是None,session会依赖全局session失效策略。
  • 失效时间是指到了这个时间,保存在服务端的django_session表中的这个session数据就没用了。之后会被删除。且客户端浏览器上的sessionid的这个cookie也会失效。

(4)删除session

  • 语法:
    • request.session.delete()
      • 客户端和服务端的关于session的会全部删除,数据库中只会根据浏览器的不同删对应的数据
    • request.session.flush()
      • 该方法只会删除浏览器上的sessionid的那个cookie,服务端的只会到了失效时间后再删除(建议使用这个)

四、token

  • 也比较常用的一种类似session的东西
  • 点我查看token详情

五、django中间件

  • django中间件的作用非常强大,请求数据到后端要经过中间件,视图函数响应的数据(return返回的数据)也要经过中间件。
  • 数据在通过中间件时,中间件都有各自独立的功能,在特定情况下对数据做相应的处理。
  • django默认有七个中间件
  • django支持自定义中间件
  • django中间件的作用
    1. 全局的用户登录校验
    2. 全局的用户访问频率校验
    3. 全局的用户权限校验()

1. 数据通过django中间件的流程

(1)正常流程

  • 请求数据到django后端的django中间件后,按照从上到下的顺序依次通过settings文件中MIDDLEWARE中书写的各个中间件——》
  • 数据到视图层,视图层再返回响应数据——》
  • 响应数据再按照从下到上的顺序依次通过settings文件中MIDDLEWARE中书写的各个中间件。

(2)特殊情况

  • 当中间件中的process_request 方法返回了一个HttpResponse对象,那么请求会立刻停止往后面走(下面的中间件和之后的视图函数都不走),立即原路返回

2. django中间件中常用的方法

  • django各个中间件中一般都含有一个process_request process_response 方法
  • 这些方法都含有request形参,放在self之后
  • 如果形参中含有response 那么必须要返回,若返回其他,则响应数据就会变成其他。

(1)process_request

  • 请求来的时候会按照settings配置文件中从上往下的顺序,依次执行每一个中间件内部定义的process_request方法

  • 当请求数据走到中间件时,会执行该方法。若该中间件没有该方法,则会跳过该中间件继续走下一个中间件

  • 该方法一旦返回了HttpResponse对象,那么请求会立刻停止往后走,立即原路返回(当process_request方法直接返回HttpResponse对象之后,会直接从当前中间件里面的process_respone往回走)

  • 方法参数:

    def process_request(self,request):
    

(2)process_response

  • 视图函数返回的响应数据走的时候,会按照settings配置文件中从下往上的顺序,依次执行每一个中间件内部定义的process_response方法

  • 该方法必须有两个形参request,response,并且必须返回response形参,不返回直接报错

  • 该方法返回什么(HttpResponsed对象) 前端就能获得什么,即该方法返回的数据会覆盖掉之前视图函数返回的响应数据。并且若该中间件上面的中间件的process_response方法也返回了HttpResponsed对象,则会再把该中间件的返回数据再覆盖掉。

  • 方法参数:

    def process_response(self,request,response):
    

(3)process_view

  • 路由匹配成功之后执行视图函数之前触发该方法

  • 如果该方法返回了HttpResponse对象 那么会从下往上一次经过每一个中间件里面的process_response方法

  • 方法参数:

    def process_view(self,request,view_name,*args,**kwargs):
    
    # view_name 是要执行的视图函数的内存地址  
    

(4)process_template_response

  • 当你返回的对象中含有render属性指向的是一个render方法的时候才会触发,从下往上的顺序

  • 方法参数:

    def process_template_response(self, request, response):
    
  • 实例

# 让后端视图函数中返回的对象含有render属性的方式
def mdzz(request):
	print(''我是视图函数mdzz'')  
	def render():
		return HttpResponse(''你好呀 我是奇葩'')
	obj = HttpResponse(''我很好 好的像个傻逼一样'')
	obj.render = render
	return obj

# 响应数据变成了: 我是视图函数mdzz

(5)process_exception

  • 当视图函数中出现错误,会自动触发,顺序是从下往上

  • 方法参数:

    def process_exception(self, request, exception):
    

3. 自定义中间件

  • 注意:django暴露给用户五个可以自定义的方法(就是上面提到的5个django中间件常用的方法)来自定义中间件

(1)自定义中间件的步骤

  1. 在应用文件下(如:app01)新建一个任意名字的文件夹(如:mymddleware)

  2. 在mymddleware文件下新建一个任意名字的py文件(如:mymdd.py)

  3. 导入方法

    from django.utils.deprecation import MiddlewareMixin
    from django.shortcuts import HttpResponse,render,redirect
    
  4. 在mymdd文件中自定义类,一个类就是一个中间件。类内部写上面提到的5个django中间件中常用的方法

  5. 在settings文件的MIDDLEWARE变量值中添加自定义的中间件路径

    MIDDLEWARE = [
        ''django.middleware.security.SecurityMiddleware'',
        ''django.contrib.sessions.middleware.SessionMiddleware'',
        ''django.middleware.common.CommonMiddleware'',
        ''django.middleware.csrf.CsrfViewMiddleware'',
        ''django.contrib.auth.middleware.AuthenticationMiddleware'',
        ''django.contrib.messages.middleware.MessageMiddleware'',
        ''django.middleware.clickjacking.XFrameOptionsMiddleware'',
        ''app01.mymiddleware.mymdd.MyMdd1'',  # 添加自定义中间件
        ''app01.mymiddleware.mymdd.MyMdd2'',  # 添加自定义中间件
    ]
    

(2)自定义django中间件实例

class MyMdd1(MiddlewareMixin):
    def process_request(self,request):
        print(''我是第一个中间件里面的process_request方法'')
        # return HttpResponse("我是中间件一里面的")

    def process_response(self,request,response):
        """
        :param request:
        :param response: 就是后端返回给前端的数据
        :return:
        """
        print(''我是第一个中间件里面的process_response方法'')
        return response
        # return HttpResponse("我是中间件一里面的")

    def process_view(self,request,view_name,*args,**kwargs):
        print(view_name)
        print(args)
        print(kwargs)
        print(''我是第一个中间件里面的process_view方法'')
        # return HttpResponse("我是中间件一里面的process_view")

    def process_exception(self,request,exception):
        print(''我是第一个中间件里面的process_exception'')
        print(exception)

    def process_template_response(self, request, response):
        print(''我是第一个中间件里面的奇葩方法'')
        return response
    
class MyMdd2(MiddlewareMixin):
    def process_request(self,request):
        print(''我是第二个中间件里面的process_request方法'')
        # return HttpResponse(''我是中间件二里面的'')

    def process_response(self,request,response):
        """
        :param request:
        :param response: 就是后端返回给前端的数据
        :return:
        """
        print(''我是第二个中间件里面的process_response方法'')
        return response

        # return HttpResponse("我是中间件二里面的")
    def process_view(self,request,view_name,*args,**kwargs):
        print(view_name)
        print(args)
        print(kwargs)
        print(''我是第二个中间件里面的process_view方法'')
        # return HttpResponse("我是中间件二里面的process_view")

    def process_exception(self, request, exception):
        print(''我是第二个中间件里面的process_exception'')
        print(exception)

    def process_template_response(self, request, response):
        print(''我是第二个中间件里面的奇葩方法'')
        return response    

Django - cookie和session

Django - cookie和session

 

 

HTTP协议的无状态保存:

    一个浏览器向一个服务器发送一个请求,服务器这边视图函数处理之后在返回数据给浏览器,浏览器解析出来这样一个过程

    多个这种过程之间没有任何关联

    但是实际过程中我们有时候会需要他们之间有关联,比如说,登录淘宝,淘宝这边需要你登录之后才给你看相应的一些页面,
此时,之前登录是一个过程,现在访问页面是一个过程,需要构建两次过程之间的关联(会话跟踪技术)


cookie简介:具体一个浏览器,针对一个服务器,存储的key-value结构

    只要设置了cookie之后,在cookie的有效期内,这个浏览器访问这个服务器的时候都会带着这个cookie;



由于cookie可以直接将用户信息暴露在浏览器(客户端),所以会带来不安全性,这时候就需要Session,数据直接存储在服务端


1. response.set_cookie(key, value)  # 设置cookie

2. request.COOKIE.get(key)  # 获取cookie

3. request.session[key] = value  # 写session
    注意django对应的操作
    ''''''
            登录页面的时候,如果是第一次登录,则按照下面的三步走,如果不是,则就更新数据
            django-session表中一条记录只针对一个浏览器

            if request.COOKIE.get("sessionid"):
                更新

                 在django-session表中创建一条记录:
                    session-key                           session-data                            expire-date
                    lik1wdki4dis0ovp944takdggc07i56o        更新数据

            else

                1.生成随机字符串 lik1wdki4dis0ovp944takdggc07i56o
                2.response.set_cookie("sessionid",lik1wdki4dis0ovp944takdggc07i56o)
                3.在django-session表中创建一条记录:
                    session-key                           session-data                            expire-date
                    lik1wdki4dis0ovp944takdggc07i56o     {"is_login":True,"username":user.user}
            ''''''

4. request.session.get(key)      # 读session

    ''''''
        1.request.COOKIE.get("sessionid")  lik1wdki4dis0ovp944takdggc07i56o
        2.django-session表中过滤记录:

            session-key                           session-data                            expire-date
            lik1wdki4dis0ovp944takdggc07i56o     {"is_login":True,"username":user.user}

          obj = django-session.objects.filter(session-key=lik1wdki4dis0ovp944takdggc07i56o).first()
        3.obj.session-data.get("is_login")
    ''''''

5. request.session.flush()

    ''''''
        flush():
            删除当前的会话数据并删除会话的Cookie
            适用于确保前面的会话数据不可以再次被用户的浏览器访问

    1.random_str = request.COOKIE.get("sessionid)  # 获得随机字符
    2.django-session.objects.filter(session-key=random_str).delete() # 在django-session表中删除这条记录
    3.response.delete_cookie("sessionid,random_str)  # 删除cookie
    ''''''


###############################################################################################################

1. Cookie和Session
        1. Cookie

        服务端:
            1. 生成字符串
            2. 随着响应将字符串回复给浏览器
            3. 从浏览器发送的请求中拿到字符串

        cookie就是保存在浏览器上的字符串!!!
        每一次请求都会携带着cookie

        把要保存的信息都保存在用户的浏览器上
        好处:
            服务端不用存,减轻了服务器压力
        坏处:
            信息不安全


    Session:
        搭配Cookie使用

        Session本质上,保存在服务端的键值对。
        好处:
            用户的信息都保存在服务端,安全
        坏处:
            数据都保存在服务端,存储压力比较大

    cookie和Session应用场景:
        登录
        刷票限制
        保存用户的浏览习惯

    Django中使用Session:
         获取、设置、删除Session中数据
        request.session[''k1'']
        request.session.get(''k1'',None)
        request.session[''k1''] = 123
        request.session.setdefault(''k1'',123) # 存在则不设置


        # 删除当前用户的所有Session数据
        request.session.delete()

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

###############################################################################################################

1.cookie
        本质上就是保存在浏览器上得键值对
        为了解决HTTP请求是无状态得

        可以用来做登录 7天免登录 浏览习惯 (每页显示多少条)
        Django 操作Cookie
            1.设置Cookie 是在response对象
                1.明文的
                    rep = 响应对象(基础必备三件套)
                    rep.set_cookie(key,value,..)
                2.加盐的
                    rep = 响应对象(基础必备三件套)
                    rep.set_signed_cookie(key,value,salt=''加密盐)

            2.获取Cookie 是在request对象
                1.明文的
                    request.COOKIES.get(''key'') / request.COOKIES[''key'']
                2.加盐的
                   request.get_signed_cookie(key, default="默认值", salt='''', max_age=None)

    2.session
        1.定义
            保存在服务器端的键值对,依赖与Cookie

        2.Django的session 操作
            1.设置session
                request.session[''k1'']
                request.session.setdefault(''k1'',123) # 存在则不设置
            2.获取session
                request.session.get(''k1'',None)
                request.session[''k1'']
            3.删除session
                del request.session[''k1'']
                注销之后删除用户所有的session数据
                request.session.delete()
            4.将所有Session失效日期小于当前日期的数据删除
                request.session.clear_expired()

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

一.Cookie

Cookie的由来

大家都知道HTTP协议是无状态的。

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

状态可以理解为客户端和服务器在某次会话中产生的数据,那无状态的就以为这些数据不会被保留。会话中产生的数据又是我们需要保存的,也就是说要“保持状态”。因此Cookie就是在这样一个场景下诞生。(会话跟踪技术)

什么是Cookie

Cookie具体指的是一段小信息,它是服务器发送出来存储在浏览器上的一组组键值对(具体一个浏览器针对一个服务器),下次访问服务器时浏览器会自动携带这些键值对,以便服务器提取有用信息。(类似于python字典的key-value结构)

Cookie的原理

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

Cookie规范

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

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

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

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

查看Cookie

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

 

Django中操作Cookie

获取Cookie

request.COOKIES[''key'']
request.get_signed_cookie(key, default=RAISE_ERROR, salt='''', max_age=None)

参数:

  • default: 默认值
  • salt: 加密盐
  • max_age: 后台控制过期时间

设置Cookie

rep = HttpResponse(...)
rep = render(request, ...)

rep.set_cookie(key,value,...)
rep.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):
    rep = redirect("/login/")
    rep.delete_cookie("user")  # 删除用户浏览器上之前设置的usercookie值
    return rep

 

Cookie版登陆验证

   models.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)

 

  views.py

# -*- encoding:utf-8 -*-
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from app01.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:
            # 登录成功
            ''''''
            响应体:
            return HttpResponse()
            return render()
            return redirect()
            ''''''

            ''''''
            设置cookie的超时参数:
            max_age=15,这里的单位是秒,超时意义是15秒后过期
            
            expires=date,超时意义是过了这个固定时间过期
            
            ''''''
            response = HttpResponse("登录成功!")
            # response.set_cookie("is_login", True,max_age=15)  # 响应体调用set_cookie
            response.set_cookie("is_login", True)  # 响应体调用set_cookie

            import datetime
            # date = datetime.datetime(year=2019, month=2, day=13, hour=9, minute=21)  # 因为是东8区,所以这里的小时要减去8
            # response.set_cookie("username", user.user, expires=date) # 将用户名存储在cookie中,方便后面在首页显示姓名
            response.set_cookie("username", user.user, path="/index/")  

            ''''''
            有效路径参数:
            path="/index/",意思就是只有在index这个视图函数下才能获得当前cookie
            ''''''

            return response

    return render(request,"login.html")


def index(request):

    print(request.COOKIES)

    is_login = request.COOKIES.get("is_login")  # 获取cookie

    if is_login:  # 如果登录成功
        username = request.COOKIES.get("username")

        last_time = request.COOKIES.get("last_time") # 上次登录时间,首次为None
        import datetime
        date = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S") # 获取当前时间,格式化
        response = render(request, "index.html", {"username": username, "last_time": last_time}) # 将从cookie中获取的last_time映射到网页中 
        response.set_cookie("last_time", date) # 设置last_time为cookie中的键值对
        return response
    else:
        return redirect("/login/")   # 二者区别?
        # return render(request, "login.html")


def test(request):

    print("test:", request.COOKIES)

    return HttpResponse("Test!")

''''''
    response.set_cookie("is_login", True):设置cookie
    request.COOKIES:获取cookie
    response.delete_cookie("cookie_key",path=''/'',domain=name):删除cookie
''''''

 

  login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <form action="" method="post">
        {% csrf_token %}
        用户名 <input type="text" name="user">
        密码 <input type="password" name="pwd">
        <input type="submit" value="submit">
    </form>

</body>
</html>

 

   index.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>

    <h3>Hi,{{ username }},welcome to Index</h3>
    <p>您上次登录时间:{{ last_time }}</p>   # 保存上次访问时间
    <a href="/logout/">注销</a>    # 后面注销的时候备用

</body>
</html>

 

访问login页面:

 

访问index页面的时候,它是带着cookie的

  一次登录成功了设置好了cookie,以后什么时候都带着cookie;当你换一个浏览器访问的时候又是新的了;浏览器和服务器请求要是一对一的,当你在这个页面带着cookie时,比如去访问京东这个cookie就没有了;

    如果登录另外一个人的账号,就会把之前的那个cookie值给覆盖掉。

 

 二.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流程解析

 

 Session版登陆验证,保存上次登录时间,session更新操作和注销功能

   views.py

# -*- encoding:utf-8 -*-
from django.shortcuts import render,HttpResponse,redirect

# Create your views here.
from app01.models import UserInfo

# Session登录视图
def login_session(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:
            request.session["is_login"] = True      # 设置session的键值
            request.session[''username''] = user.user

            ''''''
            登录页面的时候,如果是第一次登录,则按照下面的三步走,如果不是,则就更新数据
            django-session表中一条记录只针对一个浏览器
            
            if request.COOKIE.get("sessionid"):
                更新
            
                 在django-session表中创建一条记录:
                    session-key                           session-data                            expire-date
                    lik1wdki4dis0ovp944takdggc07i56o        更新数据
           
            else
            
                1.生成随机字符串 lik1wdki4dis0ovp944takdggc07i56o
                2.response.set_cookie("sessionid",lik1wdki4dis0ovp944takdggc07i56o)
                3.在django-session表中创建一条记录:
                    session-key                           session-data                            expire-date
                    lik1wdki4dis0ovp944takdggc07i56o     {"is_login":True,"username":user.user}
            ''''''

            return HttpResponse("登录成功")


    return render(request,"login.html")


def index_session(request):

    print("is_login:", request.session.get("is_login"))  # 从session中取值 # 这一句话会产生以下三步操作

    ''''''
        1.request.COOKIE.get("sessionid")  lik1wdki4dis0ovp944takdggc07i56o
        2.django-session表中过滤记录:
        
            session-key                           session-data                            expire-date
            lik1wdki4dis0ovp944takdggc07i56o     {"is_login":True,"username":user.user}
       
          obj = django-session.objects.filter(session-key=lik1wdki4dis0ovp944takdggc07i56o).first()
        3.obj.session-data.get("is_login")
    ''''''

    is_login = request.session.get("is_login")
    if not is_login:
        return redirect("/login_session/")

    username = request.session.get("username")
    last_time = request.session.get("last_time")

    import datetime
    date = datetime.datetime.now().strftime("%Y-%m-%d %X")
    request.session[''last_time''] = date
    return render(request, "index.html", {"username": username, "last_time": last_time})


# 注销
def logout(request):

    # del request.session["is_login"]  # 这种语法仅仅是删除一个键值对

    request.session.flush()

    ''''''
        flush():
            删除当前的会话数据并删除会话的Cookie
            适用于确保前面的会话数据不可以再次被用户的浏览器访问
    
    1.random_str = request.COOKIE.get("sessionid)  # 获得随机字符
    2.django-session.objects.filter(session-key=random_str).delete() # 在django-session表中删除这条记录
    3.response.delete_cookie("sessionid,random_str)  # 删除cookie
    ''''''

    return redirect( "/login/")

 

django-session表中的数据:

 

Django中的Session配置

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组件-cookie和sessiondjango的cookie和session的介绍现已完结,谢谢您的耐心阅读,如果想了解更多关于12 Django之Cookie和Session、63 Django -- cookie和session、cookie和session django中间件、Django - cookie和session的相关知识,请在本站寻找。

本文标签: