cookie和session
cookie
Set-Cookie有name和value两个重要的属性(具体属性网上搜)
服务器会填充这两个值,然后发送给客户端,客户端在此后每次请求都会带上cookie
session
session设置结束会话的时间,和session_id(没有规律的字符串)
cookie保存session标识身份的信息(也是只有这个最重要)。对含有session——ID的cookie进行签名
session可以存在缓存中
flask框架session存储有两种方式:
第一种方式:直接存在客户端的cookies中
第二种方式:存储在服务端,如:redis,memcached,mysql,file,mongodb等等,存在flask-session第三方库
session存储的消息
- 身份信息、登陆状态 2. 用户的个性配置、权限列表 3. 其他的一些通用数据
axios不支持跨域使用cookie
flask中关于cookie与session的用法
具有不安全、不正确或缺少SameSite属性的Cookie
SameSite cookies
token令牌
JWT payload 与JWT header
后端核对用户名和密码成功后,将包含用户信息的数据作为JWT的Payload,将其与JWT Header分别进行Base64编码拼接后签名,形成一个JWT Token,形成的JWT Token就是一个如同lll.zzz.xxx的字符串
对以下三篇文章学习,尝试写出token创建与认证的函数
JWT详解
token创建
jwt在项目中的应用
json.dump()函数解析
separators=(‘,’, ‘:’)参数是用来序列化时消除空格的
python字符串前b、r、u、f的作用
以 f开头表示在字符串内支持大括号内的python 表达式
b" "前缀表示:后面字符串是bytes 类型。网络编程中,服务器和浏览器只认bytes 类型数据。
base64的使用
hmac用法
为了便于理解,废话版实现的token创建与token验证函数
import base64,json,hashlib,hmac,time
salt = 'helloworld'
timeout = 360
# 返回token字符串
def create_token(user_name,exp = timeout,salt = salt): # exp单位为秒
# token有三个部分,分别为headers,payload,signature
headers={
'algorithm': 'HS256',
}
payload = {
'user_name': user_name,
"exp": int(time.time()+exp)# 过期时间戳
}
# 使用Base64 URL算法将headers的JSON对象先转码再转为字符串保存
# 由于标准的Base64编码后可能出现字符+和/,在URL中就不能直接作为参数,
# 所以可以使用urlsafe_b64encode的base64编码,其实就是把字符+和/分别变成-和_:
headers_str = json.dumps(headers, separators=(',', ':')) # 将python对象将对象中的空格去除,然后转为字符串
headers_bytes = headers_str.encode('utf-8') # 由于base64编码函数输入的类型需要为字节,这里将字符串转为bytes
headers_base64 = base64.urlsafe_b64encode(headers_bytes).replace(b'=', b'')#编码结束后得到的是bytes类型,(后
#面原因是我自己猜的,不保真。由于base64编码填充会用到=,url传参时会被转义,直接删掉,后面解码的时候再补上会比较好
headers_base64_str = headers_base64.decode('UTF-8') # 得到字符串
first = headers_base64_str
# header和payload可以直接利用base64解码出原文,
# 从header中获取哈希签名的算法,从payload中获取有效数据
# 加密payload(下面这一串,不再一步步说了)
second = base64.urlsafe_b64encode(
json.dumps(payload, separators=(',', ':')).encode('utf-8').replace(b'=', b'')).decode(
'utf-8').replace('=', '')
# 签名 把前两部分拼接之后,用哈希加密把签名两部分加密得到一个字符串
# 拼接前两部分
first_second = f"{first}.{second}"
# 对前面两部分签名
third = base64.urlsafe_b64encode(
hmac.new(salt.encode('utf-8'), first_second.encode('utf-8'), hashlib.sha256).digest()).decode('utf-8').replace('=','')
# 拼接签名和前两部分,就叫做token啦
token = ".".join([first, second, third])
return token
def verify_token(token,salt = salt,exp = timeout):
token_list = token.split('.')
headers = token_list[0]
payload = token_list[1]
signature = token_list[2]
# 应该返回的数据
result = {
'valid' : False,
'msg' : ''
}
# 判断签名是否有效
headers_payload = f"{headers}.{payload}"
new_signature = base64.urlsafe_b64encode(
hmac.new(salt.encode('utf-8'), headers_payload.encode('utf-8'), hashlib.sha256).digest()).decode(
'utf-8').replace('=','')
if(new_signature == signature):
if isinstance(payload, str):
payload = payload.encode('ascii')
rem = len(payload) % 4
if rem > 0:
payload += b'=' * (4 - rem)
# 上面这一部分是解密的部分数据补全格式
payload_data = base64.urlsafe_b64decode(payload) # 解码
data = json.loads(payload_data) # 加载payload信息为可以通过get方法获取里面的值
payload_exp = data['exp']
if( isinstance(payload_exp, int) and payload_exp<int(time.time()+exp)): # 保证payload_exp是个有效数值
result['valid'] = False
result['msg'] = 'token已失效'
else:
result['valid'] = False
result['msg'] = 'token认证失败'
else:
result['valid'] = False
result['msg'] = '非法的token'
return result
create_token(user_name='hh')
print(verify_token(“eyJhbGdvcml0aG0iOiJIUzI1NiJ9.eyJ1c2VyX25hbWUiOiJoaCIsImV4cCI6MTY2MTY2ODA2MX0.4EnhYvt90zCKpg_i4wYBylPaUg9bfiI2H4FktEc13CU”))
输出:
简洁点的:
import base64,json,hashlib,hmac,time
salt = 'helloworld'
timeout = 360
# 返回token字符串
def create_token(user_name,exp = timeout,salt = salt): # exp单位为秒
# token有三个部分,分别为headers,payload,signature
headers={
'algorithm': 'HS256',
}
payload = {
'user_name': user_name,
"exp": int(time.time()+exp)# 过期时间戳
}
first = base64.urlsafe_b64encode(
json.dumps(headers, separators=(',', ':')).encode('utf-8').replace(b'=', b'')).decode(
'utf-8').replace('=', '')
second = base64.urlsafe_b64encode(
json.dumps(payload, separators=(',', ':')).encode('utf-8').replace(b'=', b'')).decode(
'utf-8').replace('=', '')
first_second = f"{first}.{second}"
third = base64.urlsafe_b64encode(
hmac.new(salt.encode('utf-8'), first_second.encode('utf-8'), hashlib.sha256).digest()).decode('utf-8').replace('=','')
token = ".".join([first, second, third])
return token
def verify_token(token,salt = salt,exp = timeout):
token_list = token.split('.')
headers = token_list[0]
payload = token_list[1]
signature = token_list[2]
# 应该返回的数据
result = {
'valid' : False,
'msg' : ''
}
# 判断签名是否有效
headers_payload = f"{headers}.{payload}"
new_signature = base64.urlsafe_b64encode(
hmac.new(salt.encode('utf-8'), headers_payload.encode('utf-8'), hashlib.sha256).digest()).decode(
'utf-8').replace('=','')
if(new_signature == signature):
if isinstance(payload, str):
payload = payload.encode('ascii')
rem = len(payload) % 4
if rem > 0:
payload += b'=' * (4 - rem)
# 上面这一部分是解密的部分数据补全格式
payload_data = base64.urlsafe_b64decode(payload) # 解码
data = json.loads(payload_data) # 加载payload信息为可以通过get方法获取里面的值
payload_exp = data['exp']
if( isinstance(payload_exp, int) and payload_exp<int(time.time()+exp)): # 保证payload_exp是个有效数值
result['valid'] = False
result['msg'] = 'token已失效'
else:
result['valid'] = False
result['msg'] = 'token认证失败'
else:
result['valid'] = False
result['msg'] = '非法的token'
return result