Python入门自学进阶-Web框架——9Django进阶-认识COOKIE和SESSION

Posted kaoa000

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Python入门自学进阶-Web框架——9Django进阶-认识COOKIE和SESSION相关的知识,希望对你有一定的参考价值。

Django的应用

简单后台管理:
1、登录注册
2、班级、教师、学生管理
3、增删改查CRUD操作

首先,做一个简单的登录认证 ,COOKIES认识与使用:

登录页面login.html

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
<form action="login.html" method="post">
    % csrf_token %   
    #  这是csrf安全要求,实际上也是保存在COOKIES中  #
    <div>
        <label for="user">用户名:</label>
        <input id="user" type="text" name="user" />
    </div>
    <div>
        <label for="pwd">密码:</label>
        <input id="pwd" type="password" name="pwd" />
    </div>
    <div>
        <label> </label>
        <input type="submit" value="登录" />
        <span style="color: red"> msg </span>
        # msg用于错误提示,正确时为空 #
    </div>

</form>
</body>
</html>

登录成功后的跳转页面:index.html,显示用户名

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

后台的跳转路由项:

urlpatterns = [
    path('test/', views.test),
    path('login.html',views.login),
    path('index.html',views.index),
]

视图函数:

from django.shortcuts import render,HttpResponse,redirect

# Create your views here.

def login(req):
    message =""
    if req.method == "POST":
        user = req.POST.get('user')
        pwd = req.POST.get('pwd')
        if user == 'root' and pwd == 'root':
            # 在神奇的地方放置用户名,这个神奇的地方就是COOKIES
            # 放置方法是先生成一个render或redirect对象,然后使用设置方法进行设置
            # COOKIES是在客户端的电脑上的,在用户浏览器上,硬盘的某个位置
            rep = redirect('index.html')
            rep.set_cookie('username',user)
            # 这一句就是在用户电脑上的COOKIES文件中保存一个键值对'username',user,注意是用户的电脑上
            return rep
        else:
            message = "用户名或密码错误"
    return render(req,"login.html",'msg':message)

def index(req):
    # 如果用户已经登录,获取当前登录的用户名
    # 否则,返回登录页面
    # if req.COOKIES.get('csrftoken'):
    username = req.COOKIES.get('username')
    print(username)
    if username :
        return render(req,"index.html",'username':username)
    else:
        return redirect('login.html')

运行结果:

输入错误的名称或密码: 

输入正确的用户、密码:

 登录成功后,如果再次直接访问index.html,可以访问,显示用户名。如果清除一下cookie,则直接访问index.html时,跳转到login.html。

修改一下上面例子中的login视图:

login(req):
    # models.Administrator.objects.create(
    #     username='user2',
    #     password='123123'
    # )    #在登录用户表中插入几个用户进行测试
    message =""
    if req.method == "POST":
        user = req.POST.get('user')
        pwd = req.POST.get('pwd')
        counts = models.Administrator.objects.filter(username=user,password=pwd).count()
        print('counts:',counts)
        # 使用数据库中的数据进行验证,查询传递过来的用户和密码,如果条数不为0
        # if user == 'root' and pwd == 'root':
        if counts:
            # 在神奇的地方放置用户名,这个神奇的地方就是COOKIES
            # 放置方法是先生成一个render或redirect对象,然后使用设置方法进行设置
            # COOKIES是在客户端的电脑上的
            rep = redirect('index.html')
            rep.set_cookie('username',user)
            # 这一句就是在用户电脑上的COOKIES文件中保存一个键值对'username',user,注意是用户的电脑上
            return rep
        else:
            message = "用户名或密码错误"
    return render(req,"login.html",'msg':message)

使用数据库进行用户验证。至此,一个简单的登录验证功能完成。

models模块中:

from django.db import models

# Create your models here.

class Classes(models.Model):
    caption = models.CharField(max_length=32)

class Student(models.Model):
    name = models.CharField(max_length=32)
    cls = models.ForeignKey(Classes,on_delete=models.DO_NOTHING)

class Teacher(models.Model):
    name = models.CharField(max_length=32)
    cls = models.ManyToManyField(Classes)

class Administrator(models.Model):
    username = models.CharField(max_length=32)
    password = models.CharField(max_length=32)

再看一下登录过程的cookie过程:

第一次登录login.html:

 请求发送了cookie,是csrftoken,响应同样返回了这个csrftokencookie。

当我们输入正确的用户密码后,第二次请求了login.html,这时的cookie过程:

请求时带了csrftoken这个cookie,响应则返回了username:root这个cookie值,即cookie中增加了这个键值对。登录成功后跳转到了index.html,这个请求的cookie过程:

只是请求时带了cookie,其中包含了csrftoken和username 

关于COOKIE:

1、获取Cookie:

request.COOKIES['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,...)
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的页面访问;而/xxx/表示只有这个路径才能访问到cookie中的对应键值对。
        domain=None,      Cookie生效的域名,None是默认设置,是当前域名。不能设置不同的同级域名,可以设置上级域名。如www.xxx.com,可以设置xxx.com,不能设置crm.xxx.com
        secure=False,     https传输,需要设为true
        httponly=False    只能http协议传输,无法被javascript获取(不是绝对,底层抓包可以获取到也可以被覆盖),在chrome的console中,通过document.cookie无法获取到httponly=True设置的cookie键值对。False的可以获取到。

由于cookie保存在客户端的电脑上,所以,JavaScript和jquery也可以操作cookie。

<script src='/static/js/jquery.cookie.js'></script>
$.cookie("list_pager_num", 30, path: '/' );   //参数是:key ,value,其他选项,字典,一个参数是获取值,两个参数设置值,三个参数,第三个参数字典,选项

COOKIE:就是保存在浏览器端的键值对,可以利用它做登录
1、保存在用户浏览器
2、可以主动清除
3、也可以被“伪造”
4、跨域cookie不共享
5、浏览器可以设置不接受cookie
6、客户端也可以设置cookie内容:document.cookie是获取,document.cookie=“k2=v2;k3=v3”是设置。jquery提供插件jquery.cookie.js,可以操作cookie。如上面的$.cookie("list_pager_num", 30, path: '/' );

COOKIE的应用:

登录验证
    - 有敏感信息,不宜放在COOKIE,会被直接看到,敏感信息放在数据库,缺点是频繁访问数据库。
    - 签名COOKIE,使用req.set_signed_cookie(),但是有被破解的风险。
    - cookie做认证时,将不敏感信息放在cookie,敏感信息放在数据库。

COOKIE的传递是在放在HTTP的头部,请求时放在请求头,request header,形式是Cookie:xxx=xxx;xxx=xxx,响应时放在响应头中,即response header中,形式是Set-Cookie:xxx=xxx;xxx=xxx。

关于Session

Django中默认支持Session,其内部提供了5种类型的Session供开发者使用:

  • 数据库(默认)
  • 缓存
  • 文件
  • 缓存+数据库
  • 加密cookie

session是服务器端的一个键值对,session内部机制依赖于cookie。

1、数据库Session

Django默认支持Session,并且默认是将Session数据存储在数据库中,即:django_session 表中。

要使用数据库session,在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传输(默认),如果设置为 True,客户端的 JavaScript 将无法访问会话 cookie。
SESSION_COOKIE_AGE = 1209600                 # Session的cookie失效日期(2周)(默认)
SESSION_EXPIRE_AT_BROWSER_CLOSE = False      # 是否关闭浏览器使得Session过期(默认)
SESSION_SAVE_EVERY_REQUEST = False           # 是否每次请求都保存Session,默认修改之后才保存(默认)
SESSION_COOKIE_SAMESITE = 'Lax'              # 会话 cookie 上的 SameSite 标志的值。这个标志可以防止 cookie 在跨站请求中被发送,从而防止 CSRF 攻击,使一些窃取会话 cookie 的方法变得不可能。(默认)
# 该配置的可能值为:
# 'Strict' :防止浏览器在所有跨站点浏览的情况下向目标站点发送 cookie,即使在使用常规链接时也是如此。
# 例如,对于类似 GitHub 的网站来说,这意味着如果登录的用户通过企业论坛或电子邮件链接到 GitHub 的私人项目,GitHub 将不会收到会话 cookie,用户将无法访问该项目。然而,银行网站很可能不允许从外部网站链接任何交易页面,因此 'Strict' 标志将是合适的。
# 'Lax' (默认):为希望在用户从外部链接到达后保持用户登录会话的网站提供安全和可用性之间的平衡。
# 在 GitHub 的场景下,当跟随外部网站的常规链接时,会话 cookie 将被允许,而在 CSRF 倾向的请求方法(例如 POST)中被阻止。
# 'None' (字符串):会话 cookie 将随所有同站和跨站请求发送。
# False :停用该标志。
# 现代浏览器为 SameSite 标志提供了一个更安全的默认策略,并将假定 Lax 为没有明确配置值的 cookies。

接前面的cookie测试,修改一下index视图。当前index请求的客户端的cookie含有username和csrftoken。

def index(req):
    # 如果用户已经登录,获取当前登录的用户名
    # 否则,返回登录页面
    # if req.COOKIES.get('csrftoken'):
    # print('session:k1:',req.session['k1'])  #获取session中的内容方法1,如果不存在k1,后台提示KeyError:‘K1’
    print(req.session.get('k1',None))  # 获取session中的内容方法2,如果不存在,返回None,不会出错。
    username = req.COOKIES.get('username')
    print(username)
    if username :
        return render(req,"index.html",'username':username)
    else:
        return redirect('login.html')

 设置session内容:

def index(req):
    # print('session:k1:',req.session['k1'])  #获取session中的内容方法1,如果不存在k1,后台提示KeyError:‘K1’
    print(req.session.get('k1',None))  # 获取session中的内容方法2
    req.session['k1'] = 123  #设置session方式1
    username = req.COOKIES.get('username')
    print(username)
    if username :
        return render(req,"index.html",'username':username)
    else:
        return redirect('login.html')

 可以看到,前端的响应头中设置了cookie,增加了sessionid=随机串以及相应的其他设置

第二次访问index后,前端的请求头:

 请求的cookie中增加sessionid。

第二种设置session的方法:

def index(req):
    # print(req.session.get('k1',None))  # 获取session中的内容方法2
    req.session['k1'] = 123  # 设置session方式1
    req.session.setdefault('k1',456)  # 设置session方式2,session中存在k1则不改变其值,否则设置k1为第二个参数值
    print('session:k1:',req.session['k1'])   # 这里因为前面已经设置了k1,所以其值不会改变
    username = req.COOKIES.get('username')
    print(username)
    if username :
        return render(req,"index.html",'username':username)
    else:
        return redirect('login.html')

使用req.session.setdefault()方法,运行打印的结果:

可以看出k1的值没有变,还是原来的123.

 删除session中的内容,使用del,然后在设置:

def index(req):
    # print(req.session.get('k1',None))  # 获取session中的内容方法2
    req.session['k1'] = 123  # 设置session方式1
    del req.session['k1']   # 删除session中的k1
    req.session.setdefault('k1',456)  # 设置session方式2,session中存在k1则不改变其值,否则设置k1为第二个参数值
    print('session:k1:',req.session['k1'])   # 这里因为前面已经设置了k1,所以其值不会改变
    username = req.COOKIES.get('username')
    print(username)
    if username :
        return render(req,"index.html",'username':username)
    else:
        return redirect('login.html')

这时后台打印的k1的值为456.查看数据库django_session表,发现session_key没有变,但是session_data改变了。

 查询所有 键、值、键值对:
request.session.keys()
request.session.values()

request.session.items()

def index(req):
    req.session['k1'] = 123  # 设置session方式1
    del req.session['k1']   # 删除session中的k1
    req.session.setdefault('k1',456)  # 设置session方式2,session中存在k1则不改变其值,否则设置k1为第二个参数值
    print('session:k1:',req.session['k1'])   # 这里因为前面已经设置了k1,所以其值不会改变
    req.session.setdefault('k2','abc')
    req.session.setdefault('k3',[1,2,34])
    req.session.setdefault('k4','a':100,'b':200)
    print('keys():',req.session.keys())  # 返回所有键的列表
    print('values():',req.session.values())   # 返回所有值的列表
    print('items():',req.session.items())  # 返回所有键值对的列表
    username = req.COOKIES.get('username')
    if username :
        return render(req,"index.html",'username':username)
    else:
        return redirect('login.html')

打印的结果:

 注意事项:还看到如下的session方法,但是在djang3.2中使用提示错误


 request.session.iterkeys()
 request.session.itervalues()

 request.session.iteritems()

 说明在3.2以后版本中没有了这几个方法。

个人理解:也许这几个方法是生成相应的迭代器对象,可以使用iter()方法生成。

其他几个方法:

# 用户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失效策略。

def index(req):
    req.session['k1'] = 123  # 设置session方式1
    del req.session['k1']   # 删除session中的k1
    req.session.setdefault('k1',456)  # 设置session方式2,session中存在k1则不改变其值,否则设置k1为第二个参数值
    print('session:k1:',req.session['k1'])   # 这里因为前面已经设置了k1,所以其值不会改变
    req.session.setdefault('k2','abc')
    req.session.setdefault('k3',[1,2,34])
    req.session.setdefault('k4','a':100,'b':200)
    print('keys():',req.session.keys())  # 返回所有键的列表
    print('values():',req.session.values())   # 返回所有值的列表
    print('items():',req.session.items())  # 返回所有键值对的列表
    # 用户session的随机字符串
    print(req.session.session_key)
    skey = req.session.session_key
    # 将所有Session失效日期小于当前日期的数据删除
    req.session.clear_expired()
    # 检查 用户session的随机字符串 在数据库中是否
    print(req.session.exists(req.session.session_key))
    # 删除当前用户的所有Session数据
    req.session.delete(req.session.session_key)
    print('----',req.session.session_key)
    print('删除session后:',req.session.exists(req.session.session_key))
    username = req.COOKIES.get('username')
    if username :
        return render(req,"index.html",'username':username)
    else:
        return redirect('login.html')

后台运行结果:

 前端:

 也就是,删除了session后,在return来完成request,就会出错,因为请求没有完成前不能删除session。

2、缓存Session

a. 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.cache'  # 引擎
    SESSION_CACHE_ALIAS = 'default'                            # 使用的缓存别名(默认内存缓存,也可以是memcache),此处别名依赖缓存的设置
 
 
    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_ENGINE 为 "django.contrib.sessions.backends.cache" 用于简单缓存会话存储。会话数据直接被存储在缓存里。然而,会话数据可能不是长久的:因为缓存满了或者缓存服务重启了,所以缓存数据会被收回。
  • 为了持久化缓存数据,设置 SESSION_ENGINE 为 "django.contrib.sessions.backends.cached_db" 。这使用直写式缓存——每次写入缓存的数据也会被写入到数据库。如果数据不在缓存中,会话仅使用数据库进行读取。

3、文件Session:

 配置 settings.py
 
    SESSION_ENGINE = 'django.contrib.sessions.backends.file'    # 引擎
    SESSION_FILE_PATH = None                                    # 缓存文件路径,如果为None,则使用tempfile模块获取一个临时地址tempfile.gettempdir()                                                            # 如:/var/folders/d3/j9tj0gz93dg06bmwxmhh6_xm0000gn/T
 
 
    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,默认修改之后才保存

4、缓存+数据库Session

数据库用于做持久化,缓存用于提高效率

配置 settings.py
    
SESSION_ENGINE = 'django.contrib.sessions.backends.cached_db'        # 引擎

5、加密cookie Session

 配置 settings.py
   
SESSION_ENGINE = 'django.contrib.sessions.backends.signed_cookies'   # 引擎

以上是关于Python入门自学进阶-Web框架——9Django进阶-认识COOKIE和SESSION的主要内容,如果未能解决你的问题,请参考以下文章

Python入门自学进阶-Web框架——20Django其他相关知识2

Python入门自学进阶-Web框架——2Django初识

Python入门自学进阶-Web框架——3Django的URL配置

Python入门自学进阶-Web框架——21DjangoAdmin项目应用

Python入门自学进阶-Web框架——21DjangoAdmin项目应用

Python入门自学进阶-Web框架——4HttpRequest和HttpResponse及模板