drf-jwt第三方插件,DRF的三大认证的具体使用,多方式登陆的实现

1|0一、 JWT认证的使用

1|11. 第三方drf-jwt插件

  • 借助第三方的drf-jwt插件,进行jwt认证,完成token的签发和校验和刷新(需要先手动下载,命令是:pip install djangorestframework-jwt

  • drf-jwt插件其实就是一个小的应用,包含了settings,views,utils,serializers,models等文件。

  • 有关token的配置参数就在插件的settings文件中,我们也可以在自己项目的settings文件中配置后,然后覆盖掉插件中的默认配置,达到自定义token配置的目的。

    • 项目的settings文件中,当然还可以配置token的其他参数, **********一定要在配置REST_FRAMEWORK之前配置JWT_AUTH********** # drf-jwt自定义配置 import datetime JWT_AUTH = { # 过期时间 'JWT_EXPIRATION_DELTA': datetime.timedelta(seconds=300), # 是否允许刷新 'JWT_ALLOW_REFRESH': False, # 最大刷新的过期时间 'JWT_REFRESH_EXPIRATION_DELTA': datetime.timedelta(days=7), }
  • 注意:在token的签发中,有两个方法很重要

*****jwt_payload_handler和jwt_encode_handler方法***** from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler # 1. 用user对象包装成payload载荷 payload = jwt_payload_handler(user) # 2. 利用payload载荷签发token(jwt认证的头部在系统内部已写死,不需要我们参与编写了) token = jwt_encode_handler(payload)

1|22. 利用第三方插件的views完成token操作

1. 应用的urls文件中: from django.conf.urls import url, include from .router import router # eg: router.register('users', UserModelViewSet, basename='user') from rest_framework_jwt.views import ObtainJSONWebToken, obtain_jwt_token, refresh_jwt_token, verify_jwt_token urlpatterns = [ # ObtainJSONWebToken.as_view()等价于obtain_jwt_token # url(r'^login/$', ObtainJSONWebToken.as_view()), url(r'^login/$', obtain_jwt_token), # 登录接口(签发token) url(r'^refresh/$', refresh_jwt_token), # 刷新token接口 url(r'^verify/$', verify_jwt_token), # 校验token接口 url(r'', include(router.urls)) ]

2|0二、DRF的三大认证的使用

  • 三大认证组件:认证组件、权限组件、频率组件

    • 认证组件:身份认证(游客/合法用户/非法用户)
    • 权限组件:针对游客和合法用户对某一视图函数的访问权限
    • 频率组件:限制某一视图函数在一定时间内被访问的次数
  • 三大组件是按流水线式轮流进行,即:先进行认证——》再权限校验——》最后是频率校验

  • 借助第三方的drf-jwt插件,进行jwt认证,完成token的签发和校验和刷新(需要先手动下载,命令是:pip install djangorestframework-jwt

    • drf-jwt插件: 提供了 签发token、校验token、刷新token的三个视图类 认证组件中(校验jwt token,得到登录用户user对象,存储到request.user中)
  • 在视图类的自身逻辑之前书写需要的三大认证功能(注意是之前),即在视图类的下面的第一行书写三大认证。

3|0三、认证组件的使用

3|11. 认证组件的用法和注意点

  • 实际开发中对DRF自带的认证功能需求大,且一般在全局中配置认证组件。

  • 自定义的认证功能在实际开发中需求较少,但也可能会出现。

  • 注意:登录接口不用参与任何认证与权限的校验

  • 在认证功能中,认证类返回值有以下3中情况

    • 1. 没有token或者前台提交的token格式错误 返回 None 表示游客 2. 有正常的token token校验不通过,则抛出AuthenticationFailed异常,代表非法用户 3. 有正常的token token校验通过,返回 (user,token) ,表示合法用户(user是用户对象)

3|22. 认证组件使用步骤

1|0(1)使用DRF自带的认证功能(非登陆功能中)

  • 使用步骤:
1. 在settings文件中配置drf框架的认证组件 REST_FRAMEWORK = { # 异常模块:异常处理函数 'EXCEPTION_HANDLER': 'api.exception.exception_handler', # 配置全局认证组件 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework_jwt.authentication.JSONWebTokenAuthentication' ], # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置 'DEFAULT_THROTTLE_RATES': { 'user': '5/min', 'anon': '3/min', 'mobile': '1/min' }, } 2. 书写视图类的正常逻辑代码

1|0(2)使用自定义的认证类(非登录功能中)

  • 使用步骤:
# 这里自定义的认证类是在局部配置的,但一般是在settings文夹中进行全局配置 1. 在应用文件夹下新建文夹,书写自定义的认证类 如: 新建 authentications.py文夹,内部定义继承了BaseAuthentication类的MyAuthentication类 2. 在视图类的正常逻辑代码之前进行认证类的配置 from . import authentications authentication_classes = [authentications.MyAuthentication] 3. 书写视图类的正常逻辑代码

1|0(3)自定义认证类实例

''' 自定义认证类 1) 如果使用session认证,drf默认提供了SessionAuthentication 2) 如果使用drf-jwt认证框架,drf-jwt框架提供了JSONWebTokenAuthentication 3) 如果是自定义签发与校验token,才需要将校验token的算法封装到自定义的认证类中 ''' from rest_framework.authentication import BaseAuthentication from rest_framework_jwt.authentication import JSONWebTokenAuthentication class MyAuthentication(BaseAuthentication): def authenticate(self, request): """ 1) 从请求头中拿到前台提交的token(一般从HTTP_AUTHORIZATION中拿,也可以与前台约定) -- 如果设置了反爬等措施,校验一下反爬(头 token) 2)没有token,返回None,代表游客 3)有token,进入校验 -- 不通过:抛AuthenticationFailed异常,代表非法用户 -- 通过:返回 (user, token),代表合法用户 """ pass

4|0四、权限组件的使用

4|11. 权限组件的用法和注意点

  • 权限校验一般进行局部配置,因为不同的用户对视图类的权限差别很大,所以要分别配置(当然也可以同时进行全局配置和局部配置)

  • 在实际开发中,DRF自带的权限组件功能和自定义权限类两者都会有需求

  • 注意:登录接口不用参与任何认证与权限的校验

  • 权限类的返回值有两种情况

    • 1. 返回 True # 条件通过,即有权限 2. 返回 False # 条件不通过,即没有权限

4|22. 权限组件使用步骤

1|0(1)使用DRF自带的权限功能(非登录功能中)

  • 使用步骤
1. 视图类中进行局部配置DRF自带的权限组件 from rest_framework.permissions import IsAuthenticated, IsAdminUser, AllowAny, IsAuthenticatedOrReadOnly permission_classes = [IsAuthenticated] permission_classes = [IsAdminUser] 2. 书写视图类的正常逻辑代码

1|0(2)使用自定义的权限类

1. 在应用文件夹下新建一个文件,来自定义权限类 如:新建permissions.py文件,内部定义继承了BasePermission类的MyPermission类 2. 视图类中进行局部配置自定义的权限组件 from . import permissions permission_classes = [permissions.MyPermission] 3. 书写视图类的正常逻辑代码

1|0(3)自定义权限类实例

""" 自定义权限类 1) drf默认提供了一些权限类 AllowAny:游客和登录用户有全权限 IsAuthenticated:只有登录用户有全权限 IsAdminUser:只有后台用户(admin用户)有全权限 IsAuthenticatedOrReadOnly:游客有读权限,登录用户有全权限 2)如果有特殊需要,需要自定义权限类 如:只有superuser有权限、只有vip用户有权限、只有某ip网段用户有权限、只有某个视图及其子类有权限 """ from rest_framework.permissions import BasePermission class MyPermission(BasePermission): def has_permission(self, request, view): """ 1) 根据需求,request和view的辅助,制定权限规则判断条件 2)如果条件通过,返回True 3)如果条件不通过,返回False """ print(request.user, request.auth) return False # VIP用户权限 class VIPUserPermission(BasePermission): def has_permission(self, request, view): for group in request.user.groups.all(): if group.name.lower() == 'vip': return True return False

5|0五、频率组件的使用

5|11. 频率组件的用法和注意点

  • DRF自带的频率组件只有频率限制的条件,需要我们自己实现限制功能。

  • 频率组件都需要我们自定义频率类,因此需求很大

  • 频率校验一般做局部配置,但是频率校验的限制条件在settings中配置

  • 频率类的返回值有两种

    • 1. 返回 None # 表示不限制 2. 返回与限制条件有关的字符串,表示限制(注意此处的返回值的写法)

5|22. 频率组件使用步骤

  • 直接就是使用自定义的频率类
1. 在应用文件夹下新建一个文件,来自定义频率类 如:新建一个throttles.py文件,其内部定义一个继承了SimpleRateThrottle类的MobileRateThrottle类 2. 在settings文件中配置频率限制条件 # drf框架自定义配置 REST_FRAMEWORK = { # 频率组件:频率类一般做局部配置,但是频率调节在settings中配置 'DEFAULT_THROTTLE_RATES': { 'user': '5/min', 'anon': '3/min', 'mobile': '1/min' }, } 3. 在视图类中进行局部配置频率校验 from . import throttles throttle_classes = [throttles.MobileRateThrottle] 4. 书写视图类的正常逻辑代码

1|0(1)自定义频率类实例

""" 自定义频率类 1) drf默认提供了一些频率类 AnonRateThrottle:只对游客进行频率限制 UserRateThrottle:对所有用户进行频率限制 2)如果有特殊需要,需要自定义频率类 如:对ip进行限次、对电话进行限制、对视图某些信息进行限次 """ from rest_framework.throttling import SimpleRateThrottle class MobileRateThrottle(SimpleRateThrottle): """ 1)设置scope字符串类属性,同时在settings中进行drf配置DEFAULT_THROTTLE_RATES eg: DEFAULT_THROTTLE_RATES = {'mobile': '1/min'} 2)重写get_catch_key方法: 返回与限制条件有关的字符串,表示限制 返回None,表示不限制 """ scope = 'mobile' def get_cache_key(self, request, view): if not request.user.is_authenticated or not request.user.mobile: return None # 匿名用户 或 没有电话号的用户 都不限制 # 只要有电话号的用户才进行限制 return self.cache_format % { 'scope': self.scope, 'ident': request.user.mobile }

6|0六、多方式登陆的实现

  • 实现用户名、邮箱、电话号码三种方式的登陆
  • 同时实现登陆功能的jwt认证的 token的签发

6|11. 登陆功能中的注意点

  1. token只能由登陆接口签发
  2. 登陆接口也是APIView的子类,使用就一定会进行认证、权限的校验,但是实际上,登陆接口不能参与任何认证和权限的校验,所以要进行认证和权限校验的局部禁用。
  3. 登陆所需的数据和登陆校验以及token的签发都是通过序列化类完成的。
  4. 注意:因为登陆是需要用户提交数据的,所以走得是post请求。但是当走post请求时,系统会默认当前要进行的是增功能。因此,我们在序列化类中,要把系统字段改为同名的自定义反序列化字段。
  • 在进行token的签发时,需要用到drf-jwt插件来完成

6|22. 多方式登陆的实现代码

1. 应用的urls文件中: from django.conf.urls import url, include from . import views from .router import router router.register('users', views.UserListViewSet, basename='user') # basename就是别名 urlpatterns = [ # 自定义签发token的登录login接口 url(r'^login/$', views.LoginAPIView.as_view()), url(r'', include(router.urls)) ] 2. 自定义的序列化文件中: # 登陆视图类对应的序列化类 # 导入drf-jwt插件,利用其中的两个方法完成token的签发 from rest_framework_jwt.serializers import jwt_payload_handler, jwt_encode_handler import re class LoginModelSerializer(serializers.ModelSerializer): # post请求,序列化默认当做create动作进行校验,需要校验数据库,执行create动作,username会抛用户已存在异常 # 抛用户已存在异常是多余的,所以自定义系统校验规则即可,即自定义反序列化的同名字段即可 username = serializers.CharField(min_length=3, max_length=16) password = serializers.CharField(min_length=3, max_length=16) class Meta: model = models.User fields = ('username', 'password') # 用全局钩子,完成token的签发 def validate(self, attrs): # 1)通过 username 和 password 完成多方式登录校验,得到user对象 user = self._validate_user(attrs) # 自定义方法得到user对象 # 2)用user对象包装成payload载荷 payload = jwt_payload_handler(user) # 3)利用payload载荷签发token(jwt认证的头部在系统内部已写死,不需要我们参与编写了) token = jwt_encode_handler(payload) # 4)将user与token存储到serializer对象中,方便在视图类中使用 self.content = { 'user': user, 'token': token } return attrs # 利用正则,匹配出不同格式的username,再分别进行校验 def _validate_user(self, attrs): username = attrs.get('username') password = attrs.get('password') if re.match(r'.*@.*', username): # 邮箱 user = models.User.objects.filter(email=username).first() # type: models.User elif re.match(r'^1[3-9][0-9]{9}$', username): # 电话 user = models.User.objects.filter(mobile=username).first() else: # 用户名 user = models.User.objects.filter(username=username).first() if not user or not user.check_password(password): raise serializers.ValidationError({'message': '用户信息异常'}) return user

__EOF__

本文作者BigSun丶
本文链接https://www.cnblogs.com/Mcoming/p/12142204.html
关于博主:评论和私信会在第一时间回复。或者直接私信我。
版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
声援博主:如果您觉得文章对您有帮助,可以点击文章右下角推荐一下。您的鼓励是博主的最大动力!
posted @   BigSun丶  阅读(475)  评论(0编辑  收藏  举报
编辑推荐:
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
阅读排行:
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!
点击右上角即可分享
微信分享提示