DRF 07 三大认证

认证组件

 认证:判断访问的用户是谁?
      1.默认全局认证方式: session认证和基本认证
      2.修改全局认证方式
      3.修改指定视图认证方式
  • 我们在访问有些接口,会发现有的接口,是需要登录之后才能访问的,没有登录的话就不能访问。

接下来我们就一个接口,返回token,一致只要带着token,就是登录过的,如果没有的话就是没有登录。

  • 需求条件:
    • 查询所有不需要登录就能访问
    • 查询单个,需要登录才能访问

认证组件使用步骤

1.写一个认证类,继承类BaseAuthentication
2.重写authenticate方法,在该方法中实现登录认证;token在哪带着的?如果认证它是登录了
3.如果认证成功,返回两个值【返回None或者两个值】
4.认证不通过,就直接抛出异常AuthenticationFailed
5.可以局部使用和全局使用
	局部: 只在某个视图类中使用(当视图类管理的所偶遇接口)
    class BookDetailView(ViewSetMixin, RetrieveAPIView):
            authentication_classes = [LoginAuth] 
     全局:全局所有接口都生效(登录的接口不用)
    REST_FRAMEWORK = {
    	'DEFAULT_AUTHENTICATION_CLASSES':['app01.authenticate.LoginAuth']
	}
    局部禁用:只要在需要的视图类中设置=[]
    class BookDetailView(ViewSetMixin, RetrieveAPIView):
            authentication_classes = [] 	

代码:

# 视图类
## 查询所有
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    
# 查询单个
class BookDetailView(ViewSetMixin, RetrieveAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    authentication_classes = [LoginAuth] 
ps:这里中括号中写的是自己写的认证类

#### 认证类代码
class LoginAuth(BaseAuthentication):
    def authenticate(self, request):
        # 在这里实现认证,如果过是登录的,继续往后走,返回两个值,如果不是就直接抛出异常
        # 请求中是否携带token,判断是否登录,token的数据放在在地址栏中
        token= request.queryset_params.get('token',None)
        if token:
            # 这里是前端传入的token,去表里查,如果存在,就是登录了,返回两个值[固定的:当前登录用户,token]
            user_token=UserToken.object.filter(token=token).first()
           if user_token:
                return user_token.user, token
            else:
                # 没有登录抛异常
                raise AuthenticationFailed('token认证失败')
        else:
            raise AuthenticationFailed('token没传')
            
# 路由
router = SimpleRouter()
router.register('books', views.BookView, 'books')
router.register('books', views.BookDetailView, 'books')

urlpatterns = [
    path('api/v1/', include(router.urls)),
]

小提示: 不要在配置文件中乱导入任何不使用的东西,否则就会出现报错

权限组件

权限:判断访问的用户是否能够访问某个API接口?
	 默认全局权限控制:AlloAny
     修改全局权限控制
     修改指定视图权限控制

自定义权限控制类

如需自定义权限,需要继承rest_framework.permissions.BasePermission父类,并实现以下两个任何一个方法或全部

  • .has_permission(self, request, view)

    是否可以访问视图,view表示当前视图对象

  • .has_object_permission(self, request, view, obj)

    是否可以访问数据对象,view表示当前视图,obj数据对象

	当我们登录成功了,有的接口,还是不能访问,因为没有权限
# 登录成功之后,有的接口是有权限访问,有的接口是没有权限访问

代码实现:
	需求:
    查询单个和查询所有都是登录才能访问  --全局认证
    --查询单个需要超级管理员才能访问
    --查询所有,所有登录用户都能访问
#设置一个权限字段,在User表中,加入user_type字段

权限的使用

1.写一个权限类,继承BasePermission
2.重写has_permission方法,在该方法中实现权限认证,在这个方法中,request.user就是当前登录用户
3.如果有权限,就会返回True
4.如果没有权限就返回False ,定制返回的信息:
	self.message='.....'
5.局部使用和全局使用
	-局部:只在某个时候图类中使用【当前视图类管理的所有接口】
     class BookDetailView(ViewSetMixin, RetrieveAPIView):
    		permission_classes = [CommonPermission]
    - 全局:: 所有的接口都生效(在配置文件)
    REST_FRAMEWORK = {
            'DEFAULT_PERMISSION_CLASSES': [
                'app01.permissions.CommonPermission',
            ],}
    - 局部禁用:
    class BookDetailView(ViewSetMixin, RetrieveAPIView):
            permission_classes = []

频率组件

限流:控制用户访问API接口的频率次数
	DRF 框架默认是没有进行限流设置的。
    进行权限限流设置:
    	1.针对匿名用户和认证用户分别进行限流
        2.针对匿名用户和认证用户统一进行限流

使用步骤:

1.写一个频率类,继承SimpleRateThrottle
2.重写get_cache_key方法,返回什么,就以什么做限制,比如 IP ,用户id做限制
3.配置一个类属性:scope='book_5_m'
		'book_5_m' 是评率的范围参数
4.在配置文件中配置
'DEFAULT_THROTTLE_RATES': {
        'book_5_m': '5/m',
    },
5.局部使用和全局使用
	- 局部:只要某个视图类中使用【当前的视图类管理的所有接口】
    class BookDetailView(ViewSetMixin, RetrieveAPIView):
    		throttle_classes = [CommonThrottle]
   - 全局: 全局所有的接口都生效
		 REST_FRAMEWORK = {
             'DEFAULT_THROTTLE_CLASSES': ['app01.throttling.CommonThrottle'],

        }
    
    -局部禁用:
    	 class BookDetailView(ViewSetMixin, RetrieveAPIView):
            throttle_classes = [] 

过滤排序

# 在restful 规范中,要求请求地址中带着过滤条件
	- 5个接口中,只要一个接口需要有过滤和排序,查询所有的接口
    
# 比如查询所有图书的接口,查询以 将  开头的图书

总共有三个过滤类:
	内置的,自定义的,第三方的

内置过滤类的使用

  首先我们需要继承 GenerICAPIView
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    # SearChFilter内置的,固定用法,模糊匹配
    # 就有过滤功能了,指定按哪个字段过滤
    filter_backends = [SearchFilter]
     # search_fields = ['name']  # 可以按名字模糊匹配
    search_fields = ['name','price']  # 可以按名字模糊匹配或价格模糊匹配
    
 # 可以使用的搜索方式
	http://127.0.0.1:8000/api/v1/books/?search=将  # name或price中只要有红就会搜出来

使用第三方django-filter实现过滤

# 安装:django-filter
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = []
    authentication_classes = []
    throttle_classes = []
    filter_backends = [DjangoFilterBackend]
    filterset_fields = ['name','price']  # 支持完整匹配  name=聊斋11&price=93
    
# 支持的查询方式
http://127.0.0.1:8000/api/v1/books/?price=939  (精确查询)
http://127.0.0.1:8000/api/v1/books/?price=939&name=红楼梦

自定义过滤实现过滤

# 需求: 查询价格大于100的所有图书
http://127.0.0.1:8000/api/v1/books/?price_gt=100

# 第一步:定义过滤类,继承BaseFilterBackend,然后重写filter_queryset方法
class CommonFilter(BaseFilterBackend):
    def filter_queryset(self, request, queryset, view):
        # 在这里面实现过滤,返回queryset对象,就是过滤后的数据
        price_gt = request.query_params.get('price_gt', None)
        if price_gt:
            qs = queryset.filter(price__gt=int(price_gt))
            return qs

        else:
            return queryset
      
 # 第二步:配置在视图类上
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer

    filter_backends = [CommonFilter]  # 可以定制多个,从左往右,依次执行        

排序的使用

# 直接使用内置的方法
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    filter_backends = [OrderingFilter]  
    ordering_fields = ['price']

# 支持查询的方式:
	http://127.0.0.1:8000/api/v1/books/?ordering=-price
   http://127.0.0.1:8000/api/v1/books/?ordering=-id,price

分页

# 分页,只有查询所有接口才会有分页
# drf 内置中有三个分页器,对应了三种分页方式
# 内置的分页类不能直接使用,需要继承,定制一些参数后才能使用

PageNumberPagination

前端访问网址形式:

GET  http://api.example.org/books/?page=4

可以在子类中定义的属性:

  • page_size 每页数目
  • page_query_param 前端发送的页数关键字名,默认是'page'
  • page_size_query_param 前端发送的每页数目关键字名,默认为None
  • max_page_size 前端最多能够够设置的每页数量

LimitOffsetPagination

前端访问形式:

GET http://api.example.org/books/?limit=100&offset=400

可以在子类中定义的属性:

  • default_limit 默认限制,默认值与PAGE_SIZE设置一直
  • limit_query_param limit参数名,默认’limit’
  • offset_query_param offset参数名,默认’offset’
  • max_limit 最大limit限制,默认None
  • PS:如果先要在视图类中关闭分页功能,只要在视图内置设置
    • pagination_class = None

自定义分页类

可以通过自定义Pagination类,来为视图添加不同分页行为。在视图中通过pagination_clas属性来指明。

class StandardResultPagination(PageNumberPagination):
    page_size = 3
    page_size_query_param = 'page_size'
    max_page_size = 5
class BookListView(ListAPIView):
    queryset = BookInfo.objects.all()
    serializer_class = BookInfoSerializer
    # 指定当前视图所使用的分页类
    pagination_class = StandardResultPagination

通过 http://api.example.org/books/?page=<页码>&page_size=<页容量> 进行访问。

代码

# PageNumberPaginat
class CommonPageNumberPagination(PageNumberPagination):
    page_size = 2  # 每页显示2条
    page_query_param = 'page'  # page=10  查询第10页的数据,每页显示2条
    page_size_query_param = 'size'  # page=10&size=5    查询第10页,每页显示5条
    max_page_size = 5  # 每页最大显示10条


# LimitOffset
class CommonLimitOffsetPagination(LimitOffsetPagination):
    default_limit = 3  # 每页显示2条
    limit_query_param = 'limit'  # limit=3   取3条
    offset_query_param = 'offset'  # offset=1  从第一个位置开始,取limit条
    max_limit = 5
    # offset=3&limit=2      0  1 2 3 4 5


# 在 app 用下面

class CommonCursorPagination(CursorPagination):
    cursor_query_param = 'cursor'  # 查询参数
    page_size = 2  # 每页多少条
    ordering = 'id'  # 排序字段
# 配置在视图类上即可
class BookView(ViewSetMixin, ListAPIView):
    queryset = Book.objects.all()
    serializer_class = BookSerializer
    permission_classes = []
    authentication_classes = []
    throttle_classes = []
    # 之前的东西一样用 ,内置的分页类不能直接使用,需要继承,定制一些参数后才能使用
    # pagination_class = PageNumberPagination
    #基本分页方式(基本是这种,网页端):http://127.0.0.1:8000/api/v1/books/?page=2&size=3

    # pagination_class = LimitOffsetPagination
    # 偏移分页 http://127.0.0.1:8000/api/v1/books/?limit=4&offset=1
    # 从第一条开始,取4条

    pagination_class = CommonCursorPagination
    # 游标分页,只能下一页,上一页,不能跳到中间,但它的效率最高,大数据量分页,使用这种较好
posted @ 2023-02-07 16:32  亓官扶苏  阅读(98)  评论(0)    收藏  举报