JWT
简介JWT
(Json WEB Token)是一种采用 Json
方式安装传输信息的方式。 JWT
有针对各种开发语言的库。 python 中使用的是 PyJWT
,它是 Python 对 JWT
的实现。
JWT
应用场景服务端往往需要一个 ID
来表示客户端的身份,可以使用 session
,也可以在服务端创建一个 ID
返回给客户端。但是,要保证客户端不可篡改。JWT
就可以实现这种需求。
JWT
是在服务端生成一个标识,并使用某种算法对标识签名。CPU
计算资源,无法让浏览器自己主动检查过期的数据以清除。这种方案的优点是,不需要在服务端存放大量的session,减少了对内存的压力。
用于认证
常应用于服务端认证接口的 无
session
方案 ,这是Jwt
最常用的场景,一旦用户登录成功,就会得到Jwt
,然后请求中就可以带上这个Jwt
。服务器中Jwt
验证通过,就可以被允许访问资源。甚至可以在不同域名中传递,在单点登录(Single Sign On)中应用广泛。
用于数据交换
Jwt
可以防止数据被篡改,它还可以使用公钥、私钥,确保请求的发送者是可信的
JWT
安装pip install pyjwt
JWT
原理可知 jwt
生成的 token
分为三部分
json
序列化base64
编码后 使用点号连接后,加密算法使用 key 计算好一个结果,再被 base64
编码,得到签名所有数据都是明文传输的,只是做了 base64,如果是敏感信息,请不要使用
jwt
。
数据签名的目的不是为了隐藏数据,而是保证数据不被篡改。如果数据篡改了,发回到服务器端,服务器使
用自己的 key 再计算一遍,然后进行签名比对,一定对不上签名。
Base64URL
Header
和 Payload
串型化的算法是 Base64URL
。这个算法跟 Base64
算法基本类似,但有一些小的不同。JWT
作为一个令牌(token
),有些场合可能会放到 URL
(比如 api.example.com/?token=xxx
)。Base64
有三个字符 +
、/
和 =
,在 URL
里面有特殊含义,所以要被替换掉:=
被省略、+
替换成 -
,/
替换成 ***_*** 。这就是 Base64URL
算法。JWT
使用JWT
方法说明方法 | 说明 |
---|---|
jwt.encode(payload, key, algorithm=‘HS256‘, headers=None, json_encoder=None) |
生成 jwt, bytes 类型的 base64 编码 |
jwt.decode(jwt, key=‘‘, verify=True, algorithms=None, options=None, **kwargs) |
解码 jwt 为 bytes 类型的 json |
jwt.get_unverified_header(jwt) |
返回一个未验证的 jwt 头部信息 |
jwt.encode
参数说明
def encode(self,
payload, # type: Union[Dict, bytes]
key, # type: str
algorithm='HS256', # type: str
headers=None, # type: Optional[Dict]
json_encoder=None # type: Optional[Callable]
):
jwt.decode
参数说明
def decode(self,
jwt, # type: str
key='', # type: str
verify=True, # type: bool
algorithms=None, # type: List[str]
options=None, # type: Dict
**kwargs):
jwt.get_unverified_header()
参数说明
def get_unverified_header(self, jwt):
"""Returns back the JWT header parameters as a dict()
Note: The signature is not verified so the header parameters
should not be fully trusted until signature verification is complete
"""
headers = self._load(jwt)[2]
self._validate_headers(headers)
return headers
jwt.encode()
方法使用import jwt
password = '123456'
# 生成bytes类型的token
token = jwt.encode({"payload":'this is my payload'}, password, 'HS256')
print(' token:',token)
head, payload, signature = token.split(b'.') # 将成成的token(是bytes类型)切割成三段: head, payload, signature
print(' head:',head)
print(' payload:',payload)
print('signature:',signature)
------------------------------结果--------------------------------------
token: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXlsb2FkIjoidGhpcyBpcyBteSBwYXlsb2FkIn0.bPGtksZQ-ncY5mya0bF7EmpO82nlN1ohk9L2Dl2D4RA'
head: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9'
payload: b'eyJwYXlsb2FkIjoidGhpcyBpcyBteSBwYXlsb2FkIn0'
signature: b'bPGtksZQ-ncY5mya0bF7EmpO82nlN1ohk9L2Dl2D4RA'
jwt.decode()
方法使用import jwt
import base64
password = '123456'
# 生成bytes类型的token
token = jwt.encode({"payload":'this is my payload'}, password, 'HS256')
# 此函数是为了避免转码时候 base64 编码结尾处缺少 b'=',而报错.
def addpad(x):
suffix = 4 - len(x) % 4
return x + b'=' * suffix
head, payload, signature = token.split(b'.') # 将成成的token(是bytes类型)切割成三段: head, payload, signature
# 将 token (bytes 类型)转换为原来的类型
token_decode = jwt.decode(token, password, algorithms=['HS256'])
head_decode = base64.urlsafe_b64decode(addpad(head))
payload_decode = base64.urlsafe_b64decode(addpad(payload))
signature_decode = base64.urlsafe_b64decode(addpad(signature))
print(' token_decode:',token_decode, type(token_decode))
print(' head_decode:',head_decode, type(head_decode))
print(' payload_decode:',payload_decode, type(payload_decode))
print('signature_decode:',signature_decode, type(signature_decode))
------------------------------结果--------------------------------------
token_decode: {'payload': 'this is my payload'} <class 'dict'>
head_decode: b'{"typ":"JWT","alg":"HS256"}' <class 'bytes'>
payload_decode: b'{"payload":"this is my payload"}' <class 'bytes'>
signature_decode: b'l\xf1\xad\x92\xc6P\xfaw\x18\xe6l\x9a\xd1\xb1{\x12jN\xf3i\xe57Z!\x93\xd2\xf6\x0e]\x83\xe1\x10' <class 'bytes'>
jwt.decode()
方法实现过期验证import jwt
import datetime
import threading
event = threading.Event()
passwd = '123456'
token = jwt.encode({
'a':'test',
'exp': int(datetime.datetime.now().timestamp() + 5)
}, passwd, 'HS256')
print(token)
print('===============================')
print('start at about: ',int(datetime.datetime.now().timestamp()))
while True:
if not event.wait(1):
try:
print(jwt.decode(token, passwd))
except Exception as e:
print(e)
break
执行结果
b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJhIjoidGVzdCIsImV4cCI6MTU1MzQ0MDc5OH0.jzwOxmsp3zqVTXi38hsmu8K7c47j4NV8nPxQe9cQ3E0'
===============================
start at about: 1553440793
{'a': 'test', 'exp': 1553440798}
{'a': 'test', 'exp': 1553440798}
{'a': 'test', 'exp': 1553440798}
{'a': 'test', 'exp': 1553440798}
{'a': 'test', 'exp': 1553440798}
Signature has expired
jwt.get_unverified_header(jwt)
方法使用import jwt
password = '123456'
token = jwt.encode({"payload":'this is my payload'}, password, 'HS256')
print(' token:',token)
print('jwt_header:',jwt.get_unverified_header(token))
------------------------------结果--------------------------------------
token: b'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJwYXlsb2FkIjoidGhpcyBpcyBteSBwYXlsb2FkIn0.bPGtksZQ-ncY5mya0bF7EmpO82nlN1ohk9L2Dl2D4RA'
jwt_header: {'typ': 'JWT', 'alg': 'HS256'}
原文:https://www.cnblogs.com/shichangming/p/10591312.html