自定义权限
是时候获得我们的第一个自定义权限了。 作为我们现在的简要回顾:我们有两个用户,testuser 和超级用户帐户。 我们的数据库中有一个博客帖子,由超级用户创建。
我们只希望特定博客文章的作者能够对其进行编辑或删除; 否则,博客文章应为只读。 因此,超级用户帐户应具有对单个博客实例的完整 CRUD 访问权限,而常规用户 testuser 应该没有。
使用 Control + c 停止本地服务器,并在我们的帖子应用中创建一个新的 permissions.py文件。
(blogapi) $ touch posts/permissions.py
在内部,Django REST Framework 依赖于 BasePermission 类,所有其他权限类都从该 BasePermission 类继承。 这意味着诸如 AllowAny,IsAuthenticated 之类的内置权限设置会对其进行扩展。 这是 Github 上可用的实际源代码:
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
要创建自己的自定义权限,我们将覆盖 has_object_permission方法。 具体来说,我们希望对所有请求都允许只读,但对于任何写入请求(例如编辑或删除),作者必须与当前登录的用户相同。
这是我们的 posts / permissions.py 文件的内容。
# posts/permissions.py from rest_framework import permissions class IsAuthorOrReadOnly(permissions.BasePermission): def has_object_permission(self, request, view, obj): # Read-only permissions are allowed for any request if request.method in permissions.SAFE_METHODS: return True # Write permissions are only allowed to the author of a post return obj.author == request.user
我们在顶部导入权限,然后创建自定义类 IsAuthorOrReadOnly,该类扩展了 BasePermission。 然后,我们覆盖 has_object_permission。 如果请求包含 SAFE_METHODS 中包含的 HTTP 动词(包含 GET,OPTIONS 和 HEAD 的元组),则该请求为只读请求,并授予权限。
否则,该请求是针对某种类型的写入的,这意味着需要更新 API 资源,以便创建,删除或编辑功能。 在这种情况下,我们检查所讨论对象的作者(即我们的博客文章 obj.author)是否与发出请求 request.user 的用户匹配。
回到 views.py 文件中,我们应该导入 IsAuthorOrReadOnly,然后我们可以添加 PostDetail 的``permission_classes`。
# posts/views.py from rest_framework import generics from .models import Post from .permissions import IsAuthorOrReadOnly # new from .serializers import PostSerializer class PostList(generics.ListCreateAPIView): queryset = Post.objects.all() serializer_class = PostSerializer class PostDetail(generics.RetrieveUpdateDestroyAPIView): permission_classes = (IsAuthorOrReadOnly,) # new queryset = Post.objects.all() serializer_class = PostSerializer
我们完成了。 让我们测试一下。 导航到“帖子详细信息”页面。 确保您使用帖子的作者超级用户帐户登录。 因此它将在页面的右上角可见。
但是,如果您注销然后使用 testuser 帐户登录,则页面会更改。
由于允许只读权限,因此我们可以查看此页面。 但是,由于自定义的 IsAuthorOrReadOnly 权限类,我们无法发出任何 PUT 或 DELETE 请求。
请注意,通用视图将仅检查对象级权限以获取检索单个模型实例的视图。 如果您需要对列表视图进行对象级过滤(对于实例集合),则需要通过覆盖初始查询集进行过滤。
总结
设置适当的权限是任何 API 的重要组成部分。 作为一般策略,最好设置严格的项目级别权限策略,以使只有经过身份验证的用户才能查看 API。 然后,根据需要在特定的 API 端点上更易于访问视图级别或自定义权限。
