认证
用于必须登录后才能访问否个视图。
简单使用:
url.py
from django.conf.urls import url,include
from django.contrib import admin
from . import views
urlpatterns = [
url(r'^login/$', views.LoginView.as_view()),
url(r'^order/$', views.OrderView.as_view()),
url(r'^user/$', views.UserView.as_view()),
]
views.py
import uuid
from django.shortcuts import render
from django.views import View
from django.views.decorators.csrf import csrf_exempt
from django.utils.decorators import method_decorator
from rest_framework.versioning import URLPathVersioning
from rest_framework.views import APIView
from rest_framework.response import Response
from . import models
class LoginView(APIView):
def post(self,request,*args,**kwargs):
user_object = models.UserInfo.objects.filter(**request.data).first()
if not user_object:
return Response('登录失败')
random_string = str(uuid.uuid4()) # 产生随机字符串
user_object.token = random_string # 保存在数据库
user_object.save()
return Response(random_string)
class MyAuthentication:
def authenticate(self, request):
# 重写这个方法
"""
Authenticate the request and return a two-tuple of (user, token).
"""
token = request.query_params.get('token')
# 获取请求携带的token,然后获取用户对象
user_object = models.UserInfo.objects.filter(token=token).first()
if user_object:
return (user_object,token)
return (None,None)
class OrderView(APIView):
authentication_classes = [MyAuthentication, ]
# 需要登录认证的视图,设置类列表
def get(self,request,*args,**kwargs):
print(request.user) # 获取用户对象
print(request.auth) # 获取token
return Response('order')
class UserView(APIView):
authentication_classes = [MyAuthentication,]
def get(self,request,*args,**kwargs):
print(request.user)
print(request.auth)
return Response('user')
源码:
class APIView(View):
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
def dispatch(self, request, *args, **kwargs):
"""
`.dispatch()` is pretty much the same as Django's regular dispatch,
but with extra hooks for startup, finalize, and exception handling.
"""
# ###################### 第一步 ###########################
"""
request,是django的request,它的内部有:request.GET/request.POST/request.method
args,kwargs是在路由中匹配到的参数,如:
url(r'^order/(d+)/(?P<version>w+)/$', views.OrderView.as_view()),
http://www.xxx.com/order/1/v2/
"""
self.args = args
self.kwargs = kwargs
"""
request = 生成了一个新的request对象,此对象的内部封装了一些值。
request = Request(request)
- 内部封装了 _request = 老的request
- 内部封装了 authenticators = [MyAuthentication(), ] 对象类列表
"""
request = self.initialize_request(request, *args, **kwargs)
self.request = request
def initialize_request(self, request, *args, **kwargs):
"""
Returns the initial request object.
"""
parser_context = self.get_parser_context(request)
return Request(
request,
parsers=self.get_parsers(),
authenticators=self.get_authenticators(), # 认证[MyAuthentication(),]
negotiator=self.get_content_negotiator(),
parser_context=parser_context
)
def get_authenticators(self):
"""
Instantiates and returns the list of authenticators that this view can use.
"""
return [ auth() for auth in self.authentication_classes ]
def perform_authentication(self, request):
request.user
会执行Request中def user()
def user(self):
self._authenticate()
def _authenticate(self):
for authenticator in self.authenticators:
user_auth_tuple = authenticator.authenticate(self) # 循环上面获取到的认证对象类列表,执行自定制的auhenticate()方法
流程分析:
1. 当前请求到来时,执行APIview dispatch方法,request = self.initialize_request()先进行新的request封装,其中封装了老request、认证类对象列表等。
2. 然后执行 initial方法,先进行分页、再进行认证执行 perform_authentication() --- request.user
3.执行Request中def user(), user中循环认证类对象列表,执行每个对象的 def authenticate()(重写的方法),有三种返回方式:
- 元组:认证通过
- None:进行下个类的认证
- 主动抛出异常:认证失败
下面两种方式可以触发第三步的认证:
request.user 能够获取当前登录用户对象
request.auth 获取toke