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
# 游标分页,只能下一页,上一页,不能跳到中间,但它的效率最高,大数据量分页,使用这种较好

浙公网安备 33010602011771号