什么是JWT
JWT
JSON Web Token (JWT)是一个开放标准(RFC 7519),它定义了一种紧凑的、自包含的方式,用于作为JSON对象在各方之间安全地传输信息。该信息可以被验证和信任,因为它是数字签名的。
PyJWT
是Python对JWT的实现
相关文档
安装
pip install pyjwt
使用简介
jwt.encode(payload: Dict[str, Any], key: str, algorithm: str = "HS256", headers: Optional[Dict] = None, json_encoder: Optional[Type[json.JSONEncoder]] = None, ) -> str
import jwt
key = "thisisthekey"
payload = {'name': 'monkeyjerry'}
token = jwt.encode(payload, key, algorithm="HS256") # 默认算法HS256
print(token, type(token))
--------输出结果------------
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJuYW1lIjoibW9ua2V5amVycnkifQ.THZNd4mPF_HPU4xXOgymKejNT1yP_lSox_xWFODPBdY <class 'str'>
jwt生成的token分为三部分:
-
header:由数据类型、加密算法构成
-
payload:负载就是要传输的数据,一般来说放入python对象即可,会被json序列化
-
signature:签名部分。是前面2部分数据分别base64编码后使用点号连接后,加密算法使用key计算好一个结果,再被base64编码,得到签名
-
jwt.decode(jwt: str, key: str = "", algorithms: List[str] = None, options: Dict = None, **kwargs, ) -> Dict[str, Any])
- 注:algorithms必须为list
import jwt
key = "thisisthekey"
payload = {'name': 'monkeyjerry'}
token = jwt.encode(payload, key, algorithm="HS256")
token_decrypt = jwt.decode(token, key, algorithms=["HS256"])
print(token_decrypt)
-------输出结果-------
{'name': 'monkeyjerry'}
数据签名
import base64
import jwt
key = "thisisthekey"
payload = {'name': 'monkeyjerry'}
token = jwt.encode(payload, key, algorithm="HS256")
header, payload, signature = token.split('.')
def add_eq(encrypt_str):
'''为base64编码补齐等号'''
rest = 4 - len(encrypt_str) % 4
return encrypt_str + '=' * rest
print('header=', base64.urlsafe_b64decode(add_eq(header)))
print('payload=', base64.urlsafe_b64decode(add_eq(payload)))
print('signature=', base64.urlsafe_b64decode(add_eq(signature)))
- 所有数据都是明文传输的,只是做了base64,因此敏感信息不要使用jwt
- 数据签名的目的不是为了隐藏数据,而是保证数据不被篡改
# jwt.encode() 部分源码如下
......
segments.append(base64url_encode(json_header))
segments.append(base64url_encode(payload))
# Segments
signing_input = b".".join(segments)
try:
alg_obj = self._algorithms[algorithm]
key = alg_obj.prepare_key(key) # 1
signature = alg_obj.sign(signing_input, key) # 2
......
segments.append(base64url_encode(signature))
encoded_string = b".".join(segments)
return encoded_string.decode("utf-8")
......
- 数据签名的目的不是为了隐藏数据,而是保证数据不被篡改。如果数据篡改了,发回到服务器端,服务器使用自己的key再计算一遍,然后进行签名比对,一定对不上签名
import base64
import jwt
key = "thisisthekey"
payload = {'name': 'monkeyjerry'}
token = jwt.encode(payload, key, algorithm="HS256") # 客户端发送的数据(jwt)
_, _, signature_send = token.rpartition('.') # 发送数据中的签名
print(signature_send)
# 数据签名防篡改:服务端使用自己的key再计算一遍得到签名后与发送的数据签名进行比对
# 仿照jwt.encode关键代码计算即可
from jwt import algorithms
alg = algorithms.get_default_algorithms()['HS256']
new_key = alg.prepare_key(key)
# 获取前两部分 header, payload
signing_input, _, _ = token.rpartition('.')
# print(signing_input)
# 使用key签名
signature = alg.sign(signing_input.encode(), new_key)
# print(signature)
print('-------------------------')
print(base64.urlsafe_b64encode(signature).decode().strip('='))
print('~~~~~~~~~~~~~~~~~~~~~~~~~')
signing_input_modified = signing_input.encode() + b'modified data'
signature = alg.sign(signing_input_modified, new_key)
print(base64.urlsafe_b64encode(signature).decode().strip('='))
---------------- 输出结果----------------------
THZNd4mPF_HPU4xXOgymKejNT1yP_lSox_xWFODPBdY
-------------------------
THZNd4mPF_HPU4xXOgymKejNT1yP_lSox_xWFODPBdY
~~~~~~~~~~~~~~~~~~~~~~~~~
SQhR7tNDi5lkwyCs0QQfhI1RfYF592DnoVTh7vFV9sg
这里的key仅用于示例,实际项目中一般会使用更高强度的key
- jwt使用场景
- 认证:这是jwt最常用的场景,一旦用户登录成功,就会得到jwt,然后请求中就可以带上这个Jwt。服务器中jwt验证通过,就可以被允许访问资源。甚至可以在不同域名中传递,在单点登录(Single Sign On)中应用广泛
- 数据交换:jwt可以防止数据被篡改,它还可以使用公钥、私钥加密,确保请求的发送者是可信的
参考及扩展阅读
- 五分钟带你了解啥是JWT
- magedu