use*_*568 24 python django permissions django-rest-framework
我正在使用Django REST Framework来访问资源"用户".
由于用户信息是个人信息,我不希望GET请求列出系统中的每个用户,除非他们是管理员.
如果用户指定了他们的id,并且他们已登录,我希望他们能够查看他们的详细信息并在需要时修改它们(PUT POST DELETE).
总而言之,对于不是管理员的人,请禁用GET方法,并在查看其信息时允许登录用户使用GET POST DELETE PUT.
所以我创建了自定义权限类:
class UserPermissions(permissions.BasePermission):
"""
Owners of the object or admins can do anything.
Everyone else can do nothing.
"""
def has_permission(self, request, view):
# if admin: True otherwise False
def has_object_permission(self, request, view, obj):
# if request.user is the same user that is contained within the obj then allow
Run Code Online (Sandbox Code Playgroud)
这没用.经过一些调试后,我发现它首先检查has_permission,然后检查has_object_permission.因此,如果我们没有超过第一个障碍GET/user /,那么它甚至不会考虑下一个GET/user/id.
所以总之,有谁知道如何让这个工作?
谢谢 :)
编辑:
我正在使用ModelViewSets,它确实有我所描述的这个问题.
但是,如果使用Detail拆分List功能,则可以为它们分配不同的权限类:
class UserList(generics.ListCreateAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes=(UserPermissionsAll,)
class UserDetail(generics.RetrieveUpdateDestroyAPIView):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes=(UserPermissionsObj,)
class UserPermissionsAll(permissions.BasePermission):
"""
Owners of the object or admins can do anything.
Everyone else can do nothing.
"""
def has_permission(self, request, view):
if request.user.is_staff:
return True
else:
return False
class UserPermissionsObj(permissions.BasePermission):
"""
Owners of the object or admins can do anything.
Everyone else can do nothing.
"""
def has_object_permission(self, request, view, obj):
if request.user.is_staff:
return True
return obj == request.user
Run Code Online (Sandbox Code Playgroud)
wil*_*art 20
我过去使用自定义权限执行此操作并覆盖has_object_permission如下所示:
from rest_framework import permissions
class MyUserPermissions(permissions.BasePermission):
"""
Handles permissions for users. The basic rules are
- owner may GET, PUT, POST, DELETE
- nobody else can access
"""
def has_object_permission(self, request, view, obj):
# check if user is owner
return request.user == obj
Run Code Online (Sandbox Code Playgroud)
您可以执行一些更详细的操作,例如拒绝特定的请求类型(例如,允许对所有用户的GET请求):
class MyUserPermissions(permissions.BasePermission):
def has_object_permission(self, request, view, obj):
# Allow get requests for all
if request.method == 'GET':
return True
return request.user == obj
Run Code Online (Sandbox Code Playgroud)
然后在您的视图中,您告诉它使用权限类:
from my_custom_permissions import MyUserPermissions
class UserView(generics.ListCreateAPIView):
...
permission_classes = (MyUserPermissions, )
...
Run Code Online (Sandbox Code Playgroud)
Tim*_*ick 12
我有类似的需求.让我们称之为我的应用程序x.这就是我想出来的.
首先,把它放在x/viewsets.py:
# viewsets.py
from rest_framework import mixins, viewsets
class DetailViewSet(
mixins.CreateModelMixin,
mixins.RetrieveModelMixin,
mixins.UpdateModelMixin,
mixins.DestroyModelMixin,
viewsets.GenericViewSet):
pass
class ReadOnlyDetailViewSet(
mixins.RetrieveModelMixin,
viewsets.GenericViewSet):
pass
class ListViewSet(
mixins.ListModelMixin,
viewsets.GenericViewSet):
pass
Run Code Online (Sandbox Code Playgroud)
然后在x/permissions.py:
# permissions.py
from rest_framework import permissions
class UserIsOwnerOrAdmin(permissions.BasePermission):
def has_permission(self, request, view):
return request.user and request.user.is_authenticated()
def check_object_permission(self, user, obj):
return (user and user.is_authenticated() and
(user.is_staff or obj == user))
def has_object_permission(self, request, view, obj):
return self.check_object_permission(request.user, obj)
Run Code Online (Sandbox Code Playgroud)
然后在x/views.py:
# views.py
from x.viewsets import DetailViewSet, ListViewSet
from rest_framework import permissions
class UserDetailViewSet(DetailViewSet):
queryset = User.objects.all()
serializer_class = UserDetailSerializer
permission_classes = (UserIsOwnerOrAdmin,)
class UserViewSet(ListViewSet):
queryset = User.objects.all()
serializer_class = UserSerializer
permission_classes (permissions.IsAdminUser,)
Run Code Online (Sandbox Code Playgroud)
顺便说一下,请注意您可以为这两个视图集使用不同的序列化程序,这意味着您可以在list视图中显示与视图中不同的属性retrieve!例如:
# serializers.py
class UserSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('username', 'url',)
class UserDetailSerializer(serializers.HyperlinkedModelSerializer):
class Meta:
model = User
fields = ('url', 'username', 'groups', 'profile', 'password',)
write_only_fields = ('password',)
Run Code Online (Sandbox Code Playgroud)
然后在x/urls.py:
# urls.py
from x import views
from rest_framework import routers
router = routers.DefaultRouter()
router.register(r'users', views.UserViewSet)
router.register(r'users', views.UserDetailViewSet)
...
Run Code Online (Sandbox Code Playgroud)
我有点意外地router接受了相同的模式两次,但它似乎确实有效.
警告:我已通过API浏览器确认这一切都有效,但我还没有尝试通过API进行更新.
对于绊脚石,对象级别权限限制下的文档说:
For performance reasons the generic views will not automatically apply object level permissions to each instance in a queryset when returning a list of objects.
Run Code Online (Sandbox Code Playgroud)
因此,详细信息视图将起作用,但对于列表,您需要针对当前用户进行过滤.
对于@ will-hart的回答还有一件事.
在DRF3文档中,
注意:只有在视图级别has_permission检查已通过时才会调用实例级别的has_object_permission方法
因此,has_permission应指定使用has_object_permission.
from rest_framework import permissions
class MyUserPermissions(permissions.BasePermission):
def has_permission(self, request, view):
return True
def has_object_permission(self, request, view, obj):
return request.user == obj
Run Code Online (Sandbox Code Playgroud)
但是,当用户尝试获取用户列表时,上述代码将授予任何人权限.在这种情况下,最好是根据而action不是给予许可HTTP method.
from rest_framework import permissions
def has_permission(self, request, view):
if request.user.is_superuser:
return True
elif view.action == 'retrieve':
return True
else:
return False
def has_object_permission(self, request, view, obj):
if request.user.is_superuser:
return True
elif view.action == 'retrieve':
return obj == request.user or request.user.is_staff
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
22867 次 |
| 最近记录: |