JWT

jwt=Json Web token

#原理
“”"
1)jwt分三段式:头.体.签名 (head.payload.sgin)
2)头和体是可逆加密,让服务器可以反解出user对象;签名是不可逆加密,保证整个token的安全性的
3)头体签名三部分,都是采用json格式的字符串,进行加密,可逆加密一般采用base64算法,不可逆加密一般采用hash(md5)算法
4)头中的内容是基本信息:公司信息、项目组信息、token采用的加密方式信息
{
“company”: “公司信息”,

}
5)体中的内容是关键信息:用户主键、用户名、签发时客户端信息(设备号、地址)、过期时间
{
“user_id”: 1,

}
6)签名中的内容时安全信息:头的加密结果 + 体的加密结果 + 服务器不对外公开的安全码 进行md5加密
{
“head”: “头的加密字符串”,
“payload”: “体的加密字符串”,
“secret_key”: “安全码”
}
“”"

校验
“”"
1)将token按 . 拆分为三段字符串,第一段 头加密字符串 一般不需要做任何处理
2)第二段 体加密字符串,要反解出用户主键,通过主键从User表中就能得到登录用户,过期时间和设备信息都是安全信息,确保token没过期,且时同一设备来的
3)再用 第一段 + 第二段 + 服务器安全码 不可逆md5加密,与第三段 签名字符串 进行碰撞校验,通过后才能代表第二段校验得到的user对象就是合法的登录用户
“”"

drf项目的jwt认证开发流程(重点)
“”"
1)用账号密码访问登录接口,登录接口逻辑中调用 签发token 算法,得到token,返回给客户端,客户端自己存到cookies中

2)校验token的算法应该写在认证类中(在认证类中调用),全局配置给认证组件,所有视图类请求,都会进行认证校验,所以请求带了token,就会反解出user对象,在视图类中用request.user就能访问登录的用户

注:登录接口需要做 认证 + 权限 两个局部禁用
“”"

简单使用

1.安装pip install djangorestframework-jwt
2.继承AbstractUser表
3.创建超级用户
4.在urls.py中
from rest_framework_jwt.views import ObtainJSONWebToken,VerifyJSONWebToken,RefreshJSONWebToken,obtain_jwt_token
path(‘login/’, obtain_jwt_token),

注:这是建立在继承AbstractUser的基础上使用的!!!!!!


自定制auth认证类

from rest_framework_jwt.authentication import BaseAuthentication,BaseJSONWebTokenAuthentication
from rest_framework.exceptions import AuthenticationFailed
from rest_framework_jwt.authentication import jwt_decode_handler
from rest_framework_jwt.authentication import get_authorization_header,jwt_get_username_from_payload
from rest_framework import exceptions
class MyToken(BaseJSONWebTokenAuthentication):  #继承BaseJSONWebTokenAuthentication这个类
    def authenticate(self, request):  #与认证方式一样重写authenticate
        jwt_value=str(request.META.get('HTTP_AUTHORIZATION'))  #获取要认证的数据或者直白的说token!
        try:
            payload = jwt_decode_handler(jwt_value)  # 取出三段中的中间一段
        except Exception:
            raise exceptions.AuthenticationFailed("认证失败")
        user=self.authenticate_credentials(payload) #将其转化成对象
        return user,None  #返回对象(注意是对象),token(可以返回none)
    

一个正常的登录(返回jwt)

# 使用用户名,手机号,邮箱,都可以登录#
# 前端需要传的数据格式
{
"username":"lqz/1332323223/33@qq.com",
"password":"lqz12345"
}
# 视图
from rest_framework.views import APIView
from rest_framework.viewsets import ViewSetMixin, ViewSet

from app02 import ser
class Login2View(ViewSet):  # 跟上面完全一样
    def login(self, request, *args, **kwargs):
        # 1 需要 有个序列化的类
        login_ser = ser.LoginModelSerializer(data=request.data,context={'request':request})
        # 2 生成序列化类对象
        # 3 调用序列号对象的is_validad
        login_ser.is_valid(raise_exception=True)
        token=login_ser.context.get('token')
        # 4 return
        return Response({'status':100,'msg':'登录成功','token':token,'username':login_ser.context.get('username')})
    
# 序列化类
from rest_framework import serializers
from api import models
import re
from rest_framework.exceptions import ValidationError

from rest_framework_jwt.utils import jwt_encode_handler,jwt_payload_handler
class LoginModelSerializer(serializers.ModelSerializer):
    username=serializers.CharField()  # 重新覆盖username字段,数据中它是unique,post,认为你保存数据,自己有校验没过
    class Meta:
        model=models.User
        fields=['username','password']

    def validate(self, attrs):

        print(self.context)

        # 在这写逻辑
        username=attrs.get('username') # 用户名有三种方式
        password=attrs.get('password')
        # 通过判断,username数据不同,查询字段不一样
        # 正则匹配,如果是手机号
        if re.match('^1[3-9][0-9]{9}$',username):
            user=models.User.objects.filter(mobile=username).first()
        elif re.match('^.+@.+$',username):# 邮箱
            user=models.User.objects.filter(email=username).first()
        else:
            user=models.User.objects.filter(username=username).first()
        if user: # 存在用户
            # 校验密码,因为是密文,要用check_password
            if user.check_password(password):
                # 签发token
                payload = jwt_payload_handler(user)  # 获取三段式中的第二部分
                token = jwt_encode_handler(payload)  # 把payload传入,得到token
                self.context['token']=token
                self.context['username']=user.username
                return attrs
            else:
                raise ValidationError('密码错误')
        else:
            raise ValidationError('用户不存在')
# jwt的配置
import datetime
JWT_AUTH={
    'JWT_EXPIRATION_DELTA': datetime.timedelta(days=7), # 过期时间,手动配置
}


认证类
from rest_framework_jwt.authentication import BaseJSONWebTokenAuthentication
from rest_framework_jwt.utils import jwt_decode_handler
from rest_framework.exceptions import AuthenticationFailed
class MyToken(BaseJSONWebTokenAuthentication):  #因为运用到了django自带的user表所以调用BaseJSONWebTokenAuthentication
    def authenticate(self, request):  #重写authenticate
        jwt_value=request.META.get('HTTP_AUTHORIZATION')
        if jwt_value:
            try:
                payload = jwt_decode_handler(jwt_value) #将三段反解,解出中间那一段
            except Exception:
                raise AuthenticationFailed('认证发生错误')
            user = self.authenticate_credentials(payload) #获取user数据
            return user,None
        raise AuthenticationFailed('请携带认证信息')
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值