DRF之认证组件
一:认证组件介绍#
(1)认证组件入口#
(1)视图
APIView的dispath(self, request, *args, **kwargs)
(2)任务分发
dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证
(3)认证组件
self.perform_authentication(request)
(4)认证功能介绍
(1)其主要用来对用户进行认证
(2)检验用户 ----> 普通游客 | 合法用户 | 非法用户
(3)游客:代表认证通过 直接进入下一步(权限校验)
(2)合法用户:携带验证信息进行验证 验证通过将用户存储进入request.user中 再次进行下一步校验
(3)非法用户:携带验证信息进行验证 验证失败直接抛出异常 返回403权限问题
(2)源码分析#
(1)第一步APIView/dispatch/initial
def initial(self, request, *args, **kwargs):# Ensure that the incoming request is permitted self.perform_authentication(request) # 认证功能 self.check_permissions(request) # 访问权限功能 self.check_throttles(request) # 频率功能
(2)第二步进入认证功能
def perform_authentication(self, request): request.user # 得到一个方法属性 get方法
PS: 如果是复制属性 应该是request.user = XXX
(3)第三步进入request/user
@property def user(self): if not hasattr(self, '_user'): with wrap_attributeerrors(): self._authenticate() # 没有用户认证处用户 return self._user # 如果有直接返回用户
(4)第四步_authenticate
def _authenticate(self): # self.authenticators:一堆认证类产生序列化认证对象的集合体(列表) for authenticator in self.authenticators: # 循环遍历集合体拿到一个个认证对象 try: ''' authenticator.authenticate:认证对象调用认证功能 user_auth_tuple:拿到登录的用户与用户信息的返回值 调用改方法传入两个参数 self,request self:当前认证类对象 request:当前请求用户 ''' user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: # 抛出异常代表认证失败 self._not_authenticated() raise if user_auth_tuple is not None: self._authenticator = authenticator # 如果有返回值 将登录用户 与 验证信息 保存在 request.user ,request.author self.user, self.auth = user_auth_tuple return # 如果返回值为空 代表认证通过 但是没有登录用户 与验证信息 表示当前用户为游客用户 self._not_authenticated()
(5)自定义认证组件#
(1)全局settings文件配置
REST_FRAMEWORK = { # 认证类配置 'DEFAULT_AUTHENTICATION_CLASSES': [ 'api.authentications.MyAuthentication', # 自定义认证组件 ], }
(2)全局settings默认配置
# 认证类配置 'DEFAULT_AUTHENTICATION_CLASSES': [ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication', ],
(3)自定义文件配置api/Authentication
from rest_framework.exceptions import AuthenticationFailed from rest_framework.authentication import BaseAuthentication from . import models class MyAuthentication(BaseAuthentication): def authenticate(self, request): ''' 前台在请求头携带认证信息, 且默认规范用 Authorization 字段携带认证信息, 后台固定在请求对象的META字段中 HTTP_AUTHORIZATION 获取 ''' auth = request.META.get('HTTP_AUTHORIZATION',None) # 可以不携带认证信息 if auth is None: # 如果为空则表明游客 return None # 没有登录用户 与 返回信息 auth_list = auth.split() # 设置认证小规则(两段式) # 判断用户是否合法 if not (len(auth_list) == 2 and auth_list[0].lower() == 'auth'): raise AuthenticationFailed('认证信息有误 非法用户') # 非法的请求 直接抛出异常 # 解析合法的用户 if not auth_list[1] == 'qwe.asd.zxc': # 假设通过解析'qwe.asd.zxc' 可以解析处合法用户 raise AuthenticationFailed('用户校验失败 非法用户') user_obj = models.User.objects.filter(username='admin').first() if not user_obj: raise AuthenticationFailed('用户数据有误 非法用户') return (user_obj,None) # 合法将用户返回 验证信息不返回
(4)视图层
from rest_framework.views import APIView from rest_framework.response import Response class TestAPIView(APIView): def get(self,request,*args,**kwargs): ''' 测试一:前段不输入校验信息 获取用户属于匿名用户 测试二:前段加入验证信息 获取用户属于解析用户 admin ''' print(request.user) return Response( { 'status':0, 'msg':'测试成功' } )
二:权限组件介绍#
(1)权限组件入口#
(1)视图
APIView的dispath(self, request, *args, **kwargs)
(2)任务分发
dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证
(3)权限组件
self.check_permissions(request)
(2)源码分析#
(1)源码分析
def check_permissions(self, request): ''' get_permissions:产生权限对象的类 参数: self:产生权限的类的对象 request:用户请求 self:views实例化产生对象 ''' for permission in self.get_permissions(): # 循环遍历 ''' has_permission:返回值布尔值 ''' if not permission.has_permission(request, self): # 判断布尔值 如果为真则获取所有权限 反之则为假 self.permission_denied( request, message=getattr(permission, 'message', None) ) # PS:默认登录用户 与游客有全部权限
(2)系统权限类#
(1)AllowAny:游客与登录用户都含有权限
class AllowAny(BasePermission): def has_permission(self, request, view): return True
(2)IsAuthenticated:登录用户且验证通过的用户
class IsAuthenticated(BasePermission): def has_permission(self, request, view): return bool(request.user and request.user.is_authenticated)
(3)IsAdminUser:登录用户 且必须是后台管理员
class IsAdminUser(BasePermission): def has_permission(self, request, view): return bool(request.user and request.user.is_staff)
(4)IsAuthenticatedOrReadOnly:只读请求 或者合法用户
(1)游客:只读
(2)登录用户:含有全部权限
class IsAuthenticatedOrReadOnly(BasePermission): def has_permission(self, request, view): return bool( request.method in SAFE_METHODS or request.user and request.user.is_authenticated )
(3)代码示例#
(1)全局settings
REST_FRAMEWORK = { # 权限类配置 'DEFAULT_PERMISSION_CLASSES': [ 'rest_framework.permissions.AllowAny', ], }
(2)视图层
from rest_framework.permissions import IsAuthenticated # 只有登录用户才有权限 class TestAuthenticatedAPIView(APIView): permission_classes = [IsAuthenticated] # 使用 IsAuthenticated 不使用全局AllowAny def get(self, request, *args, **kwargs): return Response( { 'status': 0, 'msg': "登录且合法用户可以访问" } ) # 游客只读,登录无限制 from rest_framework.permissions import IsAuthenticatedOrReadOnly class TestAuthenticatedOrReadOnlyAPIView(APIView): permission_classes = [IsAuthenticatedOrReadOnly] def get(self, request, *args, **kwargs): return Response({ 'status': 0, 'msg': '游客只读 登录用户无限制' }) def post(self, request, *args, **kwargs): return Response({ 'status': 0, 'msg': '游客只读 登录用户无限制' })
(4)自定义权限#
(1)api/permissions
from django.contrib.auth.models import Group from rest_framework.permissions import BasePermission from rest_framework.exceptions import AuthenticationFailed class MyPermission(BasePermission): def has_permission(self, request, view): print(self) # <api.permissions.MyPermission object at 0x0000000005673C50> 当前权限对象 print(request) # <api.permissions.MyPermission object at 0x0000000005673C50> 请求对象 print(view) # <api.views.TestAdminOrReadOnlyAPIView object at 0x0000000005673518> view对象 # 只读接口 read_only = request.method in ('GET', 'HEAD', 'OPTIONS') # group为有权限的分组 group = Group.objects.filter(name='管理员').first() # groups为当前用户所属的所有分组 groups = request.user.groups.all() data1 = group and groups # group groups 必须有值 data2 = group in groups # 有权限分组 必须在所有分组中 # 读接口大家都有权限,写接口必须为指定分组下的登陆用户 return read_only or (data1 and data2)
(2)视图层
from .permissions import MyPermission class TestAdminOrReadOnlyAPIView(APIView): permission_classes = [MyPermission] def get(self, request, *args, **kwargs): return Response( { 'status':0, 'msg':"游客可以读取数据 但是不能写数据" } ) def post(self, request, *args, **kwargs): return Response( { "status":0, 'msg':'管理员可以读写' } )
三:频率组件#
(1)权限组件入口#
(1)视图
APIView的dispath(self, request, *args, **kwargs)
(2)任务分发
dispath方法内 self.initial(request, *args, **kwargs) 进入三大认证
(3)权限组件
self.check_throttles(request) # 频率组件
(2)核心源码分析#
for throttle in self.get_throttles(): if not throttle.allow_request(request, self): # 只要频率限制了,allow_request 返回False了,才会调用wait throttle_durations.append(throttle.wait()) if throttle_durations: # Filter out `None` values which may happen in case of config / rate # changes, see #1438 durations = [ duration for duration in throttle_durations if duration is not None ] duration = max(durations, default=None) self.throttled(request, duration)
PS:
(1)遍历配置的频率认证类,初始化得到一个个频率认证类对象(会调用频率认证类的 __init__() 方法)
(2)频率认证类对象调用 allow_request 方法,判断是否限次(没有限次可访问,限次不可访问)
(3)频率认证类对象在限次后,调用 wait 方法,获取还需等待多长时间可以进行下一次访问
注:频率认证类都是继承 SimpleRateThrottle 类
(3)自定义频率类#
(1)全局settings文件配置
# 频率限制条件配置 'DEFAULT_THROTTLE_RATES': { 'send_msg': '1/min' },
(2)api/
from rest_framework.throttling import SimpleRateThrottle class SendMsgRateThrottle(SimpleRateThrottle): scope = 'send_msg' # 自定义一个字符串 def get_cache_key(self, request, view): phone = request.query_params.get('phone') # 获取前段get拼接值 if not phone: # 如果 没有值 说明无任何访问限制 return None # 按照源码格式来 固定返回None # 按照源码格式 此处以手机号作为身份标识 return 'throttle_%(scope)s_%(ident)s' % {'scope': self.scope, 'ident': phone}
(3)路由层
url(r'^send_msg/$', views.TestThrottles.as_view()),
(4)视图层
from .throttles import SendMsgRateThrottle # 导入自定义的频率类 class TestThrottles(APIView): throttle_classes = [SendMsgRateThrottle] # 局部配置 def get(self, request, *args, **kwargs): return Response({ 'status': 0, 'msg': '访问频率get方式测试成功' }) def post(self, request, *args, **kwargs): return Response({ 'status': 0, 'msg': '访问频率post方式测试成功' })
PS:
(1)对api/send_msg/?phone = xxx 有限制
# 例如 http://127.0.0.1:8000/api/send_msg/?phone=1234654646
(2)对 /api/send_msg/ 或其他接口发送无限制
(3)对数据包提交phone的/api/phone/接口无限制
(4)对不是phone(如mobile)字段提交的电话接口无限制
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· AI与.NET技术实操系列:基于图像分类模型对图像进行分类
· go语言实现终端里的倒计时
· 如何编写易于单元测试的代码
· 10年+ .NET Coder 心语,封装的思维:从隐藏、稳定开始理解其本质意义
· .NET Core 中如何实现缓存的预热?
· 25岁的心里话
· 闲置电脑爆改个人服务器(超详细) #公网映射 #Vmware虚拟网络编辑器
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 零经验选手,Compose 一天开发一款小游戏!
· 一起来玩mcp_server_sqlite,让AI帮你做增删改查!!