这篇教程drf-router和authenticate认证源码分析写得很实用,希望能帮到您。 一、路由Routers在 Rest Framework 中提供了两个 router , 可以帮助我们快速的实现路由的自动生成。 必须是继承 ModelViewSet 的视图类才能自动生成路由 SimpleRouter使用方法: urls.py # 第一步:导入routers模块from rest_framework import routers# 第二步:实例化得到对象router = routers.SimpleRouter() # 第三步:注册( register('前缀', viewset视图集, 路由的别名) )router.register('books', views.BooksViewset)# 第四步:生成路由加入到原路由中# 方式一:urlpatterns = [ ...]urlpatterns += router.urls# 方式二:urlpatterns = [ ... url(r'^', include(router.urls))]# 形成路由如下<URLPattern '^books/$' [name='books-list']><URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']> DefaultRouterDefaultRouter与SimpleRouter的区别是,DefaultRouter会多附带一个默认的API根视图,返回一个包含所有列表视图的超链接响应数据。 # 前两条和SimpleRouter一样<URLPattern '^books/$' [name='books-list']><URLPattern '^books/(?P<pk>[^/.]+)/$' [name='books-detail']># 效果也和前两条类似,# 如:http://127.0.0.1:8000/books.json<URLPattern '^books/.(?P<format>[a-z0-9]+)/?$' [name='books-list']># http://127.0.0.1:8000/books/1.json<URLPattern '^books/(?P<pk>[^/.]+)/.(?P<format>[a-z0-9]+)/?$' [name='books-detail']># 多了个根路由http://127.0.0.1:8000/<URLPattern '^$' [name='api-root']>, <URLPattern '^/.(?P<format>[a-z0-9]+)/?$' [name='api-root']> action的使用action是为了给继承自 ModelViewSet 的视图类中自定义的函数也添加路由 例如下面这样: from rest_framework.viewsets import ModelViewSetfrom rest_framework.response import Responsefrom app01.ser import BooksSerializersfrom app01.models import Booksclass BooksViewSet(ModelViewSet): queryset = Books.objects.all() serializer_class = BooksSerializers # 这种方法不会自动生成,需要用action配置 def get_num(self, request, pk): book = self.get_queryset()[:int(pk)] ser = self.get_serializer(book, many=True) return Response(ser.data) 使用示例: action是一个装饰器,放在被装饰的函数上方, method:请求方式 detail:是否带pk ——>True 表示路径格式是xxx/<pk>/action方法名/ ——False 表示路径格式是xxx/action方法名/ from rest_framework.viewsets import ModelViewSetfrom rest_framework.response import Responsefrom rest_framework.decorators import actionfrom app01.ser import BooksSerializersfrom app01.models import Booksclass BooksViewSet(ModelViewSet): queryset = Books.objects.all() serializer_class = BooksSerializers @action(methods=['GET', 'POST'], detail=True) def get_num(self, request, pk): book = self.get_queryset()[:int(pk)] # 获取前几条数据 ser = self.get_serializer(book, many=True) return Response(ser.data) # 生成路由如下http://127.0.0.1:8000/books/2/get_num/<URLPattern '^books/(?P<pk>[^/.]+)/get_num/$' [name='books-get-num']> 二、认证认证的写法 - 写一个认证类,继承 BaseAuthentication,重写 authenticate, 认证的逻辑写在里面,认证通过,返回两个值,一个值给Request对象的user, 认证失败,抛异常:APIException或者AuthenticationFailed
- 将认证类添加到需要认证视图类的
authentication_classes = [认证类1] 中 - 全局使用,还是局部使用
# 全局使用,在setting.py中配置REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":["app01.app_auth.MyAuthentication",]}# 局部使用,在视图类上写authentication_classes=[MyAuthentication]# 局部禁用authentication_classes=[] 认证源码分析1、APIView重写as_view方法使之没有csrf认证——>但还是正常执行 dispatch 方法,但是 dispatch方法被 APIView重写了——>dispatch 中执行了 self.initial 认证方法——>有认证,权限,频率 2、现在只是看认证源码self.perform_authentication(request) 3、但是self.perform_authentication(request) 就一句话:request.user ,那么就需要去 drf 的 Request 对象中找 user 属性(方法) @propertydef user(self): # 先去判断当前对象中有没有'_user'这个属性,一开始肯定是没有的,因为用户是没有登录的 if not hasattr(self, '_user'): with wrap_attributeerrors(): # 没有用户,认证出用户 self._authenticate() # 有用户,直接返回用户 return self._user 4、Request 类中的 user 方法,刚开始来,没有_user ,走 self._authenticate() 5、核心,就是Request类中的 _authenticate(self) def _authenticate(self): # 遍历拿到一个认证器,进行认证 # self.authenticators 配置的一堆认证类产生的认证类对象组成的 list # self.authenticators 就是在视图类中配置的:authentication_classes = [认证类1,认证类2] 的一个个认证类的对象: ————>self.authenticators ==》 [认证类1对象,认证类2对象] for authenticator in self.authenticators: try: # 认证器调用认证方法authenticate(认证类对象self,request对象) """ def authenticate(self, request): return (self.force_user, self.force_token) """ # 返回值:登录的用户与认证的信息组成的 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() 认证组件的使用1、写一个认证类,继承 BaseAuthentication,重写 authenticate # app01_auth.pyfrom rest_framework.authentication import BaseAuthenticationfrom rest_framework.exceptions import AuthenticationFailedfrom app01.models import UserTokenclass TokenAuthentication(BaseAuthentication): def authenticate(self, request): # 认证逻辑,如果认证通过,返回两个值 # 如果认证失败,抛出AuthenticationFailed异常 token = request.data.get('token') if token: user_token = UserToken.objects.filter(token=token).first() # 认证通过 if user_token: return UserToken.user, token else: raise AuthenticationFailed('认证失败') else: raise AuthenticationFailed('请求地址中需要带token') 2、将认证类添加到需要认证视图类的authentication_classes = [认证类1] 中 # views.pyfrom rest_framework.viewsets import ModelViewSetfrom rest_framework.views import APIViewfrom rest_framework.response import Responsefrom app01.models import Books, UserInfo, UserTokenfrom app01.ser import BooksSerializerfrom app01.app01_auth import TokenAuthenticationimport uuid# 查看Books需要经过认证才能查看class BooksView(ModelViewSet): authentication_classes = [TokenAuthentication] queryset = Books.objects.all() serializer_class = BooksSerializer# 登录视图,登录后获得token,后续用token认证class LoginView(APIView): def post(self, request): response_msg = {'status': 200, 'msg': ''} username = request.data.get('username') password = request.data.get('password') user_obj = UserInfo.objects.filter(username=username, password=password).first() if user_obj: # 登录成功生成一个随机字符串 token = uuid.uuid4() # 存到UserToken表中,update_or_create有就更新,没有就新增 UserToken.objects.update_or_create(defaults={'token': token}, user=user_obj) response_msg['msg'] = '登录成功' response_msg['token'] = token else: response_msg['msg'] = '账户或密码错误' response_msg['status'] = 204 return Response(response_msg) 到此这篇关于drf-router和authenticate认证源码分析的文章就介绍到这了,更多相关drf-router和authenticate内容请搜索51zixue.net以前的文章或继续浏览下面的相关文章希望大家以后多多支持51zixue.net! Python序列的推导式实现代码 Python 实时获取任务请求对应的Nginx日志的方法 |