json web token的结构
jwt的结构由三个部分组成:
- Header
- Payload
- Signature
header头的格式如下
headers = {
#typ 属性表示令牌类型,这里就是 JWT。
'typ': ' jwt',
# alg 属性表示签名所使用的算法,JWT 签名默认的算法为 HMAC SHA256 , alg 属性值 HS256 就是 HMAC SHA256 算法
'alg': 'HS256'
}
Payload的格式
#常用格式
payload = {
iss:jwt的签发者/发行人;
sub:主题;
aud:接收方;
exp:jwt过期时间;
nbf:jwt生效时间;
iat:签发时间
jti:jwt唯一身份标识,可以避免重放攻击
}
#也可以不必遵循,例:
payload = {
'userid': userid, #用户表id
'user_code': username #用户名
}
Signature格式
#这是对前边header和payload进行签名,以后在发送/接收消息时,如果在数据被更改,则这段token值会变化,可以在每次传送数据时,判断该token是否被修改,由此判断数据是否安全
token = jwt.encode(payload=payload, key=salt, algorithm='HS256', headers=headers).decode('utf-8')
#生成的token为xxxxxx.yyyyyy.zzzzzz格式
**
场景:
**
Authorization (授权) : 用户登录发送请求,每个请求都将包含JWT,允许用户访问该令牌允许的路由、服务和资源。单点登录是现在广泛使用的JWT的一个特性,因为它的开销很小,并且可以轻松地跨域使用。
Information Exchange (信息交换) : 对于安全的在各方之间传输信息而言,JSON Web Tokens无疑是一种很好的方式。因为JWT可以被签名,例如,用公钥/私钥对,你可以确定发送人就是它们所说的那个人。另外,由于签名是使用头和有效负载计算的,您还可以验证内容没有被篡改
例如前端发送一个授权登陆请求
**
后端代码
**
from rest_framework.generics import ListAPIView
from rest_framework.response import Response
from dadaoapi.apps.home import models
from dadaoapi.settings import constant
import jwt
#dev是配置文件
from dadaoapi.settings import dev
import requests
from dadaoapi.apps.home import serializers
import json
import random #随机生成字符串
import string
class Getopenid():
"""获取微信的openid"""
def getopenid(self, js_code, *args, **kwargs):
url = "https://api.weixin.qq.com/sns/jscode2session" #请求微信服务器发送openid
app_id = "-----------" #填上自己小程序的APPID
app_secret = "--------------------------" #填上自己小程序的app_secret
#拼接url
get_url = url + "?appid=" + app_id + "&secret=" + app_secret + "&js_code=" + js_code + "&grant_type=authorization_code"
ret = requests.get(get_url)
openid = ret.json()['openid']
secret = ret.json()['session_key']
return (openid, secret)
# 前端发送code获取openid并发送jwt
class GetOpenId(ListAPIView):
"""注册用户信息并发送jwt"""
authentication_classes = [] #登陆界面不进行authentication认证
def post(self, request, *args, **kwargs):
params = request.data
js_code = params.get('jscode') #获取到前端发送的code
nickname = params.get('nickname')
city = params.get('city')
gender = params.get('gender')
# print(params)
# print(js_code, nickname, city, gender)
openid_obj = Getopenid()
openid, secret = openid_obj.getopenid(js_code)
# print(openid, type(openid))
try:
user = models.UserToken.objects.get(token=openid) #用户已存在
except Exception as e:
user = None
if user:
pass
else:
"""测试用例,如果用户已经注册则不创建用户,否则随机创建用户名"""
usertoken = models.UserToken.objects.create(token=openid)
# string.digits = 0123456789
# string.ascii_letters = 26个小写字母,26个大写字母
str_list = random.sample(string.digits + string.ascii_letters + '_' + '!' + '#' + '$' + '*', 10) # 随机生成字符串
random_str = ''.join(str_list)
name = 'dd_' + random_str # 随机生成字符串
name_login = models.UserTable.objects.filter(user_code=name)
print(name_login)
print(456)
if name_login:
while not name_login:
str_list = random.sample(string.digits + string.ascii_letters + '_' + '!' + '#' + '$' + '*',
10) # 随机生成字符串
random_str = ''.join(str_list)
name = 'dd_' + random_str # 随机生成字符串
name_login = models.UserTable.objects.filter(user_code=name)
models.UserTable.objects.create(
user_id=usertoken, user_code=name, nickname=nickname, gender=gender, city=city
)
else:
models.UserTable.objects.create(
user_id=usertoken, user_code=name, nickname=nickname, gender=gender, city=city
)
print(user)
#进行jwt,jwt需要有用户名和密码,随机生成密码,将openid作为用户名
#构造headers
userid = models.UserTable.objects.filter(user_id__token=openid).values('id').first()['id'] #取出用户id
username = models.UserTable.objects.filter(user_id__token=openid).values('user_code').first()['user_code'] #取出用户名
headers = {
'typ': ' jwt',
'alg': 'HS256'
}
#构造payload
payload = {
'userid': userid, #用户表id
'user_code': username #用户名
}
#SECRET_KEY = '9d^4a9d=m2u(d+21ck1%&d7lj9wz7vr*x!$^!@gxszlvgq@4_2'这一段代码可在setting中设置默认加盐
salt = dev.SECRET_KEY #加盐
token = jwt.encode(payload=payload, key=salt, algorithm='HS256', headers=headers).decode('utf-8')
res = {
'code': '1000',
'data': None
}
res['data'] = token
return Response(res)
**
可添加认证
**
#可添加auth认证,判断数据
from rest_framework.authentication import BaseAuthentication
import jwt
from jwt import exceptions
from dadaoapi.settings import dev
from rest_framework.response import Response
from rest_framework.exceptions import AuthenticationFailed #导入drf报错的包
class JwtQueryAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.META.get('HTTP_TOKEN')
salt = dev.SECRET_KEY
payload = None
msg = None
print("经过这里")
try:
payload = jwt.decode(token, salt, True)
except exceptions.ExpiredSignatureError:
raise AuthenticationFailed({'code': 2001,'error': "token已失效"})
except jwt.DecodeError:
raise AuthenticationFailed({'code': 2002, 'error': "token认证失败"})
except jwt.InvalidTokenError:
raise AuthenticationFailed({'code': 2003, 'error': "非法的token"})
if not payload:
return Response({'code': 1002, 'error': msg})
print(payload['nickname'], payload['userid'])