前后端分离后,如果客户端使用的原生应用(iOS,安卓),我们就无法使用cookie和session机制,所以我们使用另一套方案token
token机制:
1.在前端对后端进行访问时,后端生成一个用base64加密的token串(包含个人信息过期时间和签名)返还给前端。
2.前端第接收到token并储存在前端。
3.前端再次访问是request请求携带token串 (一般放在http的请求头里面)
4.后端接收到请求后解析前端传来的token值,因为里面有之前加密的签名,所以把签名再生成一次,和前端传来的签名进行比对,如果相同,说明前端传来的token值没有问题。如果不相同,说明前端有问题
优点:后端不用占用空间存储,直接计算出token进行返回
JWT json-web-token(方案)
三大组成:
- header:{‘alg’:‘HS256’, ‘typ’:‘JWT’} #用来指定算法和类别,最终需要将这部分转化成json字符串并用base64进行加密
- payload:添加共有声明,私有声明
公有声明:常见的问题比如过期时间、签发者、创建时间等
私有声明:根据自己的业务需求,自定义
私有声明在调用JWT时以字典参数的方式传进去,最终将公有声明和私有声明合并在一个字典内。 - 签名:
将传入的key值和加密的header和加密的payload三者进行hmac-SHA256算法加密,
加密后的值用base64再进行一次加密,生成签名
最终将加密后的header 和payload 和签名用.隔开返回一个token串
代码层面:
```python
import json
import time
import copy
import hmac
import base64
class my_jwt:
def __init__(self):
pass
@staticmethod
def b64encode(content):
#return base64.urlsafe_b64encode(content).split(b'=',b'')
return base64.urlsafe_b64encode(content).replace(b'=', b'')
@staticmethod
def b64decode(b):
mec = len(b) % 4
if mec > 0:
b += b'=' * (4-mec)
return base64.urlsafe_b64decode(b)
@staticmethod
def encode(payload,key,exp=300):
header = {'typ':'JWT','alg':'HS256'}
header_js = json.dumps(header,sort_keys=True,separators=(',',':'))
header_bs = my_jwt.b64encode(header_js.encode())
payload_self = copy.deepcopy(payload)
if not isinstance(exp,str) and not isinstance(exp,int):
raise TypeError('not be str or int!')
payload_self['exp'] = time.time() + int(exp)
payload_js = json.dumps(payload_self,sort_keys=True,separators=(',',':'))
payload_bs = my_jwt.b64encode(payload_js.encode())
if isinstance(key,str):
key = key.encode()
hm = hmac.new(key,header_bs + b'.' + payload_bs,digestmod='SHA256')
sign_bs = my_jwt.b64encode(hm.digest())
return header_bs + b'.' +payload_bs + b'.' +sign_bs
@staticmethod
def decode(token,key):
header_bs,payload_bs,sign_bs = token.split(b'.')
if isinstance(key,str):
key = key.encode()
hm = hmac.new(key,header_bs + b'.' + payload_bs,digestmod='SHA256')
si_bs = my_jwt.b64encode(hm.digest())
if sign_bs != si_bs:
raise
payload_js = my_jwt.b64decode(payload_bs)
payload = json.loads(payload_js)
if 'exp' in payload:
now = time.time()
if now > payload['exp']:
raise
return payload
if __name__ == "__main__":
token = my_jwt.encode({'username':'zhaowenhao'},'123456',300)
print(token)
print('以下是校验结果:')
print(my_jwt.decode(token,'123456'))
以上是我参看了jwt机制自己写的token方案。
python中提供的pyjwt
大体用法和我的相同,需要注意一点是它在传入公有声明和私有声明时需要在传入的参数中一同定义并传入,而我写的是函数本身就带公有声明,只需传入私有声明即可。
pyjwt演示:
jwt.encode({‘username’:‘guoxiaonao’},‘123456’)
b’eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VybmFtZSI6Imd1b3hpYW9uYW8ifQ.kgWAwfADg3M79kr0rX3GW5zrkFdpUK2Uq_9qnQ9Ub4I’a = jwt.encode({‘username’:‘guoxiaonao’},‘123456’,algorithm=‘HS256’)
jwt.decode(a,‘123456’)
{‘username’: ‘guoxiaonao’}