Django 框架的cookies,session与tooken
目录
文章目录
1.cookies 和 session
- 会话 - 从打开浏览器访问一个网站,到关闭浏览器结束此次访问,称之为一次会话
- HTTP协议是无状态的,导致会话状态难以保持
- 试想一下,如果不保持会话状态,在电商网站购物的场景
体验?
Cookies和Session就是为了保持会话状态而诞生的两个存储技术
cookies
-
cookies是保存在客户端浏览器上的存储空间
-
Chrome 浏览器 可能通过开发者工具的
Application
>>Storage
>>Cookies
查看和操作浏览器端所有的 Cookies 值 -
火狐浏览器 可能通过开发者工具的 存储 -> Cookie
-
cookies 在浏览器上是以键-值对的形式进行存储的,键和值都是以ASCII字符串的形存储(不能是中文字符串)
-
cookies中的数据是按域存储隔离的,不同的域之间无法访问 域是 I P +端口
-
在向服务器发送请求时,由服务器决定将一些保存状态的些数据储存到cookie中,cookie的数据是自动提交的.
-
cookies 的内部的数据会在每次访问此网址时都会携带到服务器端,如果cookies过大会降低响应速度
-
-
在Django 设置浏览器的COOKIE 必须通过 HttpResponse 对象来完成
-
添加、修改COOKIE
- HttpResponse.set_cookie(key, value=’’, max_age=None, expires=None)
- key:cookie的名字
- value:cookie的值
- max_age:cookie存活时间,秒为单位
- expires:具体过期时间
- 当不指定max_age和expires 时,关闭浏览器时此数据失效
- HttpResponse.set_cookie(key, value=’’, max_age=None, expires=None)
-
删除COOKIE
-
http://127.0.0.1:8000/delete_cookies
-
Set-Cookie: uname=""; expires=Thu, 01 Jan 1970 00:00:00 GMT; Max-Age=0; Path=/
-
1.值为:" "
-
expire为1970 00:00:00 GMT,意味着从一开始cookies就过期了
-
3.Max_age为0,有效期0秒.
- HttpResponse.delete_cookie(key)
- 删除指定的key 的Cookie。 如果key 不存在则什么也不发生。
-
获取cookie
-
通过 request.COOKIES 绑定的字典(dict) 获取客户端的 COOKIES数据
value = request.COOKIES.get('cookies名', '默认值') print("cookies名 = ", value)
-
-
-
示例
-
以下示例均在视图函数中调用
-
添加cookie
# 为浏览器添加键为 my_var1,值为123,过期时间为1个小时的cookie responds = HttpResponse("已添加 my_var1,值为123") responds.set_cookie('my_var1', 123, 3600) return responds
-
-
修改cookie
# 为浏览器添加键为 my_var1,修改值为456,过期时间为2个小时的cookie responds = HttpResponse("已修改 my_var1,值为456") responds.set_cookie('my_var1', 456, 3600*2) return responds
-
删除cookie
# 删除浏览器键为 my_var1的cookie #删除时,对cookies的操作,分三步 请求头的setcookies设置为 1.值为空 2.expire=1970.0.0.0 3.Max_age=0 #因为cookies的值类型值字典,所以删除键,就会删除对应的数据。 responds = HttpResponse("已删除 my_var1") responds.delete_cookie('my_var1') return responds
-
获取cookie
# 获取浏览器中 my_var变量对应的值 value = request.COOKIES.get('my_var1', '没有值!') print("cookie my_var1 = ", value) return HttpResponse("my_var1:" + value)
-
session
-
session又名会话控制,是在服务器上开辟一段空间用于保留浏览器和服务器交互时的重要数据
-
实现方式
- 使用 session 需要在浏览器客户端启动 cookie,且用在cookie中存储sessionid[session存储状态依赖cookies]
- 每个客户端都可以在服务器端有一个独立的Session
- 注意:不同的请求者之间** 不会共享这个数据,与请求者一一对应
-
Django中配置Session
-
在 settings.py 文件中
-
向 INSTALLED_APPS 列表中添加:
INSTALLED_APPS = [ # 启用 sessions 应用 'django.contrib.sessions', ]
-
向 MIDDLEWARE 列表中添加:
MIDDLEWARE = [ # 启用 Session 中间件 'django.contrib.sessions.middleware.SessionMiddleware', ]
-
-
session的基本操作:
- session对于象是一个类似于字典的SessionStore类型的对象, 可以用类拟于字典的方式进行操作
- session 只能够存储能够序列化的数据,如字典,列表等。
-
保存 session 的值到服务器
request.session['KEY'] = VALUE
-
获取session的值
VALUE = request.session['KEY']
VALUE = request.session.get('KEY', 缺省值)
-
删除session的值 删除服务器的session值
- del request.session[‘KEY’]
-
在 settings.py 中有关 session 的设置
- SESSION_COOKIE_AGE
- 作用: 指定sessionid在cookies中的保存时长(默认是2周),如下:
SESSION_COOKIE_AGE = 60 * 60 * 24 * 7 * 2
- SESSION_EXPIRE_AT_BROWSER_CLOSE = True
**设置只要浏览器关闭时,session就失效(默认为False) **
- SESSION_COOKIE_AGE
-
注: 当使用session时需要迁移数据库,否则会出现错误
python3 manage.py migrate
django 原生session 问题:
1,django_session表是 单表设计; 且该表数据量持续增持【浏览器故意删掉sessionid&过期数据未删除】
2,可以每晚执行 python3 manage.py clearsessions 【该命令可删除已过期的session数据】
Cookies vs session
存储位置:
C- 浏览器中 s- 服务器中【mysql】
安全性:
C - 不安全 s- 相对安全一些
不管C还是S , 不要存储敏感数据 【密码】
但凡需要安全传输,一定要用https://传输
sessionid : " 1ipddznn6z9eqzfp3c0t72h1etohzwxl "
2,token - 令牌
学前须知:
1,base64 ‘防君子不防小人’
方法 | 作用 | 参数 | 返回值 |
---|---|---|---|
b64encode | 将输入的参数转化为base64规则的串 | 预加密的明文,类型为bytes;例:b‘guoxiaonao’ | base64对应编码的密文,类型为bytes;例:b’Z3VveGlhb25hbw==’ |
b64decode | 将base64串 解密回 明文 | base64密文,类型为bytes;例:b’Z3VveGlhb25hbw==’ | 参数对应的明文,类型为bytes;例:b’guoxiaonao’ |
urlsafe_b64encode | 作用同b64encode,但是会将 ‘+‘替换成 ‘-’,将’/‘替换成’_’ | 同b64encode | 同b64encode |
urlsafe_b64decode | 作用同b64decode | 同b64decode | 同b64decode |
代码演示:
import base64
#base64加密
s = b'guoxiaonao'
b_s = base64.b64encode(s)
#b_s打印结果为 b'Z3VveGlhb25hbw=='
#base64解密
ss = base64.b64decode(b_s)
#ss打印结果为 b'guoxiaonao'
2,SHA-256 安全散列算法的一种(hash)
hash三大特点:
1)定长输出 2)不可逆 3) 雪崩
import hashlib
s = hashlib.sha256() #创建sha256对象
s.update(b'xxxx') #添加欲hash的内容,类型为 bytes
s.digest() #获取最终结果
3,HMAC-SHA256 是一种通过特别计算方式之后产生的消息认证码,使用散列算法同时结合一个加密密钥。它可以用来保证数据的完整性,同时可以用来作某个消息的身份验证
import hmac
#生成hmac对象
#第一个参数为加密的key,bytes类型,
#第二个参数为欲加密的串,bytes类型
#第三个参数为hmac的算法,指定为SHA256
h = hmac.new(key, str, digestmod='SHA256')
h.digest() #获取最终结果
2.1 JWT - json-web-token
1,三大组成
1,header
格式为字典-元数据格式如下
{'alg':'HS256', 'typ':'JWT'}
#alg代表要使用的 算法
#typ表明该token的类别 - 此处必须为 大写的 JWT
该部分数据需要转成json串并用base64 加密
2,payload
格式为字典-此部分分为公有声明和私有声明
公共声明:JWT提供了内置关键字用于描述常见的问题
此部分均为可选项,用户根据自己需求 按需添加key,常见公共声明如下:
{'exp':xxx, # Expiration Time 此token的过期时间的时间戳
'iss':xxx,# (Issuer) Claim 指明此token的签发者
'aud':xxx, #(Audience) Claim 指明此token的
'iat':xxx, # (Issued At) Claim 指明此创建时间的时间戳
'aud':xxx, # (Audience) Claim 指明此token签发面向群体
}
私有声明:用户可根据自己业务需求,添加自定义的key,例如如下:
{'username': 'guoxiaonao'}
公共声明和私有声明均在同一个字典中;转成json串并用base64加密
3,signature 签名
签名规则如下:
根据header中的alg确定 具体算法,以下用 HS256为例
HS256(自定义的key , base64后的header + ‘.’ + base64后的payload)
解释:用自定义的key, 对base64后的header + ‘.’ + base64后的payload进行hmac计算
2,jwt结果格式
base64(header) + ‘.’ + base64(payload) + ‘.’ + base64(sign)
最终结果如下: b’eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1b3hpYW9uYW8iLCJpc3MiOiJnZ2cifQ.Zzg1u55DCBqPRGf9z3-NAn4kbA-MJN83SxyLFfc5mmM’
3,校验jwt规则
1,解析header, 确认alg
2,签名校验 - 根据传过来的header和payload按 alg指明的算法进行签名,将签名结果和传过来的sign进行对比,若对比一致,则校验通过
3,获取payload自定义内容
4,pyjwt
1,安装 pip3 install pyjwt
方法 | 参数说明 | 返回值 |
---|---|---|
encode(payload, key, algorithm) | payload: jwt三大组成中的payload,需要组成字典,按需添加公有声明和私有声明 例如: {‘username’: ‘guoxiaonao’, ‘exp’: 1562475112} 参数类型: dict | token串 返回类型:bytes |
key : 自定义的加密key 参数类型:str | ||
algorithm: 需要使用的加密算法HS256 参数类型:str | ||
decode(token,key,algorithm,) | token: token串 参数类型: bytes/str | payload明文 返回类型:dict |
key : 自定义的加密key ,需要跟encode中的key保持一致 参数类型:str | ||
algorithm: 同encode | ||
issuer: 发布者,若encode payload中添加 ‘iss’ 字段,则可针对该字段校验 参数类型:str | 若iss校验失败,则抛出jwt.InvalidIssuerError | |
audience:签发的受众群体,若encode payload中添加’aud’字段,则可针对该字段校验 参数类型:str | 若aud校验失败,则抛出jwt.InvalidAudienceError |
PS: 若encode得时候 payload中添加了exp字段; 则exp字段得值需为 当前时间戳+此token得有效期时间, 例如希望token 300秒后过期 {‘exp’: time.time() + 300}; 在执行decode时,若检查到exp字段,且token过期,则抛出jwt.ExpiredSignatureError