1、django请求周期
用户通过浏览器请求一个页面;
请求到达Request Middlewares中间件,中间件对request做一些预处理或者直接response请求;
URLConf通过urls.py文件和请求的URL找到相应的View;
View Middlewares被访问,它同样可以对request做一些处理或者直接返回response;
如果是FBV,直接调用View中的函数,如果是CBV,通过dispatch反射,执行对应method方法;
View中的方法可以选择性的通过Models访问底层的数据;
所有的Model-to-DB的交互都是通过manager完成的;
将数据通过HTTPResponse或者render发送到Response Middlewares中间件;
Response Middlewares中间件对View返回的response做一定处理;
返回到浏览器,呈现给用户;
2、认证
-
问题1:有些api需要用户登录成功后才能访问;有些无需登录就能访问。
-
基本使用认证组件
解决:
- 创建两张表(用户表,用户对应的token表)
- 用户登录(返回token并保存到数据库)
-
认证流程原理
如图所示:
APIView类:
1、先调用父类APIView中dispatch()方法;
2、调用initialize_request()方法对request进行封装,封装后request为Request实例对象;
3、调用initial(),去认证;
4、调用perform_authentication()去实现认证;
Request类:
6、调用Request类中的user()方法;
7、调用_authenticate()方法,获取认证对象,进行一步步认证
8、在_authenticate()方法中循环所有认证对象,认证对象为authentication_classes = [],列表中的元素为一个个需要认证的实例化对象,在APIView中authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES,如果需要修改可在自己写的类中重写该类属性。
9、执行认证类的authenticate方法,三种情况:
-
如果authenticate()方法抛出异常,self._not_authenticated()执行
-
如果有返回值,必须是元组:(request.user, request.auth)
-
如果返回None,表示我不管,下一个认证来处理
10、最后回到自定义的类中,执行相应的get或者post方法。
-
-
全局配置
1、全局使用的认证类,在setting.py文件配置
REST_FRAMEWORK = { # 全局使用的认证类 'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.FirstAuthtication', 'api.utils.auth.Authtication'], }
局部使用认证类,在需要认证的类中加入类属性:authentication_classes
authentication_classes = [FirstAuthtication, Authtication, ]
2、设置未认证成功后request.user与request.auth的值,在setting.py文件中设置
REST_FRAMEWORK = { # 设置未认证成功后request.user与request.auth的值 # 'UNAUTHENTICATED_USER': lambda: '匿名用户', # request.user=匿名用户 'UNAUTHENTICATED_USER': None, # request.user=None 'UNAUTHENTICATED_TOKEN': None # request.auth=None }
-
内置认证类
1、认证类必须继承:BaseAuthentication,from rest_framework.authentication import BaseAuthentication
2、其他认证类:BasicAuthentication,浏览器对用户名和密码进行base64加密,加密后放在请求头发送给服务端
3、SessionAuthentication、TokenAuthentication、RemoteUserAuthentication都是基于django实现的。
-
内容梳理
1、使用
-
创建类,继承BaseAuthentication;实现authenticate()方法
-
返回值:
None,下一个认证来执行;
抛异常,raise exceptions.AuthenticationFailed(‘用户认证失败’),from rest_framework import exceptions;
返回元组(元素1,元素2),元素1赋值给request.user,元素2赋值给request.auth;
-
全局使用
在配置文件里设置
REST_FRAMEWORK = { # 全局使用的认证类,列表中是类的路径 'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.FirstAuthtication', 'api.utils.auth.Authtication'], # 'DEFAULT_AUTHENTICATION_CLASSES': ['api.utils.auth.FirstAuthtication'], # 设置未认证成功后request.user与request.auth的值 # 'UNAUTHENTICATED_USER': lambda: '匿名用户', # request.user=匿名用户 'UNAUTHENTICATED_USER': None, # request.user=None 'UNAUTHENTICATED_TOKEN': None # request.auth=None }
-
局部使用
在视图类中写个静态字段authentication_classes,列表中的元素是类的名称
from rest_framework import exceptions from rest_framework.authentication import BaseAuthentication class Authtication(BaseAuthentication): def authenticate(self, request): token = request._request.GET.get('token') token_obj = models.UserToken.objects.filter(token=token).first() if not token_obj: raise exceptions.AuthenticationFailed('用户认证失败') # 在rest framework内部会将两个字段赋值给request,以供后续操作使用 # token_obj.user赋值给request.user,token_obj赋值给request.auth return (token_obj.user, token_obj) def authenticate_header(self, val): pass class OrderView(APIView): ''' 订单相关业务 ''' authentication_classes = [Authtication, ] def get(self, request, *args, **kwargs): ret = { 'code': 1000, 'msg': None, 'data': None } try: ret['data'] = ORDER_DIC except Exception as e: ret['code'] = 1002 ret['msg'] = '请求异常' return JsonResponse(ret)
-
-
源码流程:
-
dispatch
-
封装request
获取定义的认证类(全局/局部),通过列表生成时创建对象。
-
initial
perform_authentication
request.user(内部循环认证对象…)
-
-