1、token介绍
- token:服务端生成的一串字符串,可以解决频繁登录的问题;
- 它作为客户端进行请求的一个令牌:
第一次登录后,服务器生成一个token返回给客户端;
客户端只需要带上token来请求数据即可,无需再次带上用户名和密码; - 目的:可以减轻服务器的压力,减少频繁的查询数据库,使服务器更加健壮;
2、jwt生成、校验token原理
2.1 生成原理
jwt的生成token格式如下,即:由 . 连接的三段字符串组成。
生成规则如下:
- 第一段HEADER部分,固定包含算法和token类型,对此json进行base64url加密,这就是token的第一段;
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
- 第二段PAYLOAD部分,包含一些数据,对此json进行base64url加密,这就是token的第二段;
{
"name": "wenjin",
"id": "1",
…
}
- 第三段SIGNATURE部分,把前两段的base密文通过
.拼接起来,然后对其进行HS256加密,再然后对hs256密文进行base64url加密,最终得到token的第三段。
base64url(
HMACSHA256(
base64UrlEncode(header) + "." + base64UrlEncode(payload),
your-256-bit-secret (秘钥加盐)
)
)
最后将三段字符串通过 .拼接起来就生成了jwt的token。
注意:base64url加密是先做base64加密,然后再将 - 替代 + 及 _ 替代 / 。
2.2 校验原理
一般在认证成功后,把jwt生成的token返回给用户,以后用户再次访问时候需要携带token,此时jwt需要对token进行超时及合法性校验。
-
将token分割成
header_segment、payload_segment、crypto_segment三部分 -
对第一部分
header_segment进行base64url解密,得到header -
对第二部分
payload_segment进行base64url解密,得到payload -
对第三部分
crypto_segment进行base64url解密,得到signature -
对第三部分
signature部分数据进行合法性校验- 拼接前两段密文,即:
signing_input - 从第一段明文中获取加密算法,默认:
HS256 - 使用 算法+盐 对
signing_input进行加密,将得到的结果和signature密文进行比较。
- 拼接前两段密文,即:
3、安全相关
- jwt生成的token第一段、第二段内容采用base64编码,可以反向被解码;
- 但是第三段内容在加密的时候,加了盐的原因【用户无法获取盐的信息】,因此jwt生成的token不会被破解;
例如:用户发送请求时,可以修改第二段用户信息内容,但是因为不知道盐的信息,无法生成正确的第三段内容
4、相关代码
4.1 安装第三方包pyjwt
pip install pyjwt
4.2 代码
#!/usr/bin/env python
# -*- coding:utf-8 -*-
import jwt
import datetime
from jwt import exceptions
from django.conf import settings
def create_token(payload, timeout=20):
"""
:param payload: 例如:{'user_id':1,'username':'wupeiqi'}用户信息
:param timeout: token的过期时间,默认20分钟
:return:
"""
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
payload['exp'] = datetime.datetime.utcnow() + datetime.timedelta(seconds=timeout)
result = jwt.encode(payload=payload, key=settings.SECRET_KEY.encode('utf-8'), algorithm="HS256", headers=headers)
return result
def parse_payload(token):
"""
对token进行和发行校验并获取payload
:param token:
:return:
"""
try:
verified_payload = jwt.decode(token, settings.SECRET_KEY.encode('utf-8'), algorithms=["HS256"])
return True, verified_payload
except exceptions.ExpiredSignatureError:
error = 'token已失效'
except jwt.DecodeError:
error = 'token认证失败'
except jwt.InvalidTokenError:
error = '非法的token'
return False, error