drf路由与认证
1、路由
drf中可以通过继承视图基类ModelViewSet的路由写法,可以自动生成路由,从而优化继承视图类ViewSetMixin的路由
drf中不同路由的使用:
1.1、urls.py中的基础路由
url('book/',views.Bookview.as_view())
url('book/(?P<pk>\d+)',views.Bookdataview.as_view())
1.2、继承ViewSetMixin视图类后的路由
url('book'/,views.Bookview.as_view(action={'get':'list','post':'create'})),
url('book/',views.Bookdataview.as_view(action={'get':'retrieve','put':'update','delete':'destroy'}))
1.3、继承ModelViewSet视图类,优化之后的实现自动路由
#1.导入routers模块
from rest_framework.viewsets routers
#2.实例化得到对象,二选一,DefaultRouter生成的路由比较多,不推荐使用
route=router.DefaultRouter()
route=router.SimpleRouter()
#3.设置路由的url路径,以及路径触发视图层的对象
router.register('books',view.Bookviewset)
#4.将自动生成的url加入到原路由中
urlpatterns+=router.urls
2、action的使用
action是将已经继承了ModelViewSet视图类的自定义函数也添加到路由中,
将装饰器放置在被装饰函数的上方,methods:请求方式,detail:是否带pk
class Bookviewset(ModelViewSet):
queryset = Book.object.all()
serializer_class = BookSerializer #继承ModelVIESet,里面封装了各种的请求方式,通过url进行关联,内置了框架,需要设置数据库中的数据,以及设置序列化器
@action(methods=['GET','POST'],detail=True)#第一个为请求方式,可以在列表内放置多个,第二个为是否需要<pk>值
def get_1(self,request,pk): #访问时路径为url('book/(?P<pk>[^/.]+)/get_1$'),即必须要提交pk以及get_1
book=self.get_queryset()[:2] #自定义,取前两个值
ser = self.get_serializer(book,many=True)
return Response(ser.data)
3、认证
3.1、认证的写法
先写一个类,继承BaseAuthentication,类里面重写函数authenticate,认证的逻辑写在里面,
认证成功,返回两个值,其中给一个值赋给Request的对象user,
认证失败,则抛出异常:APIEception或者AuthenticationFailed
3.2、认证源码分析
#1 APIVIew----》dispatch方法---》self.initial(request, *args, **kwargs)---->有认证,权限,频率
#2 只读认证源码: self.perform_authentication(request)
#3 self.perform_authentication(request)就一句话:request.user,需要去drf的Request对象中找user属性(方法)
#4 Request类中的user方法,刚开始来,没有_user,走 self._authenticate()
#5 核心,就是Request类的 _authenticate(self):
def _authenticate(self):
# 遍历拿到一个个认证器,进行认证
# self.authenticators配置的一堆认证类产生的认证类对象组成的 list
#self.authenticators 你在视图类中配置的一个个的认证类:authentication_classes=[认证类1,认证类2],对象的列表
for authenticator in self.authenticators:
try:
# 认证器(对象)调用认证方法authenticate(认证类对象self, request请求对象)
# 返回值:登陆的用户与认证的信息组成的 tuple
# 该方法被try包裹,代表该方法会抛异常,抛异常就代表认证失败
user_auth_tuple = authenticator.authenticate(self) #注意这self是request对象
except exceptions.APIException:
self._not_authenticated()
raise
# 返回值的处理
if user_auth_tuple is not None:
self._authenticator = authenticator
# 如何有返回值,就将 登陆用户 与 登陆认证 分别保存到 request.user、request.auth
self.user, self.auth = user_auth_tuple
return
# 如果返回值user_auth_tuple为空,代表认证通过,但是没有 登陆用户 与 登陆认证信息,代表游客
self._not_authenticated()
3.3、认证组件的使用
先新建一个文件:app_auth.py,里面建立一个认证类,继承BaseAuthentication,
建立函数authenticate,认证就是确定token是否存在,在视图层views中建立了登录函数 ,里面有产生一个随机的token,从前端取到token的值判断它是否存在,再判断它是否存在数据库内,如果存在的话返回给用户信息,以及token,用来放行该用户
from rest_framework.authentication import BaseAuthentication
from rest_framework.exceptions import AuthenticationFailed
from app01.models import UserToken
class MyAuthentication(BaseAuthentication):
def authenticate(self,request):
token=request.GET.get('token')
if token:
user_token = UserToken.objects.filter(token=token).first()
if user_token:
return user_token.user,token
else:
raise AuthenticationFailed('认证失败')
else:
raise AuthenticationFailed('请求地址中需要携带token')
4、认证功能全局和局部的使用
4.1、全局使用
在setting中配置
REST_FRAMEWORK={
"DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]
}
4.2、局部使用
在视图类中写
authentication_classes=[MyAuthentication]
4.3、局部禁用
在视图类前添加空,优先查找自身的属性
authentication_classes=[]