LoginSignup
3
3

More than 3 years have passed since last update.

Django REST frameworkチュートリアル その4.1

Posted at

Object level permissions

前回の記事「Django REST frameworkチュートリアル その4」の続きです。
前回の記事では認証処理を実装しましたが、その課題として以下のものがありました。

トークンを持っていれば他の人のユーザー情報やスニペットの中身を書き換えることができてしまいます。変更や削除などのリクエストを送った人がそのデータのオーナーなのかをチェックしたいです。

はい。ということで、リクエストを送った人が編集したいデータのオーナーであるかのチェックをしたいと思います。

permissions.py

自分でカスタムのパーミッションを作成する際には、BasePermissionを継承してhas_object_permission()メソッドをオーバーライドします。

新規でpermissions.pyを作成して、カスタムパーミッションを実装してみましょう。

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

コメントにある通り、GETHEADOPTIONSメソッドなどの安全なリクエストは誰でも取得できますが、他のメソッドについては、リクエストを送った人とオブジェクトのオーナーが同じでないと認証が通りません。

views.py

あとはviews.pypermission_classesに上で作ったクラスを設定してあげるだけです。

snippets/views.py
from rest_framework.response import Response
from snippets.models import Snippet
from snippets.serializers import SnippetSerializer, UserSerializer
from snippets.permissions import IsOwnerOrReadOnly
from django.contrib.auth.models import User
from rest_framework import generics, permissions


class SnippetList(generics.ListCreateAPIView):
    permission_classes = [permissions.IsAuthenticatedOrReadOnly]
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class SnippetDetail(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [IsOwnerOrReadOnly]
    queryset = Snippet.objects.all()
    serializer_class = SnippetSerializer


class UserList(generics.ListCreateAPIView):
    permission_classes = [permissions.AllowAny]
    queryset = User.objects.all()
    serializer_class = UserSerializer


class UserDetails(generics.RetrieveUpdateDestroyAPIView):
    permission_classes = [IsOwnerOrReadOnly]
    queryset = User.objects.all()
    serializer_class = UserSerializer

テスト

あらかじめユーザーを2名以上作成しておきましょう。
以下のコードでそれぞれのユーザーでアクセストークンを取得します。

curl -X POST -d "grant_type=password&username=<user_name>&password=<password>" -u"<client_id>:<client_secret>" http://localhost:8000/oauth2/token/

そしてあるスニペットに対して2人のアクセストークンでそれぞれリクエストを送ってみてください。

curl -X PATCH -H 'Content-Type:application/json' -H "Authorization: Bearer <your_access_token>" -d '{"code":"This is modified."}' http://localhost:8000/snippets/1/

そうするとスニペットのオーナーに対してはリクエストが通るのに対して、オーナーでないユーザーに対してはリクエストが拒否されるのが確認できるかと思います。

以上でオーナーのチェックは完了です。

3
3
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
3