热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

c语言restfulapi,restfulapi

Django:csrf防御机制csrf攻击过程1.用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;2.在用户信息通过验证后ÿ

Django: csrf防御机制

csrf攻击过程

e26eec80af08

1.用户C打开浏览器,访问受信任网站A,输入用户名和密码请求登录网站A;

2.在用户信息通过验证后,网站A产生COOKIE信息并返回给浏览器,此时用户登录网站A成功,可以正常发送请求到网站A;

3.用户未退出网站A之前,在同一浏览器中,打开一个TAB页访问网站B;

4.网站B接收到用户请求后,返回一些攻击性代码,并发出一个请求要求访问第三方站点A;

5.浏览器在接收到这些攻击性代码后,根据网站B的请求,在用户不知情的情况下携带COOKIE信息,向网站A发出请求。网站A并不知道该请求其实是由B发起的,所以会根据用户C的COOKIE信息以C的权限处理该请求,导致来自网站B的恶意代码被执行。

在django防御csrf攻击

原理

在客户端页面上添加csrftoken, 服务器端进行验证,服务器端验证的工作通过'django.middleware.csrf.CsrfViewMiddleware'这个中间层来完成。在django当中防御csrf攻击的方式有两种, 1.在表单当中附加csrftoken 2.通过request请求中添加X-CSRFToken请求头。注意:Django默认对所有的POST请求都进行csrftoken验证,若验证失败则403错误侍候。

取消csrftoken验证

通过csrf_exempt, 来取消csrftoken验证,方式有两种。

在视图函数当中添加csrf_exempt装饰器

GET, POST, PUT, DELETE 正好可以对应我们 CRUD (Create, Read, Update, Delete) 四种数据操作

e26eec80af08

e26eec80af08

Django REST framework教程二: 请求和响应

请求对象(Request object)

REST framework引入了一个Request对象, 它继承自普通的HttpRequest, 但能够更加灵活的解析收到的请求。Request对象的核心功能,就是其中的request.data属性。这个属性跟request.POST相似,但对我们的Web API来说,更加的有用。

request.POST     # 只能处理表单(form)数据,只能处理“POST”方法.

request.data       # 处理任意数据.可以处理'POST', 'PUT' 和 'PATCH'方法.

响应对象(Response object)

REST framework 同时引入了Response对象,是一种TemplateResponse,它携带着纯粹的内容,通过内容协商(Content Negotiation)来决定,将以何种形式,返回给客户端。

return Response(data)    #根据客户端的要求,把内容,生成对应的形式。

包装API视图(wrapping API views)

REST framework提供了两种编写API view的封装:

(1)使用@api_view装饰器,基于方法的视图

(2)继承APIView类,基于类的视图

这些视图封装,提供了些许的功能,比如:确保你的视图能够收到Request实例;还有,将内容赋予Response对象,使得内容协商(content negotiation) 可以正常的运作。

from  rest_framework  import  status

from  rest_framework.decorators  import  api_view

from  rest_framework.response  import  Response

from  snippets.models  import  Snippet

from  snippets.serializers  import  SnippetSerializer

@api_view(['GET', 'POST’])

def  snippet_list(request):

"""

列出所有的代码片段(snippets),或者创建一个代码片段(snippet)

"""

if  request.method == 'GET':

snippets = Snippet.objects.all()

serializer = SnippetSerializer(snippets, many=True)

return  Response (serializer.data)

elif  request.method == 'POST':

serializer = SnippetSerializer (data = request.data)

if  serializer.is_valid():

serializer.save()

return  Response (serializer.data, status=status.HTTP_201_CREATED)

return  Response (serializer.errors, status=status.HTTP_400_BAD_REQUEST)

@api_view(['GET', 'PUT', 'DELETE’])

def  snippet_detail(request, pk):

"""

读取, 更新 或 删除 一个代码片段实例(snippet instance)。

"""

try:

snippet = Snippet.objects.get (pk = pk)

except  Snippet.DoesNotExist:

return  Response (status = status.HTTP_404_NOT_FOUND)

if  request.method == 'GET':

serializer = SnippetSerializer (snippet)

return  Response (serializer.data)

elif  request.method == 'PUT':

serializer = SnippetSerializer(snippet, data = request.data)

if  serializer.is_valid():

serializer.save()

return  Response (serializer.data)

return  Response (serializer.errors, status=status.HTTP_400_BAD_REQUEST)

elif  request.method == 'DELETE':

snippet.delete()

return  Response (status=status.HTTP_204_NO_CONTENT)

在这里,我们已经不再明确地,解析/定义视图中 Request/Response的内容类型。request.data会自行处理输入的json请求,当然,也能处理别的格式。同样的,我们只需返回响应对象以及数据,REST framework会帮我们,将响应内容,渲染(render)成正确的格式。

为URLs添加可选的格式后缀

现在,我们的响应,不再硬性绑定在,某一种返回格式上,利用这点优势,我们可以为API端,添加格式的后缀。使用格式后缀,可以定制我们的URLs,使它明确的指向指定的格式,这意味着,我们的API可以处理一些URLs,类似这样的格式http://example.com/api/items/4/.json。

首先,需要添加一个format关键字参数,如下所示:

def  snippet_list (request, format=None):

然后对urls.py文件,做些修改:

from  rest_framework.urlpatterns  import  format_suffix_patterns

urlpatterns = format_suffix_patterns(urlpatterns)

Django REST framework教程三: 基于类的视图

与其使用基于方法(function based)的视图,我们更加倾向使用基于类(class based)的视图。

from  snippets.models  import  Snippet

from  snippets.serializers  import  SnippetSerializer

from  django.http  import  Http404

from  rest_framework.views  import  APIView

from  rest_framework.response  import  Response

from  rest_framework  import  status

class  SnippetList(APIView):

"""

列出所有代码片段(snippets), 或者新建一个代码片段(snippet).

"""

def  get (self, request, format=None):

snippets = Snippet.objects.all()

serializer = SnippetSerializer (snippets, many=True)

return  Response (serializer.data)

def  post (self, request, format=None):

serializer = SnippetSerializer(data=request.data)

if  serializer.is_valid():

serializer.save()

return  Response (serializer.data, status=status.HTTP_201_CREATED)

return  Response  (serializer.errors, status=status.HTTP_400_BAD_REQUEST)

class  SnippetDetail (APIView):

"""

读取, 更新 or 删除一个代码片段(snippet)实例(instance).

"""

def  get_object(self, pk):

try:

return  Snippet.objects.get(pk=pk)

except  Snippet.DoesNotExist:

raise  Http404

def  get(self, request, pk, format=None):

snippet = self.get_object(pk)

serializer = SnippetSerializer(snippet)

returnResponse(serializer.data)

def  put(self, request, pk, format=None):

snippet = self.get_object(pk)

serializer = SnippetSerializer(snippet, data=request.data)

if  serializer.is_valid():

serializer.save()

return  Response(serializer.data)

returnResponse(serializer.errors, status=status.HTTP_400_BAD_REQUEST)

def  delete(self, request, pk, format=None):

snippet = self.get_object(pk)

snippet.delete()

return  Response(status=status.HTTP_204_NO_CONTENT)

urlpatterns = [

url(r'^snippets/$', views.SnippetList.as_view()),

url(r'^snippets/(?P[0-9]+)/$', views.SnippetDetail.as_view()),

]

urlpatterns = format_suffix_patterns(urlpatterns)

使用混入(mixins)

目前为止,我们所用的增删改查操作,在我们创建的,任何支持模型的视图里,都没有太大区别。这些通用的行为,在REST framework的混入(mixin)类中,都已经实现(implemented)了。

from  snippets.models  import  Snippet

from  snippets.serializers  import  SnippetSerializer

from  rest_framework  import  mixins

from  rest_framework  import  generics

class  SnippetList(mixins.ListModelMixin,mixins.CreateModelMixin,

generics.GenericAPIView):

queryset = Snippet.objects.all()

serializer_class = SnippetSerializer

def  get(self, request, *args, **kwargs):

return  self.list(request, *args, **kwargs)

def  post(self, request, *args, **kwargs):

return  self.create(request, *args, **kwargs)

我们使用GenericAPIView创建了我们的视图,并且加入了ListModelMixin和CreateModelMixin

基本类提供了核心的功能,而混入(mixin)类提供了.list()和.create()行为。然后,我们显式地在get和post方法里面,放入对应的行动。非常简单,但目前够用。

class  SnippetDetail(mixins.RetrieveModelMixin,mixins.UpdateModelMixin,

mixins.DestroyModelMixin,

generics.GenericAPIView):

queryset = Snippet.objects.all()

serializer_class = SnippetSerializer

def  get(self, request, *args, **kwargs):

return  self.retrieve(request, *args, **kwargs)

def  put(self, request, *args, **kwargs):

return  self.update(request, *args, **kwargs)

def  delete(self, request, *args, **kwargs):

return  self.destroy(request, *args, **kwargs)

我们使用了GenericAPIView类提供了核心功能,而混入(mixin)类 提供了.retrieve(),.update()和.destroy()行为。

使用基于泛类(generic class)的视图

REST framework提供了一套已经实现了混入类的通用(generic)视图,我们可以使我们的views.py模块,更加瘦身!

from  snippets.models  import  Snippet

from  snippets.serializers  import  SnippetSerializer

from  rest_framework  import  generics

class  SnippetList(generics.ListCreateAPIView):

queryset = Snippet.objects.all()

serializer_class = SnippetSerializer

class  SnippetDetail(generics.RetrieveUpdateDestroyAPIView):

queryset = Snippet.objects.all()

serializer_class = SnippetSerializer

权限的类型

(1)用户是否有访问某个api的权限

(2)用户对于相同的api不同权限看到不同的数据(其实一个filter)

(3)不同权限用户对于api的访问频次,其他限制等等

(4)假删除,各种级联假删除

基本讲解

首先在django中,group以及user都可以有很多的permission,一个user会有他自身permission+所有隶属group的permission。比如:user可能显示的有3个permission,但他隶属于3个组,每个组有2个不同的权限,那么他有3+2*3个权限。

permission会在api的models.py种统一建立,在Meta中添加对应的permission然后跑migrate数据库就会有新的权限。

由于django对每一个不同的Model都会建立几个基本的权限,我会在api/models.py里面单独建一个ModulePermission的Model,没有任何其他属性,就只有一个Meta class上面对应各种权限,这就是为了syncdb用的,另外还一个原因后面再说。

当前我们的API在编辑或者删除的时候没有任何限制,我们不希望有些人有高级的行为,确保:

(1)代码段始终与创建者相关联

(2)只允许授权的用户可以创建代码段

(3)只允许代码段创建者可以更新和删除

(4)没有认证的请求应该有一个完整的只读权限列表

添加用户信息在我们的models中

owner = models.ForeignKey('auth.User', related_name='snippets', on_delete=models.CASCADE)

为我们user models添加serializers

from  django.contrib.auth.models  import  User

class  UserSerializer(serializers.ModelSerializer):

snippets =serializers.PrimaryKeyRelatedField(many=True,queryset=Snippet.objects.all())

class  Meta:

model = User

fields = ('id','username','snippets’)

因为'snippets'是User模型上的反向关系,所以在使用ModelSerializer类时,它不会被默认包含,因此我们需要为它添加一个显式字段。

from  django.contrib.auth.models  import  User

from  snippets.serializers  import  UserSerializer

class  UserList(generics.ListAPIView):

queryset =User.objects.all()

serializer_class =UserSerializer

class  UserDetail(generics.RetrieveAPIView):

queryset =User.objects.all()

serializer_class =UserSerializer

将代码段与用户关联

现在,如果我们创建了代码段,就无法将创建代码段的用户与代码段实例相关联。用户不作为序列化表示的一部分发送,而是传入请求的属性。

我们处理它的方式是通过在我们的代码片段视图上覆盖一个perform_create()方法,允许我们修改实例保存的方式,并处理在传入请求或请求的URL中隐含的任何信息。

在我们SnippetList 视图类中,添加下面的方法

def perform_create(self, serializer):

serializer.save(owner=self.request.user)

当我们的serializer里create()方法被调用时,将自动添加owner字段和验证合法的请求数据

更新我们的seralizer

现在sippets创建的时候已经和我们的用户关联起来,让我们更新我们的SnippetSerializer,添加以下定义的字段:

owner= serializers.ReadOnlyField(source='owner.username’)

source参数用于控制那个属性被用来填充字段,并且可以指向序列化实例上的任何属性。 它也可以采用上面所示的虚线符号,在这种情况下,它将遍历给定的属性,与使用Django的模板语言类似的方式。

我们添加的字段是无类型的ReadOnlyField类,与其他类型的字段,例如CharField,BooleanField等相反。无类型的ReadOnlyField总是只读的,并且将用于序列化表示,但不会 用于在反序列化时更新模型实例。 我们也可以在这里使用CharField(read_only = True)

同时需要在meta class中添加owner字段

class  Meta:

model = Snippet

fields = ('id','title','code','linenos','language','style','owner')

在views中添加请求权限

现在snippets 已经和我们的用户关联上了,我们需要确保仅仅通过验证的用户能够增删改

REST framework 包含有一些权限类,我们可以用来限制谁可以访问给定的视图,在这种情况下,首先我们查找IsAuthenticatedOrReadOnl,这将确保已验证的请求获得读写访问权限,并且未验证的请求获得只读访问权限。

然后在SnippetList和SnippetDetailview中添加下面这个属性

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

对象级别的权限

我们希望所有的代码片段对任何人都可见,但也确保只有创建代码片段的用户能够更新或删除它。为了实现这个,我们需要创建一个自定义权限

在snippets.app中,创建一个新的文件,名为permissions.py

from  rest_framework  import  permissions

classIsOwnerOrReadOnly(permissions.BasePermission):

def  has_object_permission(self, request, view, obj):

"

读取权限对任何的request都适用,接下来将要添加GET,HEAD,OPTIONS请求权限

''

if request.method in permissions.SAFE_METHODS:

return  True

return  obj.owner == request.user

现在我们在SnippetDetail view中通过编辑permission_classes属性为snippet实例中添加自定义的权限

permission_classes = (permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly,)



推荐阅读
author-avatar
是你让我变得冷漠涡
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有