【DRF】Django REST Framework - Tutorial 4: 认证 和&权限

16 篇文章 0 订阅
15 篇文章 2 订阅

发布日期 2019/May/10

最后更新日期:? 2019/May/10



当前,我们的 API 在“谁”可以编辑或删除 snippets 上没有任何限制。我们希望有一些更高级的行为来确保:

  • Code snippets are always associated with a creator.
  • 仅有验证过的用户可以创建 snippets。
  • 仅有该 snippet 的创建者可以更新或者删除它。
  • 未认证过的/匿名(用户)请求应当有完全的 read-only 访问权限。

添加必要信息段到我们的模型中

Adding information to our model

我们将会在 Snippet 模型上做几处修改。
首先,我们添加一对 fields。其中一处的 fields 将会用于表示创建了 code snippet 的用户。另外的 field 将会被用户储存 the highlighted HTML representation of the code.
models.py 中添加以下两处 fields 到 Snippet 模型

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

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

原:We’d also need to make sure that when the model is saved, that we populate the highlighted field, using the pygments code highlighting library.

我们需要导入一些其它的包:

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

现在我们可以重载 .save() 方法在 model class 中:

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 = 'table' if self.linenos else False
    options = {'title': self.title} if self.title else {}
    formatter = HtmlFormatter(style=self.style, linenos=linenos,
                              full=True, **options)
    self.highlighted = highlight(self.code, lexer, formatter)
    super(Snippet, self).save(*args, **kwargs)

完成所有操作后,我们需要更新数据库表。通常我们会创建一个数据库迁移来执行此操作,但是出于本教程的目的,我们只需删除数据库并重新开始。

原: When that’s all done we’ll need to update our database tables. Normally we’d create a database migration in order to do that, but for the purposes of this tutorial, let’s just delete the database and start again.

$ rm -f db.sqlite3
$ rm -r snippets/migrations
$ python manage.py makemigrations snippets
$ python manage.py migrate

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

原:You might also want to create a few different users, to use for testing the API. The quickest way to do this will be with the createsuperuser command.

$ python manage.py createsuperuser

为我们的 User 模型添加 endpoints

Adding endpoints for our User models

既然我们已经有一些用户可以使用,我们最好将这些用户的表示添加到我们的API中。创建新的序列化器很简单。在serializers.py 中添加:

原: Now that we’ve got some users to work with, we’d better add representations of those users to our API. Creating a new serializer is easy. In serializers.py add:

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”是用户模型上的反向关系,因此在使用ModelSerializer类时,默认情况下不会包含它,因此我们需要为它添加一个显式字段。

原:Because ‘snippets’ is a reverse relationship on the User model, it will not be included by default when using the ModelSerializer class, so we needed to add an explicit field for it.

我们还将向views.py添加一些视图。我们只想对用户表示使用只读视图,所以我们将使用ListapiView和RetrieveapiView基于类的通用视图。

原:We’ll also add a couple of views to views.py. We’d like to just use read-only views for the user representations, so we’ll use the ListAPIView and RetrieveAPIView generic class-based views.

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中引用它们。将以下内容添加到 snippets/urls.py 中的模式。

原:Finally we need to add those views into the API, by referencing them from the URL conf. Add the following to the patterns in snippets/urls.py.

path('users/', views.UserList.as_view()),
path('users/<int:pk>/', views.UserDetail.as_view()),

将 Snippets 关联到 Users

Associating Snippets with Users

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

原:Right now, if we created a code snippet, there’d be no way of associating the user that created the snippet, with the snippet instance. The user isn’t sent as part of the serialized representation, but is instead a property of the incoming request.

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

原: The way we deal with that is by overriding a .perform_create() method on our snippet views, that allows us to modify how the instance save is managed, and handle any information that is implicit in the incoming request or requested URL.

SnippetList view class,添加如下方法:

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

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

原:The create() method of our serializer will now be passed an additional ‘owner’ field, along with the validated data from the request.

更新我们的序列器(serializer)

Updating our serializer

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

原: Now that snippets are associated with the user that created them, let’s update our SnippetSerializer to reflect that. Add the following field to the serializer definition in serializers.py:

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

Note: Make sure you also add ‘owner’, to the list of fields in the inner Meta class.
This field is doing something quite interesting. The source argument controls which attribute is used to populate a field, and can point at any attribute on the serialized instance. It can also take the dotted notation shown above, in which case it will traverse the given attributes, in a similar way as it is used with Django’s template language.

The field we’ve added is the untyped ReadOnlyField class, in contrast to the other typed fields, such as CharField, BooleanField etc… The untyped ReadOnlyField is always read-only, and will be used for serialized representations, but will not be used for updating model instances when they are deserialized. We could have also used CharField(read_only=True) here.

添加权限请求到 views 中

Adding required permissions to views

Now that code snippets are associated with users, we want to make sure that only authenticated users are able to create, update and delete code snippets.

REST framework includes a number of permission classes that we can use to restrict who can access a given view. In this case the one we’re looking for is IsAuthenticatedOrReadOnly, which will ensure that authenticated requests get read-write access, and unauthenticated requests get read-only access.

First add the following import in the views module

from rest_framework import permissions

Then, add the following property to both the SnippetList and SnippetDetail view classes.

permission_classes = (permissions.IsAuthenticatedOrReadOnly,)

添加 login 功能到 Browsable API

Adding login to the Browsable API

If you open a browser and navigate to the browsable API at the moment, you’ll find that you’re no longer able to create new code snippets. In order to do so we’d need to be able to login as a user.

We can add a login view for use with the browsable API, by editing the URLconf in our project-level urls.py file.

Add the following import at the top of the file:

from django.conf.urls import include

And, at the end of the file, add a pattern to include the login and logout views for the browsable API.

urlpatterns += [
    path('api-auth/', include('rest_framework.urls')),
]

The ‘api-auth/’ part of pattern can actually be whatever URL you want to use.

Now if you open up the browser again and refresh the page you’ll see a ‘Login’ link in the top right of the page. If you log in as one of the users you created earlier, you’ll be able to create code snippets again.

Once you’ve created a few code snippets, navigate to the ‘/users/’ endpoint, and notice that the representation includes a list of the snippet ids that are associated with each user, in each user’s ‘snippets’ field.

Object 级别的权限

Object level permissions

Really we’d like all code snippets to be visible to anyone, but also make sure that only the user that created a code snippet is able to update or delete it.

To do that we’re going to need to create a custom permission.

In the snippets app, create a new file, 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属性,将该自定义权限添加到我们的代码段实例端点:

原:Now we can add that custom permission to our snippet instance endpoint, by editing the permission_classes property on the SnippetDetail view class:

permission_classes = (permissions.IsAuthenticatedOrReadOnly,
                      IsOwnerOrReadOnly,)

Make sure to also import the IsOwnerOrReadOnly class.

from snippets.permissions import IsOwnerOrReadOnly

现在,如果再次打开浏览器,如果您以创建代码段的同一用户身份登录,则会发现“DELETE”和“PUT”操作仅显示在代码段实例端点上。

原: Now, if you open a browser again, you find that the ‘DELETE’ and ‘PUT’ actions only appear on a snippet instance endpoint if you’re logged in as the same user that created the code snippet.

使用 API 通过认证

Authenticating with the API

Because we now have a set of permissions on the API, we need to authenticate our requests to it if we want to edit any snippets. We haven’t set up any authentication classes, so the defaults are currently applied, which are SessionAuthentication and BasicAuthentication.

当我们通过Web浏览器与API交互时,我们可以登录,然后浏览器会话将为请求提供所需的身份验证。

原: When we interact with the API through the web browser, we can login, and the browser session will then provide the required authentication for the requests.

如果我们以编程方式与API交互,我们需要在每个请求上明确提供身份验证凭据。

原:If we’re interacting with the API programmatically we need to explicitly provide the authentication credentials on each request.

如果我们尝试在不进行身份验证的情况下创建代码段,则会收到错误消息:

原:If we try to create a snippet without authenticating, we’ll get an error:

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

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

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

原:We can make a successful request by including the username and password of one of the users we created earlier.

http -a admin:password123 POST http://127.0.0.1:8000/snippets/ code="print(789)"

{
    "id": 1,
    "owner": "admin",
    "title": "foo",
    "code": "print(789)",
    "linenos": false,
    "language": "python",
    "style": "friendly"
}

Summary

We’ve now got a fairly fine-grained set of permissions on our Web API, and end points for users of the system and for the code snippets that they have created.

In part 5 of the tutorial we’ll look at how we can tie everything together by creating an HTML endpoint for our highlighted snippets, and improve the cohesion of our API by using hyperlinking for the relationships within the system.

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
提供的源码资源涵盖了安卓应用、小程序、Python应用和Java应用等多个领域,每个领域都包含了丰富的实例和项目。这些源码都是基于各自平台的最新技术和标准编写,确保了在对应环境下能够无缝运行。同时,源码中配备了详细的注释和文档,帮助用户快速理解代码结构和实现逻辑。 适用人群: 这些源码资源特别适合大学生群体。无论你是计算机相关专业的学生,还是对其他领域编程感兴趣的学生,这些资源都能为你提供宝贵的学习和实践机会。通过学习和运行这些源码,你可以掌握各平台开发的基础知识,提升编程能力和项目实战经验。 使用场景及目标: 在学习阶段,你可以利用这些源码资源进行课程实践、课外项目或毕业设计。通过分析和运行源码,你将深入了解各平台开发的技术细节和最佳实践,逐步培养起自己的项目开发和问题解决能力。此外,在求职或创业过程中,具备跨平台开发能力的大学生将更具竞争力。 其他说明: 为了确保源码资源的可运行性和易用性,特别注意了以下几点:首先,每份源码都提供了详细的运行环境和依赖说明,确保用户能够轻松搭建起开发环境;其次,源码中的注释和文档都非常完善,方便用户快速上手和理解代码;最后,我会定期更新这些源码资源,以适应各平台技术的最新发展和市场需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值