JWT(Json WEB Token)
Posted scm
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了JWT(Json WEB Token)相关的知识,希望对你有一定的参考价值。
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
分为三部分
- header: 由数据类型、加密算法构成
- payload: 负载就是要传输的数据,一般来说放入python对象即可,会被
json
序列化 - signature: 签名部分。是前面2部分数据分别
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'lxf1xadx92xc6Pxfawx18xe6lx9axd1xb1{x12jNxf3ixe57Z!x93xd2xf6x0e]x83xe1x10' <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'}
!-->!-->以上是关于JWT(Json WEB Token)的主要内容,如果未能解决你的问题,请参考以下文章
简单代码实现JWT(json web token)完成SSO单点登录
JSON Web Token (JWT) Python 的实现
java小技能:JWT(json web token)认证实现
Json Web Token (JWT) 究竟是如何减少人在循环攻击的?