6-1 认证和权限-DRF认证
目录:
- 认证介绍
- 初始化操作(模型、视图、urls)
- 初识BasicAuthentication(客户端用户名密码认证)
一、DRF认证
现在我们写的接口,会发现一个问题,就是任何人都可以创建数据库,修改数据。这样肯定是不行的,我们希望只有数据的创建者才能有权限修改数据,如果不是,只能有只读权限。这个好比什么呐?好比我们有一个购物车的话,去访问,我们就要去登录的情况下去访问。
其实在Django rest famework 已经默认帮我做认证了。我们可以去 看下源码:我们按 Ctrl + 类名:
generics.ListCreateAPIView => GenericAPIView => views.APIView => APIView(View)
来我们看下 APIView 的源码:
class APIView(View):
....
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES #权限认证
....
我们进入 Ctrl + api_settings 继续进去看:
api_settings = APISettings(None, DEFAULTS, IMPORT_STRINGS) #原来在这边,意思就是说 有配置权限的话就去读自己配置的,没有的话就读DEFAULTS
好啦!那我们进去看看 Ctrl + DEFAULTS 继续看看,默认的权限是啥?
EFAULTS = {
# Base API policies
.....,
'DEFAULT_AUTHENTICATION_CLASSES': (
'rest_framework.authentication.SessionAuthentication', #session验证
'rest_framework.authentication.BasicAuthentication' #客户端 用户名密码验证
),
....
}
好啦。终于明白啦。它的默认验证是 SessionAuthentication 和 BasicAuthentication。
二、初始化操作
2.1、创建app
python manage.py startapp app04
2.2、模型
说明:编辑modles.py文件
from django.db import models
class Game(models.Model):
name = models.CharField(verbose_name="游戏名", max_length=64)
desc = models.CharField(verbose_name="描述", max_length=20)
user = models.ForeignKey('auth.User', on_delete=models.CASCADE) #继承django自带的用户
def __str__(self):
return self.name
2.3、序列化
说明:新建并且编辑 serializers.py 文件
from rest_framework import serializers
from .models import Game
class GameSerializer(serializers.ModelSerializer):
class Meta:
model = Game
fields = "__all__"
# extra_kwargs = {
# "user": {"read_only": True} #当我们开启验证的时候需要打开,因为默认是 当前用户。所以只需 出参显示,入参无需传入
# }
2.4、路由
说明:编辑根级路由和当前路由
#根级路由
from django.contrib import admin
from django.urls import path, include
urlpatterns = [
path('admin/', admin.site.urls),
path('api/', include('app04.urls'))
]
#当前app04路由
from django.urls import path
from app04 import views
urlpatterns = [
path("game/", views.GameList.as_view(), name="game-list"),
path("game/<int:pk>/", views.GameDetail.as_view(), name="game-detail")
]
2.5、 初始化数据库
#初始化数据库 >python manage.py makemigrations >python manage.py migrate #新建用户 >python manage.py createsuperuser
2.6、视图
说明:编辑Views.py视图文件
from .serializers import GameSerializer
from .models import Game
from rest_framework import generics
class GameList(generics.ListCreateAPIView): #ListCreateAPIView=>GenericAPIView => views.APIView => APIView(View)
queryset = Game.objects.all()
serializer_class = GameSerializer
class GameDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = Game.objects.all()
serializer_class = GameSerializer
三、初识BasicAuthentication(客户端用户名密码认证)
3.1、 BasicAuthentication验证
说明:因为我们创建用户的时候,需要 获取当前的用户,不需要自己输入,所以就是在我们创建保存数据库的时候需要重写对应的方法。那这个函数在哪里呐。我们找一下。
Ctrl + ListCreateAPIView => CreateModelMixin
class CreateModelMixin(object): """ Create a model instance. """ def create(self, request, *args, **kwargs): serializer = self.get_serializer(data=request.data) serializer.is_valid(raise_exception=True) self.perform_create(serializer) headers = self.get_success_headers(serializer.data) return Response(serializer.data, status=status.HTTP_201_CREATED, headers=headers) def perform_create(self, serializer): serializer.save() def get_success_headers(self, data): try: return {'Location': str(data[api_settings.URL_FIELD_NAME])} except (TypeError, KeyError): return {}
能看出来,我们在保存序列化数据的时候是 通过 perform_create 方法保存数据。所以我们只需要重写这个方法就可以了。
所以我们编辑 views.py中的GameList类。如下:
from .serializers import GameSerializer
from .models import Game
from rest_framework import generics
from rest_framework.authentication import BasicAuthentication #导入BasicAuthentication认证,是用于客户端用户名密码认证
class GameList(generics.ListCreateAPIView):
queryset = Game.objects.all()
serializer_class = GameSerializer
def perform_create(self, serializer): #重写perform_create方法,传入当前用户
#print(self.request.user) #验证查看是否是当前用户
serializer.save(user=self.request.user) #request是APIview封装好的,这个request.user是BasicAuthentication认证赋值的
查看一下 self.request的源码,看看Apiview到底是怎么封装的:Ctrl 按键 + request:
class APIView(View):
....
def dispatch(self, request, *args, **kwargs):
....
#对django的request的进行封装,在 initialize_request 做了用户认证,然后把 BasicAuthentication 传进去了,可以 Crtrl + initialize_request进去看
request = self.initialize_request(request, *args, **kwargs)
#封装后的 request 赋值给 APIView
self.request = request
....
好啦,request知道是哪里来的了,那我们再看看 BasicAuthentication 到底返回给我们什么?看下 BasicAuthentication的源码:
class BasicAuthentication(BaseAuthentication): """ HTTP Basic authentication against username/password. """ www_authenticate_realm = 'api' def authenticate(self, request): """ Returns a `User` if a correct username and password have been supplied using HTTP Basic authentication. Otherwise returns `None`. """ auth = get_authorization_header(request).split() if not auth or auth[0].lower() != b'basic': return None if len(auth) == 1: msg = _('Invalid basic header. No credentials provided.') raise exceptions.AuthenticationFailed(msg) elif len(auth) > 2: msg = _('Invalid basic header. Credentials string should not contain spaces.') raise exceptions.AuthenticationFailed(msg) try: auth_parts = base64.b64decode(auth[1]).decode(HTTP_HEADER_ENCODING).partition(':') except (TypeError, UnicodeDecodeError, binascii.Error): msg = _('Invalid basic header. Credentials not correctly base64 encoded.') raise exceptions.AuthenticationFailed(msg) userid, password = auth_parts[0], auth_parts[2] return self.authenticate_credentials(userid, password, request) def authenticate_credentials(self, userid, password, request=None): """ Authenticate the userid and password against username and password with optional request for context. """ credentials = { get_user_model().USERNAME_FIELD: userid, 'password': password } user = authenticate(request=request, **credentials) if user is None: raise exceptions.AuthenticationFailed(_('Invalid username/password.')) if not user.is_active: raise exceptions.AuthenticationFailed(_('User inactive or deleted.')) return (user, None) #返回出来了user=>user给了request,none给了token def authenticate_header(self, request): return 'Basic realm="%s"' % self.www_authenticate_realm
对了,这边别忘记了 serializers.py 序列化文件也要开放一下:
from rest_framework import serializers
from .models import Game
class GameSerializer(serializers.ModelSerializer):
class Meta:
model = Game
fields = "__all__"
extra_kwargs = {
"user": {"read_only": True} #由于用户是出参显示,入参只需要当前用户,所以这边设置只读
}
好啦。这边我们事先 准备了一个用户 :zhangqg,密码:123456,通过 createsuperuser命令创建。
postman测试步骤:
1、入参:

2、 Basic Auth 用户名密码验证

3.2、认证总结
- DRF默认认证是 SessionAuthentication、BasicAuthentication
- 目前采用BasicAuthentication、通过浏览器传递账号密码,base64加密,认证成功后,返回一个元组。元组的第一个用户对象,赋值给request
- 我们重写perform_create 就可以从request 拿到User
- 在序列化话里面取当前用户 => HiddenField ,serializer.CurrentUserDefault(源码显示还是一个当前request)

浙公网安备 33010602011771号