Django框架之六-->Cookie和Session

会话(Session)跟踪是Web程序中常用的技术,用来跟踪用户的整个会话。常用的会话跟踪技术是Cookie与Session。Cookie通过在客户端记录信息确定用户身份,Session通过在服务器端记录信息确定用户身份。

Cookie(储存在用户本地终端上的数据)

Cookie,有时也用其复数形式 Cookies,指某些网站为了辨别用户身份、进行 session 跟踪而储存在用户本地终端上的数据(通常经过加密)。

  HTTP协议是一种无状态协议,在数据交换完毕后,服务器端和客户端的链接就会关闭,每次交换数据都需要建立新的链接。这就需要在请求中存放一段可以让客户端区分服务端的内容,这段内容就是Cookie.

  Cookie就是由服务器发给客户端的特殊信息,而这些信息以文本文件的方式存放在客户端,然后客户端每次向服务器发送请求的时候都会带上这些特殊的信息。

  Cookie特性:    

    1. 服务端可以在浏览器上设置COOKIE 保存在浏览器上的
    2. 每次请求会携带COOKIE
    3. Cookie是有效时间的
    4. 可以用来做登录或其他事情

提示:Cookie中保存中文只能编码。一般使用UTF-8编码即可。不推荐使用GBK等中文编码,因为浏览器不一定支持,而且JavaScript也不支持GBK编码。

# 来自https://my.oschina.net/xianggao/blog/395675?fromerr=GC9KVenE
当用户使用浏览器访问一个支持Cookie的网站的时候,用户会提供包括用户名在内的个人信息并且提交至服务器; 
接着,服务器在向客户端回传相应的超文本的同时也会发回这些个人信息,当然这些信息并不是存放在HTTP响应体(Response Body)中的, 
而是存放于HTTP响应头(Response Header);当客户端浏览器接收到来自服务器的响应之后,浏览器会将这些信息存放在一个统一的位置, 
对于Windows操作系统而言,我们可以从: [系统盘]:\Documents and Settings\[用户名]\Cookies目录中找到存储的Cookie;自此, 
客户端再向服务器发送请求的时候,都会把相应的Cookie再次发回至服务器。而这次,Cookie信息则存放在HTTP请求头(Request Header)了。 
有了Cookie这样的技术实现,服务器在接收到来自客户端浏览器的请求之后,就能够通过分析存放于请求头的Cookie得到客户端特有的信息, 
从而动态生成与该客户端相对应的内容。通常,我们可以从很多网站的登录界面中看到“请记住我”这样的选项,如果你勾选了它之后再登录,那么 
在下一次访问该网站的时候就不需要进行重复而繁琐的登录动作了,而这个功能就是通过Cookie实现的。

Web应用程序是使用HTTP协议传输数据的。HTTP协议是无状态的协议。一旦数据交换完毕,客户端与服务器端的连接就会关闭,再次交换数据需要
建立新的连接。这就意味着服务器无法从连接上跟踪会话。Cookie就是这样的一种机制。它可以弥补HTTP协议无状态的不足。

如果你把Cookies看成为http协议的一个扩展的话,理解起来就容易的多了,其实本质上cookies就是http的一个扩展。有两个http头部是专门 
负责设置以及发送cookie的,它们分别是Set-Cookie以及Cookie。当服务器返回给客户端一个http响应信息时,其中如果包含Set-Cookie这个 
头部时,意思就是指示客户端建立一个cookie,并且在后续的http请求中自动发送这个cookie到服务器端,直到这个cookie过期。如果cookie的 
生存时间是整个会话期间的话,那么浏览器会将cookie保存在内存中,浏览器关闭时就会自动清除这个cookie。另外一种情况就是保存在客户端的 
硬盘中,浏览器关闭的话,该cookie也不会被清除,下次打开浏览器访问对应网站时,这个cookie就会自动再次发送到服务器端。一个cookie的设 
置以及发送过程分为以下四步:
# 客户端发送一个http请求到服务器端
# 服务器端发送一个http响应到客户端,其中包含Set-Cookie头部
# 客户端发送一个http请求到服务器端,其中包含Cookie头部
# 服务器端发送一个http响应到客户端

登录百度后的响应头

登录百度后的请求头

Django中操作Coolie

设置与获取Coolie

普通版

# 在响应对象上设置Cookie
rep = HttpResponse(...)
rep = render(request, ...)
rep = redirect(...)
rep.set_cookie(key,value,...)

set_cookie(self, key, value='', max_age=None, expires=None, path='/',domain=None, secure=False, httponly=False)
# key, 键
# value='', 值
# max_age=None, Cookie保存时间(s)
# expires=None, Cookie过期时间(datetime时间对象)
# path='/', Cookie生效的路径,/ 表示根路径,特殊的:根路径的cookie可以被任何url的页面访问
# domain=None, Cookie生效的域名
# secure=False, https传输
# httponly=False 只能http协议传输,无法被JavaScript获取(不是绝对,底层抓包可以获取到也可以被覆盖)

# 获取cookie
request.COOKIES.get(键)

加盐版

比普通版多了一个盐,取值时也要根据盐取
# 设置Cookie
rep = HttpResponse(...)
rep = render(request, ...)
rep = redirect(...)

rep.set_signed_cookie(key,value,salt='加密盐',...)
# 获取
get_signed_cookie(self, key, default=RAISE_ERROR, salt='', max_age=None)
# salt: 加密盐
# default: 取不到的默认值

Cookie登录装饰器

# 注意模板中表单提交的url是不固定的

# 装饰器
def time(func):
    def inner(request):
        user = request.COOKIES.get("user") # 获取Cookie
        url = request.get_full_path() # 获取带参数的url
        if user:  # 如果获取到了Cookie说明登陆过
            return func(request) # 跳转到要去的页面
        # 没有登陆过跳转到登录页面,并且携带跳转之前的url
        return redirect("/login/?from={}".format(url))
    return inner

# 登录视图函数
def login(request):
    url = request.GET.get("from")  # 获得跳转来的url
    if request.method == "POST":
        name = request.POST.get("user")
        pwd = request.POST.get("pwd")
        # 验证密码
        if (name,pwd) in user_info:
            if url: # 如果是跳转来的,就跳转回去
                ret = redirect(url)
            else:  # 如果是直接登录就跳转到主页
                ret = redirect("//")
            ret.set_cookie("user",name) # 添加Cookie信息
            return ret
    return render(request,"loggin.html")

# 其他页面
@time
def show(request): #inner(request)
    user = request.COOKIES.get("user")
    return render(request,"show.html",{"user":user})

Session

  除了使用Cookie,Web应用程序中还经常使用Session来记录客户端状态。Session是服务器端使用的一种记录客户端状态的机制,使用上比Cookie简单一些,相应的也增加了服务器的存储压力。

Session技术则是服务端的解决方案,它是通过服务器来保持状态的。由于Session这个词汇包含的语义很多,因
此需要在这里明确一下 Session的含义。首先,我们通常都会把Session翻译成会话,因此我们可以把客户端浏
览器与服务器之间一系列交互的动作称为一个 Session。从这个语义出发,我们会提到Session持续的时间,会
提到在Session过程中进行了什么操作等等;其次,Session指的是服务器端为客户端所开辟的存储空间,在其中
保存的信息就是用于保持状态。从这个语义出发,我们则会提到往Session中存放什么内容,如何根据键值从 
Session中获取匹配的内容等。要使用Session,第一步当然是创建Session了。那么Session在何时创建呢?当
然还是在服务器端程序运行的过程中创建的,不同语言实现的应用程序有不同创建Session的方法,而在Java中
是通过调用HttpServletRequest的getSession方法(使用true作为参数)创建的。在创建了Session的同时,
服务器会为该Session生成唯一的Session id,而这个Session id在随后的请求中会被用来重新获得已经创建的
Session;在Session被创建之后,就可以调用Session相关的方法往Session中增加内容了,而这些内容只会保
存在服务器中,发到客户端的只有Session id;当客户端再次发送请求的时候,会将这个Session id带上,服务
器接受到请求之后就会依据Session id找到相应的Session,从而再次使用之。正式这样一个过程,用户的状态也
就得以保持了。

###什么是Session### Session是另一种记录客户状态的机制,不同的是Cookie保存在客户端浏览器中,而
Session保存在服务器上。客户端浏览器访问服务器的时候,服务器把客户端信息以某种形式记录在服务器上。这
就是Session。客户端浏览器再次访问时只需要从该Session中查找该客户的状态就可以了。

如果说Cookie机制是通过检查客户身上的“通行证”来确定客户身份的话,那么Session机制就是通过检查服务器
上的“客户明细表”来确认客户身份。Session相当于程序在服务器上建立的一份客户档案,客户来访的时候只需要
查询客户档案表就可以了。
虽然Session保存在服务器,对客户端是透明的,它的正常运行仍然需要客户端浏览器的支持。这是因为Session
需要使用Cookie作为识别标志。

  Session是基于Cookie的,Django中request对象设置Session之后会给客户端添加一个Cookie,同时将该Cookie对应的信息存放在本地.

Session为客户端发送的Cookie

服务端存储的数据 - 客户端的值便是服务端数据的主键,session_data是键值对序列化加密后得到的,expire_date是session_key过期时间,

客户端发来请求时,服务端拿到sessionid对应的值,再根据该值拿到该用户对应的信息.

无论是客户端Cookie失效,还是服务端Session失效,都会让客户端与服务端失去联系

使用Session

def index(request):
    # 获取、设置、删除Session中数据
    request.session['k1']  # 获取 拿不到报错
    request.session.get('k1',None) # 获取
    request.session['k1'] = 123  # 设置
    request.session.setdefault('k1',123) # 存在则不设置
    del request.session['k1']  # 删除键值对并不是删除session

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


    # 用户session的随机字符串
    request.session.session_key

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

    # 检查 用户session的随机字符串 在数据库中是否
    request.session.exists("session_key")

    # 删除当前用户的所有Session数据
    request.session.delete()  # 将客户端Cookie设置为空
    request.session.flush()  # 删除掉客户端的Cookie

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

 

Session信息存储方式相关配置

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

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

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

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

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

Session其他公用选项

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

# Session的cookie保存的路径(默认)                 
SESSION_COOKIE_PATH = "/"                  

# Session的cookie保存的域名(默认)             
SESSION_COOKIE_DOMAIN = None  

# 是否Https传输cookie(默认)                       
SESSION_COOKIE_SECURE = False  

# 是否Session的cookie只支持http传输(默认)                        
SESSION_COOKIE_HTTPONLY = True        

# Session的cookie失效日期(2周)(默认)                
SESSION_COOKIE_AGE = 1209600          
                  
# 是否关闭浏览器使得Session过期(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False     

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

CBV中加装饰器

from django.utils.decorators import method_decorator

# 装饰器函数
def  check_login(func):
    pass

# 要在CBV视图中使用我们上面的check_login装饰器,有以下三种方式:
#1. 加在CBV视图的get或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")
    
    @method_decorator(check_login) # 这里
    def post(self, request):
        print("Home View POST method...")
        return redirect("/index/")


# 加在dispatch方法上
# 因为CBV中首先执行的就是dispatch方法,所以这么写相当于给get和post方法都加上了登录校验。
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/")

# 直接加在视图类上,但method_decorator必须传 name 关键字参数
# 如果get方法和post方法都需要登录校验的话就写两个装饰器。
@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方法上

备注:

  • csrf_protect,为当前函数强制设置防跨站请求伪造功能,即便settings中没有设置全局中间件。
  • csrf_exempt,取消当前函数防跨站请求伪造功能,即便settings中设置了全局中间件。
    from django.views.decorators.csrf import csrf_exempt, csrf_protect
    
    
    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/")
    

      

posted @ 2018-01-25 15:46  瓜田月夜  阅读(141)  评论(0编辑  收藏  举报