drf——jwt

这篇具有很好参考价值的文章主要介绍了drf——jwt。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

jwt原理

使用jwt认证和使用session认证的区别

drf——jwt

drf——jwt文章来源地址https://www.toymoban.com/news/detail-463721.html

三段式

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

# 1. header jwt的头部承载两部分信息:
声明类型 这里是jwt
声明加密的算法 通常直接使用 HMSC SHA256
公司信息
{
    'typ':'jwt',
    'alg':'HS256'
}
然后将头部进行base64编码 构成了第一部分
eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9

# 2. payload 载荷就是存放有效信息的地方
当前用户信息 用户名 用户id
exp:jwt的过期时间 这个过期时间必须要大于签发时间

定义一个payload:
{
    "exp":"1234567890",
    "name":"jason",
    "user_id":99
}
然后将其进行base64编码 得到jwt的第二部分
eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9

# signature  JWT的第三部分是一个签证信息,这个签证信息由三部分组成:

header (base64后的)
payload (base64后的)
secret
这个部分需要base64加密后的header和base64加密后的payload使用.连接组成的字符串,然后通过header中声明的加密方式进行加盐secret组合加密,然后就构成了jwt的第三部分。

将这三部分用.连接成一个完整的字符串,构成了最终的jwt:

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9.TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ

jwt开发流程

# 使用jwt认证的开发流程 就是两部分
	第一部分:签发token的过程 登录做的
        用户携带用户名和密码 访问我 我们校验通过,生成token串,返回给前端
    第二部分:token认证过程 登录认证时使用 其实就是咱们之前讲的认证类 在认证类中完成对token的认证操作
        用户访问我们需要登陆后才能访问的接口,必须携带我们签发的token串(请求头)
        我们取出token 验证该token是否过期,是否被篡改,是否是伪造的
        如果正常,说明荷载中的数据,就是安全的,可以根据荷载中的用户id,查询出当前登录用户,放到request中即可

drf-jwt快速使用

# djagno+drf框架中,使用jwt来做登录认证

# 使用第三方:
	-django-rest-framework-jwt:https://github.com/jpadilla/django-rest-framework-jwt
    -djangorestframework-simplejwt:https://github.com/jazzband/djangorestframework-simplejwt
        
# 我们可以自己封装 :https://gitee.com/liuqingzheng/rbac_manager/tree/master/libs/lqz_jwt

# 安装
	pip3 install djangorestframework-jwt
    
# 补充:
	密码明文一样,每次加密后都不一样,如何做,动态加盐,动态的盐要保存,跟密码保存在一起
    有代码 有数据库 没有登不进去的系统
 
# 解决不了:
	token被获取,模拟发送请求
    不能篡改
    不能伪造
 
# 快速使用
	签发过程(快速签发),必须是auth的user表(人家帮你写好了)
    	登录接口--》基于auth的user表签发的
    认证过程
    	登录认证,认证类(写好了)
       
   
# 总结:
	签发:只需要在路由中配置
        from rest_framework_jwt.views import obtain_jwt_token
        urlpatterns = [
            path('login/', obtain_jwt_token), 
        ]
    认证:视图类上加
    	class BookView(ViewSet):
            authentication_classes = [JSONWebTokenAuthentication] # 认证类,drf-jwt提供的
            permission_classer = [IsAuthenticated]  # 权限类 drf提供的
    访问的时候 要在请求头中携带 必须叫
    	Authorization:jwt token串

drf-jwt定制返回格式

# 登录签发token的接口 要返回code,msg,username,token等信息
参照:jwt源码
	from rest_framework_jwt import settings  # 配置文件
	from rest_framework_jwt.utils import jwt_response_payload_handler # 返回格式

# 对返回格式进行定制
	1 写个函数 函数返回字典格式 返回的格式 会被序列化 前端看到
    	def common_response(token, user=None, request=None):
            return {
                'code':100,
                'msg':'登录成功',
                'token':token,
                'username':user.username
            }
    2 写的函数在配置文件中配置
    	JWT_AUTH = {
    	'JWT_RESPONSE_PAYLOAD_HANDLER':'app01.jwt_response.common_response',
		}

drf-jwt自定义用户表签发

# 1 创建一个用户表
	class User(models.Model):
        username = models.CharField(max_length=32)
        password = models.CharField(max_length=64)
        age = models.IntegerField()
        email = models.CharField(max_length=64)
# 2 登录接口
    jwt_payload_handler = api_settings.JWT_PAYLOAD_HANDLER
    jwt_encode_handler = api_settings.JWT_ENCODE_HANDLER
	class UserView(ViewSet):
        def login(self,request):
            username = request.data.get('username')
            password = request.data.get('password')
            user = User.objects.filter(username=username,password=possword).first()
            if user:
                # 登录成功,签发token-->先背过,
                # 1 通过user 获取payload
                payload = jwt_payload_handler(user)
                print(payload)
                # 2 通过payload 得到token
                token = jwt_encode_handler(payload)
                return Response({'code': 100, 'msg': '登录成功', 'username': user.username, 'token': token})
            else:
                return Response({'code': 101, 'msg': '用户名或密码错误'})
# 3 登录接口签发token返回给前端

drf-jwt自定义认证类

# drf的认证类定义方式,之前学过
# 在认证类中,自己写逻辑
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
import jwt
from rest_framework_jwt.settings import api_settings
from .models import User
jwt_decode_handler = api_settings.JWT_DECODE_HANDLER

# 根据JSONWebTokenAuthentication重写authenticate方法
from rest_framework_jwt.authentication import JSONWebTokenAuthentication

class JWTAuthentication(BaseAuthentication):
    def authenticate(self,request):
        token = request.META.get('HTTP_TOKEN')
        # 背过
        # 校验token是否过期 合法 如果都通过 查询出当前用户 返回
        # 如果不通过 抛异常
        try:
            payload = jwt_decode_handler(token)
            # 如果认证通过 payload就可以认为是安全的 我们就可以使用
            user_id = payload.get('user_id')
            # 每个需要登录后 才能访问的接口 都会走这个认证类 一旦走到这个认证类,就会去数据库查询一次数据
            user = User.objects.get(pk=user_id)
            # 优化后的
            # user = User(username=payload.get('username'),id=user_id)
            # user = {'username':payload.get('username'),'id':user_id}
        except jwt.ExpiredSignature:
            raise AuthenticationFailed('token过期')
        except jwt.DecodeError:
            raise AuthenticationFailed('解码失败')
        except jwt.InvalidTokenError:
            raise AuthenticationFailed('token认证异常')
        except Exception:
            raise AuthenticationFailed('token认证异常')
        return user,token
    
# 局部使用和全局使用

drf-jwt的签发源码分析

# from rest_framework_jwt.views import obtain_jwt_token
# obtain_jwt_token就是ObtainJSONWebToken.as_view()---》视图类.as_view()

# 视图类
class ObtainJSONWebToken(JSONWebTokenAPIView):
    serializer_class = JSONWebTokenSerializer

# 父类:JSONWebTokenAPIView
class JSONWebTokenAPIView(APIView):
    # 局部禁用掉权限和认证
    permission_classes = ()
    authentication_classes = ()
    def post(self, request, *args, **kwargs):
        # serializer=JSONWebTokenSerializer(data=request.data)
        serializer = self.get_serializer(data=request.data)
		# 调用序列化列的is_valid---》字段自己的校验规则,局部钩子和全局钩子
        # 读JSONWebTokenSerializer的局部或全局钩子
        if serializer.is_valid(): # 全局钩子在校验用户,生成token
            # 从序列化类中取出user
            user = serializer.object.get('user') or request.user
            # 从序列化类中取出token
            token = serializer.object.get('token')
            # 咱么定制返回格式的时候,写的就是这个函数
            response_data = jwt_response_payload_handler(token, user, request)
            response = Response(response_data)
            return response
        return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
    
    
# JSONWebTokenSerializer的全局钩子
class JSONWebTokenSerializer(Serializer):
        def validate(self, attrs):
        # attrs前端传入的,校验过后的数据 {username:lqz,password:lqz12345}
        credentials = {
            'username':attrs.get('username'),
            'password': attrs.get('password')
        }
        if all(credentials.values()): # 校验credentials中字典的value值是否都不为空
            # user=authenticate(username=前端传入的,password=前端传入的)
            # auth模块的用户名密码认证函数,可以传入用户名密码,去auth的user表中校验用户是否存在
            # 等同于:User.object.filter(username=username,password=加密后的密码).first()
            user = authenticate(**credentials)
            if user:
                if not user.is_active:
                    msg = _('User account is disabled.')
                    raise serializers.ValidationError(msg)
                payload = jwt_payload_handler(user)
                return {
                    'token': jwt_encode_handler(payload),
                    'user': user
                }
            else:
                msg = _('Unable to log in with provided credentials.')
                raise serializers.ValidationError(msg)
        else:
            msg = _('Must include "{username_field}" and "password".')
            msg = msg.format(username_field=self.username_field)
            raise serializers.ValidationError(msg)

drf-jwt的认证源码分析

# from rest_framework_jwt.authentication import JSONWebTokenAuthentication
# JSONWebTokenAuthentication
class JSONWebTokenAuthentication(BaseJSONWebTokenAuthentication):
    def get_jwt_value(self, request):
        # request-->jwt 'token串'
        auth = get_authorization_header(request).split()
        # 按照空格切割之后-->auth=['jwt','token串']
        auth_header_prefix = api_settings.JWT_AUTH_HEADER_PREFIX.lower()
        if not auth:
            if api_settings.JWT_AUTH_COOKIE:
                return request.COOKIES.get(api_settings.JWT_AUTH_COOKIE)
            return None
        if smart_text(auth[0].lower()) != auth_header_prefix:
            return None
        if len(auth) == 1:
            msg = _('Invalid Authorization header. No credentials provided.')
            raise exceptions.AuthenticationFailed(msg)
        elif len(auth) > 2:
            msg = _('Invalid Authorization header. Credentials string '
                    'should not contain spaces.')
            raise exceptions.AuthenticationFailed(msg)
        return auth[1] # auth取索引1 ---> token串

# 因为我们重写了authenticate
# JSONWebTokenAuthentication中没有要从父类中查找
# 父类中找:BaseJSONWebTokenAuthentication---》authenticate,找到了
    def authenticate(self, request):
        # 调JSONWebTokenAuthentication中的get_jwt_value
        # 拿到前端传入的token串
        jwt_value = self.get_jwt_value(request)
        # 如果前端没传 返回None,request.user中就没有当前登录用户
        # 如果前端没有携带token,也能进入到视图类的方法中执行,控制不住登录用户
        # 所以咱们才加了个权限类,来做控制
        if jwt_value is None:
            return None
        try:
            payload = jwt_decode_handler(jwt_value)
        except jwt.ExpiredSignature:
            msg = _('Signature has expired.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.DecodeError:
            msg = _('Error decoding signature.')
            raise exceptions.AuthenticationFailed(msg)
        except jwt.InvalidTokenError:
            raise exceptions.AuthenticationFailed()
        # 调用authenticate_credentials通过payload会返回当前登录用户
        user = self.authenticate_credentials(payload)
        return (user, jwt_value)
    
# 如果用户不携带token,也能认证通过
# 所以我们必须加个权限类来限制
from rest_framework.permissions import IsAuthenticated # 是否认证通过
class IsAuthenticated(BasePermission):
    def has_permission(self, request, view):
        # 必须有当前登录用户且已经完成认证
        return bool(request.user and request.user.is_authenticated)

到了这里,关于drf——jwt的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • [Daimayuan] 三段式(C++,数组前缀和)

    有一个长度为 n n n 的序列,现在我们想把它切割成三段(每一段都是连续的),使得每一段的元素总和都相同,请问有多少种不同的切割方法 输入描述 第一行给出一个数 n n n ,( 1 ≤ n ≤ 1 0 5 1≤n≤10^5 1 ≤ n ≤ 1 0 5 ) 第二行给出序列 a 1 a_1 a 1 ​ , a 2 a_2 a 2 ​ , a 3 a_3 a 3 ​

    2024年02月05日
    浏览(36)
  • 电力系统电流三段式保护MATLAB仿真模型

    完整资源请查看主页置顶博客(专享优惠) 整体模型如下: Matlab/Simulink搭建的电力系统电流保护模型采用辐射型单电源供电的运行方式 Ⅰ段保护的搭建 Ⅰ段保护为瞬时速断保护,根据Ⅰ段整定原则确定整定值。线路发生短路故障时,短路电流急剧增大;超过设置的整定值时

    2024年02月14日
    浏览(47)
  • Verilog基础:三段式状态机与输出寄存

    相关阅读 Verilog基础 https://blog.csdn.net/weixin_45791458/category_12263729.html         对于Verilog HDL而言,有限状态机(FSM)是一种重要而强大的模块,常见的有限状态机书写方式可以分为一段式,二段式和三段式,笔者强烈建议使用三段式因为这样能使状态机逻辑清晰且易于维护。    

    2024年02月04日
    浏览(43)
  • 三段式电流保护与自动重合闸MATLAB仿真模型

    微 ❤ 关注“电气仔推送”获得资料(专享优惠) 前加速、后加速的区别: 前加速是保护装置不判别是永久性故障还是瞬时故障,直接跳闸,然后经重合闸装置来纠正;后加速是保护装置是先判别故障类型有选择性跳闸 以下只叙述后加速的相关内容,前加速不在赘述!!!

    2024年02月02日
    浏览(37)
  • 【附源码】基于fpga的自动售货机(三段式状态机)

    目录 1、VL38 自动贩售机1 题目介绍 思路分析 代码实现 仿真文件 2、VL39 自动贩售机2 题目介绍: 题目分析 代码实现 仿真文件 3、状态机基本知识         设计一个自动贩售机,输入货币有三种,为0.5/1/2元,饮料价格是1.5元,要求进行找零,找零只会支付0.5元。 ps:   

    2024年02月01日
    浏览(46)
  • Verilog写状态机的三种描述方式之三段式

    状态机的设计思路: 一是从状态机变量入手,分析各个状态的输入、状态转移和输出; 二是先确定电路的输出关系,再回溯规划每个状态的条件、输入等; 状态机的三要素是状态、输入和输出 , 根据状态机状态是否和输入条件相关,可以分为Moore型状态机(与输入无关)和

    2024年02月14日
    浏览(44)
  • 【状态机设计】Moore、Mealy状态机、三段式、二段式、一段式状态机书写规范

    目录 状态机介绍 状态机类型 Moore 型状态机 Mealy 型状态机 状态机设计流程 自动售卖机 状态机设计:3 段式(推荐) 实例 实例 状态机修改:2 段式 实例 状态机修改:1 段式(慎用) 实例 状态机修改:Moore 型 实例 实例   有限状态机(Finite-State Machine,FSM),简称状态机,是

    2024年02月03日
    浏览(51)
  • web学习--登录认证--会话技术--cookie--session--令牌--java-jwt使用--jjwt使用

    前置学习: http springmvc 会话:用户打开浏览器,访问web服务器资源,会话建立,直到有一方断开连接会话结束,一次会话可以多次请求和连接 会话跟踪:一种维护浏览器状态的方式,服务器需要识别多次请求是否来自同一浏览器,以便同一次会话多次请求间共享数据。 cooki

    2024年02月15日
    浏览(67)
  • 【零基础玩转BLDC系列】无刷直流电机无位置传感器三段式启动法详细介绍及代码分享

    无刷直流电动机基本转动原理等内容请参考《基于霍尔传感器的无刷直流电机控制原理》、《基于反电动势过零检测法的无刷直流电机控制原理》与《以GD32F30x为例定时器相关功能详解》,BLDC基本原理及基础知识本篇不再赘述。 直流无刷电机由于定子绕组的反电动势与电机的

    2023年04月08日
    浏览(91)
  • 3-1. SpringBoot项目集成【用户身份认证】实战 【技术选型篇】基于Session、Token、JWT怎么选?

    通过第二章2-2. SpringBoot API开发详解 --SpringMVC注解+封装结果+支持跨域+打包,我们实现了基于SpringBoot项目的 API接口开发 ,并实现 API结果统一封装、支持跨域请求 等等功能,接下来开始第三章,主要做用户身份认证,主要实现一套 统一鉴权的用户身份认证的机制 。 我已经提

    2024年01月22日
    浏览(55)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包