一种开发的行业标准 RFC 7519 ,用于安全的表示双方之间的声明。
广泛应用在系统的用户认证
浏览器发送 用户名和密码 到服务器中,服务端判断用户名和密码是否正确,
如果正确则生成一个 token,并返回给浏览器
浏览器每次都要带有服务端返回的 token ,一起进行请求,
由服务端校验 token 的合法性
如果合法则返回数据,不合法则返回浏览器错误信息
jwt 生成 token 的示例如下(总共为三段字符串,使用 . 进行分隔)
eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.
eyJ1c2VyX2lkIjoxMTExLCJ1c2VybmFtZSI6IkhhbnkiLCJleHAiOjE2MDI3MjQxMTZ9.
-ivPhXGKYAn7ON0rMInChUBHMjiBOtvthHhdwcxvkRY
第一段字符串表示为
eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.
是 HEADER 部分,固定包含算法和 token 类型,
对 json 进行 base64url 加密
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
第二段字符串表示为
eyJ1c2VyX2lkIjoxMTExLCJ1c2VybmFtZSI6IkhhbnkiLCJleHAiOjE2MDI3MjQxMTZ9.
是 payload 部分,包含有一部分数据,对 json 进行 base64url 加密
payload = {
'user_id': 1111, # 自定义用户ID
'username': 'Hany', # 自定义用户名
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5) # 超时时间
}
第三段字符串表示为
-ivPhXGKYAn7ON0rMInChUBHMjiBOtvthHhdwcxvkRY
将前两段字符串的密文通过 . 进行拼接起来,然后使用 HS256 进行加密,
对 HS256 密文进行 base64url 加密,得到 token 的第三段
base64url(
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
your-256-bit-secret (秘钥加盐)
)
)
替换规则:
base64url 加密是先做 base64 加密,然后再将 - 替代 + , _ 替代 /
关于 jwt 的安装
pip install jwt
基于 Python 的 pyjwt 实现代码:
import jwt
import datetime
SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='
def create_token():
# 构造header
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
# 构造payload
payload = {
'user_id': 1111, # 自定义用户ID
'username': 'Hany', # 自定义用户名
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=5) # 超时时间
}
result = jwt.encode(payload = payload, key = SALT, algorithm = "HS256", headers = headers).decode('utf-8')
return result
if __name__ == '__main__':
token = create_token()
print(token)
浏览器 会携带服务器端返回的 token 进行 超时 及 合法性 校验
服务器端在获取到用户携带的 token 后,会对 token 解密为三个字符串
即 header_segment , payload_segment , crypto_segment 三部分
然后对 header_segment , payload_segment , crypto_segment 进行 base64url 解密,
得到 header , payload , signature 三部分
服务器端会对 signature 这一部分进行合法性校验
校验规则如下:
jwt 生成 token 的前两段字符(第二个 . 之前的所有字符),
即 对 HEADER 和 payload 进行 base64url 加密后产生的字符串
(从第一段明文中)获取加密算法,默认 HS256
使用 算法 + 盐 对 token 的前两段字符进行加密,将得到的结果与第三段 signature 密文进行比较
实现代码:
import jwt
from jwt import exceptions
def get_payload(token):
try:
SALT = 'iv%x6xo7l7_u9bf_u!9#g#m*)*=ej@bek5)(@u3kh*72+unjv='
verified_payload = jwt.decode(token, SALT, True)
print("token 认证成功")
return verified_payload
except exceptions.ExpiredSignatureError:
print('token 已失效')
except jwt.DecodeError:
print('token 认证失败')
except jwt.InvalidTokenError:
print('非法的 token')
if __name__ == '__main__':
token = "eyJ0eXAiOiJqd3QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyX2lkIjoxMTExLCJ1c2VybmFtZSI6IkhhbnkiLCJleHAiOjE2MDI3MjY1MjN9.r49ST_8v71BswEkvOSGjyGWY5J6ksmz8BCAhZNxjgOg"
payload = get_payload(token)
注: token 可以先自己手动生成一份,然后再进行复制粘贴到此代码中,进行 jwt 的用户认证
参考链接:
https://www.pythonav.com/wiki/detail/6/67/
2020-10-15