Require a present and correct csrfmiddlewaretoken for POST requests that have a CSRF cookie, and set an outgoing CSRF cookie.html
This middleware should be used in conjunction with the {% csrf_token %}
template tag.django
django 的中间件是基于 post 的请求,当post 请求到来的时候 在csrftoken 中间件中执行 process_view 验证 token的正确性,若是验证失败,则返回forbidden 提示给用户。编程
其次咱们能够在咱们不须要验证csrftoken的视图view中加装饰器来使咱们的视图函数免予csrftoken的校验,使用以下:json
from django.shortcuts import render, HttpResponse from django.views import View from django.views.decorators.csrf import csrf_exempt, csrf_protect # csrf_token 单独示例 from django.utils.decorators import method_decorator # 基于函数的使用 @csrf_exempt def index(request): # what you want you view do in this return HttpResponse("index") # 基于类的方式 2-1 @method_decorator(csrf_exempt, name="dispatch") class StudentView(View): #方式 2-1 @method_decorator(csrf_exempt) def dispatch(self, request, *args, **kwargs): # do something before diaspatch ret = super(StudentView, self).dispatch(request, *args, **kwargs) #do somethig after dispatch return ret def get(self, request, *args, **kwargs): return HttpResponse("GET") def post(self, request, *args, **kwargs): return HttpResponse("POST")
django 中cbv模式中,已类来接受一个请求的到来,经过类继承 view 类
经过父类的dispatch 方法经过反射 进行请求方法的分发。咱们也能够在继承父类的dispatch 方法 来自定制本身的一些操做,rest-framework 也是基于这个实现的,所以咱们先看看下他的源码部分:api
首先是url中的配置:跨域
urlpatterns = [ re_path('^student/$', views.StudentView.as_view()), re_path('^dog/$', views.DogView.as_view()), ]
当请求到来的时候,执行as_view() 方法让咱们来看下 as_view()作了啥:安全
def as_view(cls, **initkwargs): """Main entry point for a request-response process.""" ....... def view(request, *args, **kwargs): self = cls(**initkwargs) if hasattr(self, 'get') and not hasattr(self, 'head'): self.head = self.get self.request = request self.args = args self.kwargs = kwargs return self.dispatch(request, *args, **kwargs) # 看这里执行了View的dispatch 方法 view.view_class = cls view.view_initkwargs = initkwargs # take name and docstring from class update_wrapper(view, cls, updated=()) # and possible attributes set by decorators # like csrf_exempt from dispatch update_wrapper(view, cls.dispatch, assigned=()) return view
再来看看 view类的dispatch 方法:注意可定制的操做前面已经给出服务器
def dispatch(self, request, *args, **kwargs): # 这里的self. http_method_names = ['get', 'post', 'put', 'patch', 'delete', 'head', 'options', 'trace'] if request.method.lower() in self.http_method_names: # 经过反射找到对应的方法 handler = getattr(self, request.method.lower(), self.http_method_not_allowed) else: handler = self.http_method_not_allowed return handler(request, *args, **kwargs)
首先 rest_framework 是为了遵循RESTful 规范而诞生的框架;
那咱们首先须要知道什么是RESTful 规范restful
REST与技术无关,表明的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”cookie
REST从资源的角度类审视整个网络,它将分布在网络中某个节点的资源经过URL进行标识,客户端应用经过URL来获取资源的表征,得到这些表征导致这些应用转变状态
REST与技术无关,表明的是一种软件架构风格,REST是Representational State Transfer的简称,中文翻译为“表征状态转移”
全部的数据,不过是经过网络获取的仍是操做(增删改查)的数据,都是资源,将一切数据视为资源是REST区别与其余架构风格的最本质属性
对于REST这种面向资源的架构风格,有人提出一种全新的结构理念,即:面向资源架构(ROA:Resource Oriented Architecture)
接下来让咱们了解下他的API设计规范
一、在url接口中推荐使用Https协议,让网络接口更加安全(Https是Http的安全版,即HTTP下加入 SSL层,HTTPS的安全基础是SSL,所以加密的详细内容就须要SSL(安全套接层协议))
二、url中能够体现这是个API接口 域名规范
https://api.example.com 尽可能将API部署在专用域名(会存在跨域问题)
https://example.org/api/ API很简单
三、url中还能够体现版本号,不一样的版本能够有不一样的接口,使其更加简洁,清晰
URL,如:https://api.example.com/v1/
请求头跨域时, 引起发送屡次请求
四、restful 提倡面向资源编程,因此在url接口中尽可能要使用名词,不要使用动词
https://api.example.com/v1/zoos
https://api.example.com/v1/animals
https://api.example.com/v1/employees
五、此外url中还能够添加条件去筛选匹配
过滤,经过在url上传参的形式传递搜索条件
https://api.example.com/v1/zoos?limit=10:指定返回记录的数量
https://api.example.com/v1/zoos?offset=10:指定返回记录的开始位置
https://api.example.com/v1/zoos?page=2&per_page=100:指定第几页,以及每页的记录数
https://api.example.com/v1/zoos?sortby=name&order=asc:指定返回结果按照哪一个属性排序,以及排序顺序
https://api.example.com/v1/zoos?animal_type_id=1:指定筛选条件
六、能够根据Http不一样的method,进行不一样的资源操做(5种方法:GET / POST / PUT / DELETE
/ PATCH)
GET :从服务器取出资源(一项或多项)
POST :在服务器新建一个资源
PUT :在服务器更新资源(客户端提供改变后的完整资源)
PATCH :在服务器更新资源(客户端提供改变的属性)
DELETE :从服务器删除资源
200 OK - [GET]:服务器成功返回用户请求的数据,该操做是幂等的(Idempotent)。 201 CREATED - [POST/PUT/PATCH]:用户新建或修改数据成功。 202 Accepted - [*]:表示一个请求已经进入后台排队(异步任务) 204 NO CONTENT - [DELETE]:用户删除数据成功。 400 INVALID REQUEST - [POST/PUT/PATCH]:用户发出的请求有错误,服务器没有进行新建或修改数据的操做,该操做是幂等的。 401 Unauthorized - [*]:表示用户没有权限(令牌、用户名、密码错误)。 403 Forbidden - [*] 表示用户获得受权(与401错误相对),可是访问是被禁止的。 404 NOT FOUND - [*]:用户发出的请求针对的是不存在的记录,服务器没有进行操做,该操做是幂等的。 406 Not Acceptable - [GET]:用户请求的格式不可得(好比用户请求JSON格式,可是只有XML格式)。 410 Gone -[GET]:用户请求的资源被永久删除,且不会再获得的。 422 Unprocesable entity - [POST/PUT/PATCH] 当建立一个对象时,发生一个验证错误。 500 INTERNAL SERVER ERROR - [*]:服务器发生错误,用户将没法判断发出的请求是否成功。 更多看这里:http://www.w3.org/Protocols/rfc2616/rfc2616-sec10.html
1.首先咱们的视图须要时候基于cbv的模式,咱们的类须要继承rest_framework的view的 APIView 父类
以下:
class DogView(APIView): def get(self, request, *args, **kwargs): return HttpResponse("GET") def post(self, request, *args, **kwargs): return HttpResponse("POST")
接下来让咱们研究下APIView的dispath 方法:
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. """ self.args = args self.kwargs = kwargs # 对原生的request 加工(丰富) """" Request( request,parsers=self.get_parsers(), authenticators=self.get_authenticators(), negotiator=self.get_content_negotiator(), parser_context=parser_context) 原生的request = request._request """ # 首先是对原生的request进行了加个处理 request = self.initialize_request(request, *args, **kwargs) self.request = request self.headers = self.default_response_headers # deprecate?
咱们来看下 self.initialize_request 这个方法实现方法
def initialize_request(self, request, *args, **kwargs): """ Returns the initial request object. """ parser_context = self.get_parser_context(request) # self.get_authenticators() seteings配置的一个列表 # authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES # 对原生的request第二次加工 return Request( request, # 封装了解析器类 parsers=self.get_parsers(), # 封装了用户用户认证的类 authenticators=self.get_authenticators(), # url后缀名的显示方式 ex--> .json negotiator=self.get_content_negotiator(), parser_context=parser_context )
在讨论源码以前我先rest_framework配置放在这里(后面须要修改的会加上去):
# 能够看这里 from rest_framework import settings # List of settings that may be in string import notation. IMPORT_STRINGS = ( 'DEFAULT_RENDERER_CLASSES', 'DEFAULT_PARSER_CLASSES', 'DEFAULT_AUTHENTICATION_CLASSES', 'DEFAULT_PERMISSION_CLASSES', 'DEFAULT_THROTTLE_CLASSES', 'DEFAULT_CONTENT_NEGOTIATION_CLASS', 'DEFAULT_METADATA_CLASS', 'DEFAULT_VERSIONING_CLASS', 'DEFAULT_PAGINATION_CLASS', 'DEFAULT_FILTER_BACKENDS', 'DEFAULT_SCHEMA_CLASS', 'EXCEPTION_HANDLER', 'TEST_REQUEST_RENDERER_CLASSES', 'UNAUTHENTICATED_USER', 'UNAUTHENTICATED_TOKEN', 'VIEW_NAME_FUNCTION', 'VIEW_DESCRIPTION_FUNCTION' )
封住完request以后接下来咱们看看后面的源码
# 进行一系列的认证 #初始化进入验证,下面来看看initial 这个函数作了啥 self.initial(request, *args, **kwargs) #-------------------------------------------------- def initial(self, request, *args, **kwargs): """ Runs anything that needs to occur prior to calling the method handler. """ self.format_kwarg = self.get_format_suffix(**kwargs) ....... ## 版本的控制的 version, scheme = self.determine_version(request, *args, **kwargs) request.version, request.versioning_scheme = version, scheme # 认证 self.perform_authentication(request) # 权限验证 self.check_permissions(request) # 访问频率 self.check_throttles(request)
接下来讨论 认证方法
self.perform_authentication(request)源码:
View 类 def perform_authentication(self, request): """ Perform authentication on the incoming request. Note that if you override this and simply 'pass', then authentication will instead be performed lazily, the first time either `request.user` or `request.auth` is accessed. """ request.user Request 类 def _authenticate(self): """ Attempt to authenticate the request using each authentication instance in turn. """ # 遍历 setting defaults 的列表 的 """ 'rest_framework.authentication.SessionAuthentication', 'rest_framework.authentication.BasicAuthentication' """ # 执行每一个self.authenticators类中的认证类方法: for authenticator in self.authenticators: try: # 返回值有三种 """ 1.返回user 与 token 对象(认证成功) 2.返回None(不作处理,交个下一个) 3.抛出认证异常(认证失败) """ user_auth_tuple = authenticator.authenticate(self) except exceptions.APIException: self._not_authenticated() raise if user_auth_tuple is not None: self._authenticator = authenticator self.user, self.auth = user_auth_tuple return self._not_authenticated()
认证类的写法:
# Lower 写法 class MyBasicAuthentication(object): def authenticate(self, request): token = request._request.GET.get("token") if token: return ("alex",None) raise exceptions.AuthenticationFailed("failed") def authenticate_header(self, val): pass """咱们能够继承他的类""" # 基于用户token的认证 from rest_framework.authentication import BasicAuthentication 默认的几种用户认证类 本身写的能够继承BasicAuthentication 1.一中是本身定义类而后在view视图中这要表达: authentication_classes=[ yourauthclass, ] 2.或者全局配置 REST_FRAMEWORK={ "DEFAULT_AUTHENTICATION_CLASSES":[.......] }
接下来是用户权限的控制 这个比较简单直接上rest的自带的几个权限验证的源码类本身研究:
from rest_framework.permissions import BasePermission class BasePermission(object): """ A base class from which all permission classes should inherit. """ def has_permission(self, request, view): """ Return `True` if permission is granted, `False` otherwise. """ return True # 这个力度更加细致对于每一个用户的管理,后面会将 def has_object_permission(self, request, view, obj): """ Return `True` if permission is granted, `False` otherwise. """ return True