Django学习笔记一十五——cookies和session

众所周知,HTTP是一个无状态协议,为了提高效率,比较原始的方法就是引入cookies的概念(虽然现在去cookies化是大趋势,但一时半会还是要使用cookies的。)

从原理上来说,cookies就是保存在浏览器上的键值对,服务器控制这响应 ,在响应中可以让浏览器在本地保存这个键值对,下一次请求在发送的时候就会自动携带这个键值对(cookies值)。要注意的是cookies是服务端设置的,我们可以设置浏览器让服务端禁用cookies。但是有很多Web在登录的时候还是基于cookies的

cookies的作用

1.保持登录状态(几天内免登陆)

2.记录用户的浏览器习惯(搜索记录)

3.简单的防止刷票 

没有cookies的使用

在前面的登录案例中,我们都是不保持状态的,每次打开login页面都要登录,正常的视图函数是这样的

def login(request):
    if request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'hehe' and pwd =='123':
            return redirect('/home/')
    return render(request,'login.html')

我们每次在打开登录页面,在POST用户名和密码以后,都会进行一次登录操作。如果登录成功,就直接跳转到下一步操作,但是每次进入login页面都要进行一次登录。

把cookies引入登录程序

引入cookies 

引入cookies的方法也比较简单,我们先看一看是怎么在程序中加载cookies的

def login(request):
    if request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'hehe' and pwd =='123':
            rep = redirect('/home/')    #得到一个响应对象
            rep.set_cookie('123','abc') #设置cookies
            return rep
    return render(request,'login.html')

在上面的这段代码中,我们再生成一个相应对象以后对这个对象添加一个cookies以后,直接返回对象。在登录进入主页以后,重新刷新一遍,我们检查一下页面(Network)

 检查一下cookies,是不是多了一个键值对,key和value就是我们在代码中添加的。

cookies的获取

再次进入home页面以后,我们可以在获取COOKIES

def home(request):
    ret = request.COOKIES['123']
    print(ret)
    return render(request,'home.html')

然后可以对COOKIES进行比较如果,来判定是否已经登录

COOKIES的保存时间

默认情况下COOKIES的保存时间是随着浏览器的,浏览器一旦关闭COOKIES就失效。

登录时的COOKIES

 我们可以把COOKIES的键值对设置成{'is_loged':0},然后在登录主页的时候获取这个COOKIES,然后进行比对,如果比对成功,直接进入主页,否则跳转至登录页面。

def login(request):
    if request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'hehe' and pwd =='123':
            rep = redirect('/home/')    #得到一个响应对象
            rep.set_cookie('is_loged','1') #设置cookies
            return rep
    return render(request,'login.html')


def home(request):
    ret = request.COOKIES.get('is_loged',0) #获取COOKIES
    if ret == '1':
        return render(request,'home.html')
    else:
        return redirect('/login/')

这样就实现了免登陆的效果。

 装饰器版的登录校验

在平时我们访问网站的时候,比方上淘宝,在每个页面都是有登录状态的,我们就要在每个页面添加一个登录校验的过程,可是有些页面是已经使用了,那么就到了装饰器的使用时间了。先看一下代码

#定义装饰器函数
def login_check(func):
    @wraps(func)      #装饰器修复技术
    def inner(request,*args,**kwargs):
        ret = request.COOKIES.get('is_logged',0)
        if ret == '1':
            return func(request,*args,**kwargs)
        else:
            return redirect('/login/')
    return inner



def login(request):
    if request.method == 'POST':
        user = request.POST.get('user')
        pwd = request.POST.get('pwd')
        if user == 'hehe' and pwd =='123':
            rep = redirect('/home/')    #得到一个响应对象
            rep.set_cookie('is_logged','1',max_age=10) #设置cookies
            return rep
    return render(request,'login.html')


#用装饰器来修饰页面判定登录情况
@login_check
def home(request):
    return  render(request,'home.html')

上面这段程序的流程就是在对home页面发出请求的时候,通过装饰器函数login_check检查cookies里的登录状态,如果已经登录,就进入home页面,否则就进入登录的页面。等待登录。但是这种用法有个问题所以不大常用:如果有好多个页面在请求的时候倒要进行判定,在每个视图函数前面都要加个这个装饰器。那就要用到后面会讲到的中间件。

Session的使用

从Cookie到Session

虽然我们用Cookie在一定成都上解决了Http请求保持状态的需求,但是Cookie本身最大只能支持4096字节,并且由于Cookie是保存在浏览器里的,即便是用了加密盐,也很有可能被拦截或窃取,安全性很难保证。

于是,一种新的方案就出来了,我们给浏览器的Cookie分配一个唯一的id,用户在访问的时候,通过Cookie里的id从服务端取到保存了某段时间内的用户私密资料,比方登录状态,账号密码等。这样,几乎所有的数据都是存在服务器端,就没有数据大小的限制,并且由于数据是存放在服务器里,安全也相对来说高一些。

Session的优缺点

优点:

比Cookie存档数据多

安全性好

缺点

Session的数据量大,会占用一些服务器的资源,并且在请求量大时加大了服务器的负载。

Django内Session的相关方法

在Django内,Session的工作也就是下面几条:

  • 存Session
    • 在服务端生成一个随机的字符串

    • 生成一个上面的随机字符串的大字典来保存用户的数据
    • 生成的随机字符串作为Cookie返回给浏览器

  • 取Session
    • 从请求携带的Cookie中找到那个随机的字符串
    • 拿到字符串去Session中找对应的大字典
    • 从大字典内根据Key找值

并且Session是在settings里绑定的数据库中的,我们可以查一下

 上面的数据就是新添加 了一条Session内容以后数据库的数据。session_key就是Cookie里存储的那个随机的字符串

 而那个前面说的大字典就是以密文的方式保存在session_data字段里的数据。但是有一点要注意,这个数据是只要有一个浏览器的请求一个session,过来,就会生成一个。你开两个页面就会有两条内容

获取、设置、删除Session内的数据

request.session['key'] = value                #设置session中的键值对
request.session['key']                        #获取session中的key对应的value
request.session.flush()                       #删除当前会话并删除会话中的Cookie

我们从下面一个登录、浏览主页和注销的页面来演示一下session是怎么使用的。

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

        if name == 'aaa' and pwd =='bbb':
            rep = HttpResponse('登录成功')
            request.session['is_log'] = 1   #session中添加登录状态
            request.session['user'] = name  #session中添加内容
            request.session.set_expiry(10)  # 10秒钟之后失效
            return rep
        
        else:
            return redirect('/session_test/login')
    else:
        return render(request,'login.html')


#浏览主页并检查登录状态
def home(request):
    print(request.session.get('is_log'))
    if request.session.get('is_log') == 1:
        return  render(request,'home.html')
    else:
        return redirect('/session_test/login')

#注销然后进入登录页面
def clear_session(request):
    request.session.flush()
    return redirect('/session_test/login')
Session入门使用

所有的键值对

request.sesssion.keys()    -->    <class 'dict_keys'>     #获取session内所有key
request.session.values() -->  <class 'dict_values'>    #获取session内所有values
request.session.values()  --><class 'dict_items'>   #获取session键值对
#打印的结果dict_items([('is_log', 1), ('user', 'aaa'), ('_session_expiry', 100)]) <class 'dict_items'>

session中生成的随机字符串

request.session.session_key

注意这不是个方法,不用带括号。

session的清除

删除当前用户的所有Session数据

request.session.delete('session_key')#删除session_key对应的session内数据,但是只会删除session,但是Cookie里的随机字符串还在
request.session.flush() #删除session和Cookie
request.session.clear_expired()    #删除所有session失效日期小于当前日期的数据

request.session.set_expiry(value)   #session的失效策略
#默认的过期时间是两周,如果自己设置了过期时间,这样自己设定的优先级就会高于默认的
#如果value是个整数,session会在些秒数后失效。
#如果value是个datatime或timedelta,session就会在这个时间后失效。
#如果value是0,用户关闭浏览器session就会失效。
#如果value是None,session会依赖全局session失效策略。

那个clear_expired()常常用来定时清除过期的Session来释放空间。

 session的失效策略是通过Cookie的失效来实现的,如果超过指定时间,Cookie就不在存储那个随机字符串,但是Session大字典的内容是还在数据库中,必须手动调用上面那条指令来释放。

Session在settings内的设置

session还可以通过下面的内容进行设置,直接加载settings.py文件后面就行了

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

 装饰器版的Session使用

最后看一下装饰器版的Session是怎么使用的,和Cookie一样,用一个页面的请求来判定登录状态

from functools import wraps
#检查登录状态的装饰器
def check_login(func):
    @wraps(func)
    def inner(request,*args,**kwargs):
        ret = request.session.get('is_log')
        if ret == 1:
            return func(request,*args,**kwargs)

        else:
            return redirect('/session_test/login/')

    return inner
def login(request):
    return HttpResponse(12345656)

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

        if name == 'aaa' and pwd =='bbb':
            rep = HttpResponse('登录成功')
            request.session['is_log'] = 1   #session中添加登录状态
            request.session['user'] = name  #session中添加内容
            request.session.set_expiry(100)  # 10秒钟之后失效
            return rep
        
        else:
            return redirect('/session_test/login')
    else:
        return render(request,'login.html')



#用装饰器检查登录状态
@check_login
def home(request):
    return render(request,'home.html')
View Code
原文地址:https://www.cnblogs.com/yinsedeyinse/p/12799403.html