#なぜ書こうと思ったか
Djangoが好きでプライベートで色々と触っているのですが、QiitaにDjango周りの記事はそれなりにあってもDjango REST Framework(以下DRF)周りの記事が少ない・・・(この記事を書いている段階で159件)
とても強力なフレームワークであり、かつフロントエンドとサーバーサイドを分割して開発するのが一般的になってきている現状で、DRFはとても魅力的な選択肢の一つであると思います。
一方で、日本語の記事や技術書が少なく、英語のドキュメントを読むことが必須になると英語ができない方からするととっつきにくい印象を与えてしまうのではないかと思います。
とりわけ初心者からすると日本語ですら理解できないような内容を英語で書かれてもなぁ・・となりがちだと思うので書きました。
#DRFのPermission
アクセス制御に関する領域です。
Authentication or identification by itself is not usually sufficient to gain access to information or code. For that, the entity requesting access must have authorization.
Apple Developer Documentation
Appleのデベロッパーのドキュメントにあるように、一般的には認証や識別のみでは情報やコードにアクセスすることに対して十分ではなく、アクセスを要求するエンティティには権限が必要という考えがあります。
このDRFのPermissionはviewの開始時に実行され、権限チェックでは通常、request.user
、及び、request.auth
プロパティの認証情報を使ってリクエストを許可するかを決定します。
#権限の決定方法
DRFの権限は常に権限クラスのリストとして定義されます。
viewの本体を実行する前にリスト内の各権限がチェックされ、それに失敗した場合はexceptions.PermissionDenied
の例外が発生し、本体の実行はなくなります。
DRFの権限はまた、オブジェクトレベルの権限もサポートし、この権限はユーザーが特定のオブジェクト(通常はmodel)に対しての操作が許可されるかどうかを決定するために使われます。
自身でviewを作成し、それにオブジェクトレベルの権限を適用する場合、もしくはget_object
ジェネリックビューでメソッドをオーバーライドする場合には.check_object_permissions(request,obj)
viewを取得した時点でviewのメソッドを呼び出す必要があります。
そうすると、viewが適切な権限を持つ場合はそのまま続行され、権限を所有していない場合にはPermissionDenied
もしくはNotAuthenticated
の例外が返されます。
#設定方法
デフォルトの許可ポリシーの設定はDEFAULT_PERMISSION_CLASSES
を使って設定します。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.IsAuthenticated',
)
}
仮に指定しない場合はAlloWAny
を使います。
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': (
'rest_framework.permissions.AllowAny',
)
}
APIViewクラスベースのviewを使ってviewごと、viewsetごとに認証の範囲を設定することもできます。
from rest_framework.permissions import IsAuthenticated
from rest_framework.response import Response
from rest_framework.views import APIView
class ExampleView(APIView):
permission_classes = (IsAuthenticated,)
def get(self, request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
もう一つの書き方として、@api_viewデコレーターを用いて関数ベースのviewを書いている場合はこうなります。
@api_view('GET')
@permission_classes((IsAuthenticated, ))
def example_view(request, format=None):
content = {
'status': 'request was permitted'
}
return Response(content)
#APIリファレンス
##AllowAny
AllowAnyクラスは要求が認証されていようがされていまいが無制限のアクセスを許可します。
アクセス許可の設定に空のリスト、もしくはタプルを使っても同じような結果になるため、厳密に言えば必要ありませんが、意図を明示的にするために使うと便利です。
##IsAuthenticated
IsAuthenticatedクラスは任意の認証されていないユーザーを拒否し、それ以外の権限を許可します。
APIに登録済みのユーザーのみがアクセスできるようにする場合に使われます。
##IsAdminUser
IsAdminUserクラスはuser.is_staff
がTrue
となっている場合以外の全てのユーザーを拒否します。
##IsAuthenticatedOrReadOnly
IsAuthenticatedOrReadOnlyクラスは認証されたユーザーが任意の要求を実行できるようになります。
権限がないユーザーのリクエストはリクエストメソッドがGET
、HEAD
またはOPTIONS
などの安全なメソッドである場合のみに限定されます。
APIで匿名ユーザーに読み取り権限を許可し、認証済みのユーザーに対して書き込み権限を有するという時に適しています。
##DjangoModelPermissions
DjangoModelPermissionsではDjangoの標準モデルであるdjango.contrib.auth
のアクセス許可に紐づけられています。
.queryset
プロパティが設定されているviewにのみ適用する必要があり、ユーザーが認証され、関連するモデル権限が割り当てられている場合に承認されます。
例として、
-
POST
リクエストにはユーザーがadd
モデルに対する権限が必要 -
PUT
とPATCH
リクエストにはchange
モデルに対する権限が必要 -
DELETE
リクエストにはdelete
モデルに対する権限が必要
となっています。
また、デフォルトの動作を上書きしてカスタムモデルの権限をサポートすることもでき、例えばviewにGET
リクエストの権限を含めることもできます。
オーバーライドされたget_query()
メソッドを使用する場合、queryset
属性を含まない可能性があります。この場合、viewを以下のように必須のquerset
でマークすることが推奨されています。
queryset = User.objects.none() #DjangoModelPermissionsに必要
##DjangoModelPermissionsOrAnonReadOnly
上のDjangoModelPermissions
に似ていますが、こちらでは認証されていないユーザーがAPIに対して読み取り専用のアクセスをすることができます。
##DjangoObjectPermissions
モデルに対してオブジェクトごとのパーミッションを許可するDjangoの標準オブジェクトパーミッションクラスと連携しています。
もし使用する場合はdjango-guardian
などのオブジェクトレベルのパーミッションをサポートするパーミッションバックエンドを追加する必要があります。
DjangoObjectPermissions
はdjango-guardian
パッケージを必要とはせず、他のオブジェクトレベルのバックエンドも同様にサポートする必要があることには注意してください。
DjangoModelPermissions
と同様に、この権限は.queryset
を持つviewにのみ適用する必要があり、ユーザーが認証され、オブジェクトの権限と関連するモデルの権限を割り当てられている場合にのみ承認されます。
加えて、'DjangoModelPermissions'をオーバーライドどすることでカスタムモデルの権限を使用できます。
##TokenHasReadWriteScope
OAuthAuthentication
および、OAuth2Authentication
クラスのいずれかで使用することを目的としています。
認証されたトークンが読み取り権限が割り当てられている場合にGET
、OPTIONS
またはHEAD
のような安全なメソッドに限って許可されます。
#カスタム権限
カスタム権限を実装するBasePermission
には次のメソッドいずれか、または両方をオーバーライドして実装します。
.has_permission(self,request,view)
.has_object_permission(self,request,view,obj)
リクエストに対してアクセス権を割り当てる場合にはメソッドはTrue
を返し、それ以外はFalse
を返します。
また、リクエストが読み取り操作か書き込み操作であるかをテストする必要がある場合は、以下のようにSAFE_METHODS
を含むタプルである定数に対して、GET
、OPTIONS
、HEAD
のようなリクエストメソッドをチェックする必要があります。
if request.method in permissions.SAFE_METHODS:
# Check permissions for read-only request
else:
# Check permissions for write request
#リファレンス
Django REST Framework