Django Rest Framework组件:认证和授权模块BaseAuthentication
视图FBV与CBV模板
FBV:在urls.py中一个url对应一个函数,如以下:
path('^user/', views.users) FBV
path('^student/', views.student.as_views()) CBV
#FBV:一个url对应一个函数 def users(request): if request.method == "GET": return HttpResponse(json.dumps((uers))) if request.method == "POST": pass if request.method == "PUT": pass if request.method == "Delete": pass #CBV:一个url对应一个类 #CBV基于反射:请求方法的不同,执行不同的方法 # 原理:url路由-》view方法-》dispatch方法:Get、、 from django.views import View class student(View): def dispatch(self,request,*args,**kwargs): # print("before") #执行父类的dispatch方法 ret = super(student,self).dispatch(request,*args,**kwargs) print("after") return ret def get(self,request,*args,**kwargs): return HttpResponse("GET") def post(self,request,*args,**kwargs): return HttpResponse("POST") def put(self,request,*args,**kwargs): return HttpResponse("PUT") def delete(self,request,*args,**kwargs): return HttpResponse("DELETE")
上面两种视图模板,CBV更适合我们开发,而对于CBV模板在Django rest 框架中开发流程如下:
url.py
from django.conf.urls import url, include from app名.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
views.py
from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def dispatch(self, request, *args, **kwargs): """ 请求到来之后,都要执行dispatch方法,dispatch方法根据请求方式不同触发 get/post/put等方法 注意:APIView中的dispatch方法有好多好多的功能 """ return super().dispatch(request, *args, **kwargs) def get(self, request, *args, **kwargs): return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
CSRF的免除
对于FBV:单个函数免除csrf
1.先在视图下导入from django.views.decorators.csrf import csrf_exempt
2.给单个函数加上 @csrf_exempt
对于CBV:单个函数免除csrf
1.先在视图下导入from django.utils.decorators import method_decorator
2.给类下单个函数加上 @method_decorator(csrf_exempt)
注意:你可以把它加在子类重写的dispatch方法上,当子类的dispatch执行时通过super执行父类的dispatch方法,再通过反射找到子类相应的函数去执行。
Token认证
局部配置:只对单个URL对应的视图函数有效。
#认证三步走:
1.对需要认证的url对应的CBV,写一个认证类,里面必须包括两个方法:
authenticate:具体验证工作这个函数中做
authenticate_header:验证失败响应头返回值设置
2.认证类使用列表容器存储并赋值给authentication_classes
authentication_classes = [TestAuthentication, ]
3.认证成功返回元组:
return ('登录用户', '用户token')
可以通过request.user获取
1.客户端通过url传入token方式
from django.conf.urls import url, include from App名.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ val = request.query_params.get('token') if val not in token_list: raise exceptions.AuthenticationFailed("用户认证失败") return ('登录用户', '用户token') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ # 验证失败时,返回的响应头WWW-Authenticate对应的值 pass class TestView(APIView): authentication_classes = [TestAuthentication, ]def get(self, request, *args, **kwargs): print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
2.通过请求头传入
from django.conf.urls import url, include from app名.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response from rest_framework.authentication import BaseAuthentication from rest_framework.request import Request from rest_framework import exceptions token_list = [ 'sfsfss123kuf3j123', 'asijnfowerkkf9812', ] class TestAuthentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ import base64 auth = request.META.get('HTTP_AUTHORIZATION', b'') if auth: auth = auth.encode('utf-8') auth = auth.split() if not auth or auth[0].lower() != b'basic': raise exceptions.AuthenticationFailed('验证失败') if len(auth) != 2: raise exceptions.AuthenticationFailed('验证失败') username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') if username == 'alex' and password == '123': return ('登录用户', '用户token') else: raise exceptions.AuthenticationFailed('用户名或密码错误') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ return 'Basic realm=api' class TestView(APIView): authentication_classes = [TestAuthentication, ]def get(self, request, *args, **kwargs): print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')
全局配置:对所有URL对应的视图函数有效。
1.在应用目录下和views.py文件同级下创建认证模块。然后在认证模块下创建认证类
class TestAuthentication(BaseAuthentication): def authenticate(self, request): """ 用户认证,如果验证成功后返回元组: (用户,用户Token) :param request: :return: None,表示跳过该验证; 如果跳过了所有认证,默认用户和Token和使用配置文件进行设置 self._authenticator = None if api_settings.UNAUTHENTICATED_USER: self.user = api_settings.UNAUTHENTICATED_USER() else: self.user = None if api_settings.UNAUTHENTICATED_TOKEN: self.auth = api_settings.UNAUTHENTICATED_TOKEN() else: self.auth = None (user,token)表示验证通过并设置用户名和Token; AuthenticationFailed异常 """ import base64 auth = request.META.get('HTTP_AUTHORIZATION', b'') if auth: auth = auth.encode('utf-8') auth = auth.split() if not auth or auth[0].lower() != b'basic': raise exceptions.AuthenticationFailed('验证失败') if len(auth) != 2: raise exceptions.AuthenticationFailed('验证失败') username, part, password = base64.b64decode(auth[1]).decode('utf-8').partition(':') if username == 'alex' and password == '123': return ('登录用户', '用户token') else: raise exceptions.AuthenticationFailed('用户名或密码错误') def authenticate_header(self, request): """ Return a string to be used as the value of the `WWW-Authenticate` header in a `401 Unauthenticated` response, or `None` if the authentication scheme should return `403 Permission Denied` responses. """ return 'Basic realm=api'
2.在settings配置文件中写入(添加刚才写的认证类的位置):
REST_FRAMEWORK = { 'DEFAULT_AUTHENTICATION_CLASSES':( '应用名.应用下的模块名.模块下的认证类名', ) }
3.urls.py文件不需要改动,views.py文件去掉authentication_classes = [TestAuthentication, ]
from django.conf.urls import url, include from 应用名.views import TestView urlpatterns = [ url(r'^test/', TestView.as_view()), ]
#!/usr/bin/env python # -*- coding:utf-8 -*- from rest_framework.views import APIView from rest_framework.response import Response class TestView(APIView): def get(self, request, *args, **kwargs): # self.dispatch print(request.user) print(request.auth) return Response('GET请求,响应内容') def post(self, request, *args, **kwargs): return Response('POST请求,响应内容') def put(self, request, *args, **kwargs): return Response('PUT请求,响应内容')