django自带的jwt认证经常会满足不了我们的需求,因此我们往往要对其进行重写才能应用。当我们有多个用户类时,我们应该怎么办呢?我的想法是分别写认证方法,然后局部认证。
首先我们看下模型类的定义。由于项目的需要,我设置两个模型类,
学生与教师。
模型类定义
学生
class Student(models.Model):
stu_id = models.AutoField(verbose_name='学生编号', primary_key=True)
stu_email = models.EmailField(verbose_name='邮箱')
stu_name = models.CharField(verbose_name='姓名', max_length=32)
sex_choice = (
('女性', '女'),
('男性', '男'),
)
stu_sex = models.SmallIntegerField(verbose_name='性别', choices=sex_choice, default=1)
class_id = models.IntegerField(verbose_name='班级编号',)
grade_id = models.IntegerField(verbose_name='年级编号',)
head_img = models.CharField(max_length=255,verbose_name="头像")
stu_password = models.CharField(verbose_name='密码', max_length=64)
stu_create_time = models.DateField(verbose_name='创建时间', auto_now_add=True)
stu_update_time = models.DateField(verbose_name='更新时间', auto_now=True)
is_delete = models.BooleanField(default=False, verbose_name='是否被删除')
class Meta:
db_table = 'Student'
verbose_name = '学生表'
verbose_name_plural = verbose_name
教师
class Teacher(models.Model):
tea_id = models.AutoField(verbose_name='教师编号', primary_key=True)
tea_name = models.CharField(verbose_name='姓名', max_length=32)
tea_sex = models.CharField(verbose_name='性别', max_length=20)
tea_email = models.EmailField(verbose_name='邮箱')
tea_password = models.CharField(verbose_name='密码', max_length=64)
role = models.CharField(verbose_name='角色', max_length=20,default="教师")
tea_create_time = models.DateField(verbose_name='创建时间', auto_now_add=True)
tea_update_time = models.DateField(verbose_name='更新时间', auto_now=True)
is_delete = models.BooleanField(default=False, verbose_name='是否删除')
head_img = models.CharField(verbose_name='头像',max_length=1024,default="https://image.so.com/view?q=%E7%94%A8%E6%88%B7%E5%A4%B4%E5%83%8F&listsrc=sobox&listsign=8a31dae9c8165262bc6bf65fda6cba65&src=360pic_strong&correct=%E7%94%A8%E6%88%B7%E5%A4%B4%E5%83%8F&ancestor=list&cmsid=2d9514bb9cb82e8d68f0516fcfd2c041&cmras=0&cn=0&gn=0&kn=0&crn=0&bxn=0&fsn=60&cuben=0&pornn=0&manun=33&adstar=0&clw=283#id=8a31dae9c8165262bc6bf65fda6cba65&currsn=0&ps=86&pc=86")
class Meta:
db_table = 'Teacher'
verbose_name = '教师表'
verbose_name_plural = verbose_name
登录
class LoginView(APIView):
authentication_classes = [] # 取消全局认证
def post(self, request, *args, **kwargs):
tea_email = request.data.get('tea_email')
tea_pwd = request.data.get('tea_password')
tea_pwd=md5(tea_pwd)
user_obj = Teacher.objects.filter(tea_email=tea_email, tea_password=tea_pwd).first()
if not user_obj:
return Response({'code': 0, 'error': '用户名或密码错误'})
payload = {
'tea_id': user_obj.tea_id, # 自定义用户ID
'tea_name': user_obj.tea_name, # 自定义用户名
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=100), # 设置超时时间,1min
"role":user_obj.role
}
jwt_token = create_token(payload=payload)
return Response({'code': 1, 'token': jwt_token,})
class StuLoginView(APIView):
authentication_classes = [] # 取消全局认证
def post(self, request, *args, **kwargs):
stu_email = request.data.get('stu_email')
stu_pwd = request.data.get('stu_password')
stu_pwd=md5(stu_pwd)
user_obj = Student.objects.filter(stu_email=stu_email, stu_password=stu_pwd).first()
if not user_obj:
return Response({'code': 0, 'error': '用户名或密码错误'})
payload = {
'stu_id': user_obj.stu_id, # 自定义用户ID
'stu_name': user_obj.stu_name, # 自定义用户名
'exp': datetime.datetime.utcnow() + datetime.timedelta(minutes=10), # 设置超时时间,1min
"role": user_obj.role
}
jwt_token = create_token(payload=payload)
return Response({'code': 1, 'token': jwt_token})
jwt认证
class JWTQueryParamsAuthentication(BaseAuthentication):
def authenticate(self, request):
token = request.query_params.get('token')
if not token:
raise AuthenticationFailed({"code": 401, "error": "登录成功后才能访问"})
# 切割
# 解密payload,判断是否过期
# 验证第三段的合法性
import jwt
salt = settings.SECRET_KEY
try:
# 从token中获取payload【不校验合法性】
# unverified_payload = jwt.decode(token, None, False)
# print(unverified_payload)
# 从token中获取payload【校验合法性】
payload = jwt.decode(jwt=token, key=salt, algorithms=["HS256"])
return (payload,token)
except jwt.exceptions.ExpiredSignatureError:
error = "token已失效"
raise AuthenticationFailed({"code": 401, "error": error})
except jwt.exceptions.DecodeError:
error = "token已认证失败"
raise AuthenticationFailed({"code": 401, "error": error})
except jwt.exceptions.InvalidTokenError:
error = "非法的token"
raise AuthenticationFailed({"code": 401, "error": error})
def create_token(payload):
salt = settings.SECRET_KEY
# 构造Header,默认如下
headers = {
'typ': 'jwt',
'alg': 'HS256'
}
jwt_token = jwt.encode(headers=headers, payload=payload, key=salt, algorithm='HS256')
return jwt_token