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=[]
posted @ 2020-07-09 22:46  疏星淡月  阅读(194)  评论(0编辑  收藏  举报