关于身份认证,这边只给出相关的操作,但是不细说,原因就是这些实际上需要搭配着实例进行理解,这边只介绍操作,以及稍微介绍一下相关的区别。
可以使用该 DEFAULT_AUTHENTICATION_CLASSES 设置全局设置默认身份验证方案(一般采用这一种)。例如:
REST_FRAMEWORK = {
'DEFAULT_AUTHENTICATION_CLASSES': [
'rest_framework.authentication.BasicAuthentication',
'rest_framework.authentication.SessionAuthentication',
······这边加入你的登录的方案··················
]
}
还可以使用基于类的 APIView 视图,基于每个视图或每个视图集设置身份验证方案。
from rest_framework.authentication import SessionAuthentication, BasicAuthentication
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
authentication_classes = [SessionAuthentication, BasicAuthentication]
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'user': str(request.user), # `django.contrib.auth.User` instance.
'auth': str(request.auth), # None
}
return Response(content)
可能产生下面两种禁止状态
HTTP 401 Unauthorized
HTTP 403 Permission Denied
最基础的登录,只有登录按钮,登录也仅仅只能在本次使用,当我们换页面或者关闭浏览器再打开,登录状态就消失了。
这个一般也不会去使用,只是做一个基类进行继承,这边就不进行介绍此种登录的操作了。
如果身份验证成功, BasicAuthentication 则提供以下凭据:
Session登录,这边值得关注的就是这是采用传递cookie进行登录,传递一个session-id作为登录的标识,并存储到数据库当中,作为登录凭证,时间限制在2周。
如果身份验证成功, SessionAuthentication 则提供以下凭据:
如果您将 AJAX 样式的 API 与 SessionAuthentication 一起使用,则需要确保为任何“不安全”的 HTTP 方法调用(如 PUT 、 PATCH POST 或 DELETE 请求)包含有效的 CSRF 令牌
此身份验证方案允许您将身份验证委托给 Web 服务器,该服务器设置环境 REMOTE_USER 变量。
要使用它,您的 AUTHENTICATION_BACKENDS 设置中必须包含 django.contrib.auth.backends.RemoteUserBackend (或子类)。默认情况下, RemoteUserBackend 为尚不存在的用户名创建 User 对象。
如果身份验证成功, RemoteUserAuthentication 则提供以下凭据:
这个token诞生的原因实际上是为了解决session登录的不足,我们在具体具体的使用环境中,session只能满足存储在一个服务器当中,但是真实的情况往往一个网站部署之下对应着不止一个服务器,有多个服务器,也就是当我们第一次访问这个页面登录了,这台服务器传递过来一个session-id,但是你下一次点击,你访问同一个网站,但是网络给你分配到另一个服务器下的这个网页,那你的session不在这个服务器下存储,这就产生了问题,token就直接从数学的产生字符串的角度解决了这个问题,高并发的情况下。
若要使用该 TokenAuthentication 方案,需要将身份验证类配置为包括 TokenAuthentication ,并在 INSTALLED_APPS 设置中另外包含 rest_framework.authtoken :
INSTALLED_APPS = [
...
'rest_framework.authtoken'
]
确保在更改设置后运行 manage.py migrate ,该应用程序rest_framework.authtoken 会将 Django 数据库迁移。
您还需要为用户创建令牌:
from rest_framework.authtoken.models import Token
token = Token.objects.create(user=...)
print(token.key)
对于要进行身份验证的客户端,令牌密钥应包含在 Authorization HTTP 标头中。键应以字符串文本“Token”为前缀,两个字符串之间用空格分隔。例如:
Authorization: Token 9944b09199c62bcf9418ad846dd0e4bbdfc6ee4b
如果要在标头中使用其他关键字,例如 Bearer ,只需子类并设置 keyword 类 TokenAuthentication 变量即可。
如果身份验证成功, TokenAuthentication 则提供以下凭据:
request.user 将是一个 Django User 实例。
request.auth 将是一个 rest_framework.authtoken.models.Token 实例。
被拒绝权限的未经身份验证的响应将导致具有相应 WWW 身份验证标头的 HTTP 401 Unauthorized 响应。例如:
WWW-Authenticate: Token
可以使用该 DEFAULT_PERMISSION_CLASSES 设置全局设置默认权限策略。例如:
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.IsAuthenticated',
]
}
如果未指定,此设置默认为允许无限制访问:
'DEFAULT_PERMISSION_CLASSES': [
'rest_framework.permissions.AllowAny',
]
局部权限一般分为两种:
第一:
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = [IsAuthenticated]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
第二种:
from rest_framework.decorators import api_view, permission_classes
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
@api_view(['GET'])
@permission_classes([IsAuthenticated])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
AllowAny 权限类将允许不受限制的访问,无论请求是经过身份验证还是未经身份验证
IsAuthenticated已经登录的,只有登录的用户才能进行后面的操作
IsAdminUser 管理员用户才允许后面的操作
IsAuthenticatedOrReadOnly 登录的或者只读,讲人话就是只有登录用户才能post put delete 不登陆的用户仅能进行查看
新建一个Permissions.py,在里面写权限类
若要实现自定义权限,请重写 BasePermission 并实现以下方法之一或两者:
下面是一个权限类示例,该权限类根据阻止列表检查传入请求的 IP 地址,并在 IP 被阻止时拒绝请求:
from rest_framework import permissions
class BlocklistPermission(permissions.BasePermission):
"""
Global permission check for blocked IPs.
"""
def has_permission(self, request, view):
ip_addr = request.META['REMOTE_ADDR']
blocked = Blocklist.objects.filter(ip_addr=ip_addr).exists()
return not blocked
缓存实际上作用在二次查询的时候,首次查询甚至会比原本的查询还慢(因为需要写操作,写入缓存),drf当中的默认缓存是用一个简单的字典进行存储的,(模拟redius),我们这边,对于知识的介绍,所以就采用业内常用的redius进行介绍。
他们之间的关系大概按照上图,从图中我们可以明显看出Redius的缓存具有滞后性,也就是在数据更新后,redius当中的数据并没有随之更新,所以对于这个非关系型数据库当中的数据,需要我们手动删除。
Django 提供了一个 method_decorator 使用带有基于类的视图的装饰器。这可以与其他缓存修饰器一起使用,例如 cache_page 和 vary_on_cookie vary_on_headers 。
from django.utils.decorators import method_decorator
from django.views.decorators.cache import cache_page
from django.views.decorators.vary import vary_on_cookie,vary_on_headers
from rest_framework.response import Response
from rest_framework.views import APIView
from rest_framework import viewsets
class UserViewSet(viewsets.ViewSet):
# With cookie: cache requested url for each user for 2 hours
@method_decorator(cache_page(60*60*2))
@method_decorator(vary_on_cookie)
def list(self, request, format=None):
content = {
'user_feed': request.user.get_user_feed()
}
return Response(content)
class ProfileView(APIView):
# With auth: cache requested url for each user for 2 hours
@method_decorator(cache_page(60*60*2)) # 2小时缓存时间
@method_decorator(vary_on_headers("Authorization",))
def get(self, request, format=None):
content = {
'user_feed': request.user.get_user_feed()
}
return Response(content)
class PostView(APIView):
# Cache page for the requested url
@method_decorator(cache_page(60*60*2))
def get(self, request, format=None):
content = {
'title': 'Post title',
'body': 'Post content'
}
return Response(content)
限流的作用首先就是防止爬虫,以及一些暴力访问,维护网站的稳定性,在drf当中的限流首先坐的事情就是类似pessmission的事情一样,或者说就是另类的认证。
这种一般用的少,一般都是个性化设置,不过这边也列出来
可以使用 DEFAULT_THROTTLE_CLASSES 和DEFAULT_THROTTLE_RATES 设置全局设置默认限制策略。
例如:(在setting当中进行设置)
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.AnonRateThrottle',
'rest_framework.throttling.UserRateThrottle'
],
'DEFAULT_THROTTLE_RATES': {
'anon': '1/sec',
'user': '1000/day'
}
}
简要介绍一下上面的那些术语:
术语 | 说明 |
---|---|
AnonRateThrottle | 未登录用户的限制,一般和‘anon’联合使用,来进行限制 |
UserRateThrottle | 登录用户的限制,一般和‘user’进行联合使用,来进行限制 |
anon | 对应的就是AnonRateThrottle |
user | 对应的就是UserRateThrottle |
day | 时间单位,相同的时间还有sec hou min 取的都是英语单词的前三个字母 |
还是分为两种,一种是类视图 ,一种式api/函数视图
第一种类视图:这个式关于登录用户的限流,然后限流的具体参数在setting当中进行书写
'DEFAULT_THROTTLE_RATES': {
'user': '1000/day'
}
from rest_framework.response import Response
from rest_framework.throttling import UserRateThrottle
from rest_framework.views import APIView
class ExampleView(APIView):
throttle_classes = [UserRateThrottle]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
第二种函数视图:
@api_view(['GET'])
@throttle_classes([UserRateThrottle])
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
或者:
@action(detail=True, methods=["post"], throttle_classes=[UserRateThrottle])
def example_adhoc_method(request, pk=None):
content = {
'status': 'request was permitted'
}
return Response(content)
一般默认使用 WSGI 环境中变量的值 REMOTE_ADDR的这个属性进行识别用户,也就是drf当中的request.Meta.REMOTE_ADDR这个属性也就是访问网站的ip地址进行限制。
当设置了X-Forwarded-For的话,就是采用这个方法进行检测,但是这个一般好像有点问题,(笔者暂时不知道),这个是通过转发前的ip进行检测。
上文你会发现,即使是局部的限制,我们仍然没办法做到一个页面设置这个页面一分钟最多访问2次,下一个页面一分钟访问3次这样子的效果,这时候就需要用上自定义的访问了
操作也有两种,推荐方式二,操作少,OwO:
首先先新建一个Throttle.py,内部专门写这个限流类
然后写上:aaa是随便的名字,一般和你要限制的相关
class BurstRateThrottle(UserRateThrottle):
scope = 'aaa'
全局设置就先跳过了,感觉不是很适合,直接开始介绍局部限制
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_RATES': {
'aaa': '60/min',
}
}
然后到对应的视图当中写上:
class ExampleView(APIView):
throttle_classes = [BurstRateThrottle]
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
当然还是局部设置
先到setting当中加上’rest_framework.throttling.ScopedRateThrottle’,这个就是用于此处的,然后就可以在后面的设置当中加上自定义的label和对应的时间设置。
REST_FRAMEWORK = {
'DEFAULT_THROTTLE_CLASSES': [
'rest_framework.throttling.ScopedRateThrottle',
],
'DEFAULT_THROTTLE_RATES': {
'bbb': '1000/day',
}
}
然后我们在调用具体的view视图的时候:
class ContactListView(APIView):
throttle_scope = 'bbb'
就可以直接得到了。
首先先检查有没有django-filter这个包,有了才能进行后续的操作,没有就安装一下。
首先的操作就是,到setting当中添加上
REST_FRAMEWORK = {
'DEFAULT_FILTER_BACKENDS': ['django_filters.rest_framework.DjangoFilterBackend']
}
以及应用上添加上‘django_filter’
然后就是在view当中导入:
from rest_framework import filters
要在视图类中添加(同时注意要把django_filters在settings中配置)
filter_backends = [DjangoFilterBackend,filters.SearchFilter,filters.OrderingFilter]
filterset_fields = '__all__'
search_fields = ['order','title','album__album_name'] #外键加入两个下划线
ordering_fields = '__all__'
然后根据自己的实际去尽心修改即可
我们之前就已经使用过了,这边就介绍一点不一样的。
首先就是我们之前使用的
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.PageNumberPagination',
'PAGE_SIZE': 2,
}
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'rest_framework.pagination.LimitOffsetPagination',
'PAGE_SIZE': 2,
}
就把上面的那个注释掉,转到view函数当中
pagination_class = LimitOffsetPagination
就把需要分页的框起来就可以
自定义的分页格式,先创建一个新的PaginationClass.py
在这个文件中写入你想要的参数
class StandardResultsSetPagination(PageNumberPagination):
page_size = 2
page_size_query_param = 'page_size' # 这个主要用于前端传递的可指定参数,后面进行演示
max_page_size = 1000
然后想要调用成局部的:
class BillingRecordsView(generics.ListAPIView):
queryset = Billing.objects.all()
serializer_class = BillingRecordsSerializer
pagination_class = StandardResultsSetPagination
想要调用成全局的:
REST_FRAMEWORK = {
'DEFAULT_PAGINATION_CLASS': 'apps.core.pagination.StandardResultsSetPagination'
}
以及可以修改的属性:
若要设置这些属性,应重写 PageNumberPagination 该类,然后启用自定义分页类,如上所示。
但是我们可以改变url来改变一页多少数量