刚才的错误没有了,但是报了个新的错误:Snippet.owner必须是User实例,给它赋值的是AnonymousUser(匿名用户),导致ValueError了。这个报错是发生这条代码:
serializer.save(owner=self.request.user)也就是说请求访问视图后,进行反序列化了,但是反序列化失败了。非常奇怪!我们的请求中并没有用户信息,正常来说在访问视图的时候就该被拦截了。
给视图添加认证我们需要让API更符合常规,让未认证的用户不能执行视图中的代码。DRF提供了rest_framework .permissions来给视图添加认证:
其中IsAuthenticatedOrReadOnly表示只有认证了才能读写,否则只能读。把它添加到SnippetList和SnippetDetail视图中:
from rest_framework import permissions permission_classes = [permissions.IsAuthenticatedOrReadOnly]再请求试试,刚才的错误没有了,API返回的是需要提供用户凭证:
如果用浏览器打开:8000/snippets/,会发现只有GET方法没有POST,这是因为需要添加DRF登录视图,在tutorial/urls.py中添加rest_framework.urls:
urlpatterns += [ path('api-auth/', include('rest_framework.urls')), ]api-auth/可以自定义。
刷新页面右上角就会出现Log in按钮,登录后就能POST了。
对象级权限为了更细粒度的控制权限,让用户只能编辑自己创建的snippet,新建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新增IsOwnerOrReadOnly权限,继承了permissions.BasePermission,重写了has_object_permission()方法。接着在snippets/views.py中给SnippetDetail加上:
from snippets.permissions import IsOwnerOrReadOnly permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsOwnerOrReadOnly]试下访问其他用户创建的snippet,发现只能查看:
访问自己创建的snippet,可以修改和删除:
以上是官网的示例,我在Postman测试了下,发现超管dongfanger可以创建snippet:
普通用户player也可以创建snippet:
我想让普通用户不能创建,只能超管创建。仿照官网示例,在snippets/permissions.py中添加IsAdminOrReadOnly:
class IsAdminOrReadOnly(permissions.BasePermission): def has_permission(self, request, view): return request.user.is_superuser接着给SnippetList加上:
permission_classes = [permissions.IsAuthenticatedOrReadOnly, IsAdminOrReadOnly]用普通用户尝试创建,提示没有权限:
用超级管理员尝试创建,成功: