您的位置:首页 > 编程语言 > Python开发

python django rest framework Authentication & Permissions

2017-11-06 12:11 781 查看

身份验证和权限

目前我们的API对谁可以编辑或删除代码片段没有任何限制。 我们希望有一些更高级的行为,以确保:

1. 代码片段始终与创建者相关联。

2. 只有经过身份验证的用户才可以创建片段。

3. 只有代码段的创建者可能会更新或删除它。

4. 未经身份验证的请求应具有完全只读访问权限。

将信息添加到我们的模型

我们将对Snippet模型类进行一些更改。 首先,我们添加几个字段。 其中一个字段将用于表示创建代码段的用户。 其他字段将用于存储代码的突出显示的HTML表示形式。

将以下两个字段添加到models.py中的片段模型中。

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


我们还需要确保保存模型时,使用pygments代码高亮库来填充突出显示的字段。

我们需要一些额外的进口:

from pygments.lexers import get_lexer_by_name
from pygments.formatters.html import HtmlFormatter
from pygments import highlight


现在我们可以在模型类中添加一个.save()方法:

def save(self, *args, **kwargs):
"""
Use the `pygments` library to create a highlighted HTML
representation of the code snippet.
"""
lexer = get_lexer_by_name(self.language)
linenos = self.linenos and 'table' or False
options = self.title and {'title': self.title} or {}
formatter = HtmlFormatter(style=self.style, linenos=linenos,
full=True, **options)
self.highlighted = highlight(self.code, lexer, formatter)
super(Snippet, self).save(*args, **kwargs)


完成之后,我们需要更新我们的数据库表。 通常情况下,我们会创建一个数据库迁移,但为了实现本教程的目的,我们只需删除数据库并重新启动即可。

python manage.py makemigrations snippets
python manage.py migrate


您可能还想创建几个不同的用户,以用于测试API。 最快捷的方法是使用createsuperuser命令。

python manage.py createsuperuser


为我们的用户模型添加端点

现在我们有一些用户可以使用,我们最好将这些用户的表示添加到我们的API中。 创建一个新的序列化器很容易。 在serializers.py中添加:

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')


由于“片段”在用户模型上是相反的关系,因此在使用ModelSerializer类时将不会包含默认的片段,所以我们需要为其添加一个显式字段。我们还将为views.py添加一些视图。 我们只想为用户表示使用只读视图,所以我们将使用ListAPIView和RetrieveAPIView通用的基于类的视图。

from django.contrib.auth.models import User

class UserList(generics.ListAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer

class UserDetail(generics.RetrieveAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer


确保还要导入UserSerializer类

from snippets.serializers import UserSerializer


最后,我们需要将这些视图添加到API中,方法是从URL conf中引用它们。 将以下内容添加到urls.py中的模式中。

url(r'^users/$', views.UserList.as_view()),
url(r'^users/(?P<pk>[0-9]+)/$', views.UserDetail.as_view()),


将片段与用户相关联

现在,如果我们创建了一个代码片段,那么就没有办法将创建片段的用户与代码片段实例关联起来。 用户不是作为序列化表示的一部分发送的,而是作为传入请求的属性。我们处理这个问题的方式是在代码片断视图上重写.perform_create()方法,这允许我们修改如何管理实例保存,并处理传入请求或请求URL中隐含的任何信息。

在SnippetList视图类中添加以下方法:

def perform_create(self, serializer):
serializer.save(owner=self.request.user)


我们序列化器的create()方法现在将被传递一个额外的“owner”字段,以及来自请求的验证数据。

更新我们的序列化器

现在,片段与创建它们的用户相关联,让我们更新我们的SnippetSerializer以反映这一点。 将以下字段添加到serializers.py中的序列化程序定义中:

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


注意:请确保您也添加“owner”到内部Meta类中的字段列表。

class SnippetSerializer(serializers.ModelSerializer):
owner = serializers.ReadOnlyField(source='owner.username')

class Meta:
model = Snippet
fields = ('id', 'title', 'code', 'linenos', 'language', 'style', 'owner')


这个领域正在做一些有趣的事情。 source参数控制哪个属性用于填充字段,并且可以指向序列化实例上的任何属性。 它也可以采用上面显示的虚线符号,在这种情况下,它将以与Django的模板语言类似的方式遍历给定的属性。我们添加的字段是无类型的ReadOnlyField类,与其他类型的字段相比,如CharField,BooleanField等…非类型化的ReadOnlyField总是只读的,并且将用于序列化的表示,但不会是 用于在反序列化时更新模型实例。 我们也可以在这里使用CharField(read_only = True)。

将所需的权限添加到视图

现在代码片段与用户相关联,我们要确保只有经过身份验证的用户才能创建,更新和删除代码片段。REST框架包含许多权限类,我们可以使用这些权限类来限制可以访问给定视图的人员。 在这种情况下,我们正在寻找的是IsAuthenticatedOrReadOnly,这将确保经过身份验证的请求获得读写访问,未经身份验证的请求获得只读访问。

首先在视图模块中添加以下导入

from rest_framework import permissions


然后,将以下属性添加到SnippetList和SnippetDetail视图类。

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)


添加登录到Browsable API

如果您现在打开浏览器并导航到可浏览的API,则会发现您不再能够创建新的代码片段。 为了做到这一点,我们需要能够以用户身份登录。我们可以通过编辑我们的项目级urls.py文件中的URLconf来添加可浏览API的登录视图。

在文件顶部添加以下导入:

from django.conf.urls import include


然后,在文件末尾添加一个模式,以包含可浏览API的登录和注销视图。

urlpatterns += [
url(r'^api-auth/', include('rest_framework.urls',
namespace='rest_framework')),
]


模式的r’^ api-auth /’部分实际上可以是任何您想要使用的URL。 唯一的限制是包含的url必须使用“rest_framework”命名空间。 在Django 1.9+中,REST框架将设置命名空间,所以你可以把它放在外面。现在,如果您再次打开浏览器并刷新页面,则会在页面右上方看到一个“登录”链接。 如果您以之前创建的用户身份登录,则可以再次创建代码片段。一旦创建了一些代码片段,请导航到“/ users /”端点,并注意到代表性包括每个用户的“代码段”字段中与每个用户关联的代码段ID列表。

对象级权限

实际上,我们希望所有人都可以看到所有代码片段,但也要确保只有创建代码段的用户才能更新或删除它。要做到这一点,我们将需要创建一个自定义权限。在snippets应用程序中,创建一个新文件permissions.py

from rest_framework import permissions

class IsOwnerOrReadOnly(permissions.BasePermission):
"""
Custom permission to only allow owners of an object to edit it.
"""

def has_object_permission(self, request, view, obj):
# Read permissions are allowed to any request,
# so we'll always allow GET, HEAD or OPTIONS requests.
if request.method in permissions.SAFE_METHODS:
return True

# Write permissions are only allowed to the owner of the snippet.
return obj.owner == request.user


现在我们可以通过编辑SnippetDetail视图类中的permission_classes属性来将该自定义权限添加到我们的代码片段实例端点:

permission_classes = (permissions.IsAuthenticatedOrReadOnly,
IsOwnerOrReadOnly,)


确保还要导入IsOwnerOrReadOnly类。

from snippets.permissions import IsOwnerOrReadOnly


使用API进行身份验证

因为我们现在在API上拥有一组权限,所以如果我们要编辑任何代码片段,我们需要验证我们的请求。 我们还没有设置任何认证类,因此当前应用了默认值,即SessionAuthentication和BasicAuthentication。当我们通过Web浏览器与API进行交互时,我们可以登录,然后浏览器会话将为请求提供所需的身份验证。如果我们正在以编程方式与API进行交互,则需要在每个请求上明确提供身份验证凭据。如果我们尝试创建一个没有认证的片段,我们会得到一个错误:

http POST http://127.0.0.1:8000/snippets/ code="print 123"

{
"detail": "Authentication credentials were not provided."
}


我们可以通过包含我们之前创建的用户的用户名和密码来提出成功的请求。

http -a tom:password123 POST http://127.0.0.1:8000/snippets/ code="print 789"

{
"id": 1,
"owner": "tom",
"title": "foo",
"code": "print 789",
"linenos": false,
"language": "python",
"style": "friendly"
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  django python