Django Rest framework Permissions
18353 ワード
今日は久しぶりにDjango Postingをしました!インフラ面の問題や社内業務の終了、文書化に関わることが多く、特徴開発ができず、今になってやっと特徴開発を開始しました.
今日議論する内容はDjango Rest FrameworkのPermission機能です.
私が新しく実現した機能はLMS組織とクラス管理システムです.組織およびクラス管理システムの場合、特定のAPIを呼び出すには、特定の「権限」が必要です.「権限」は、次のようにモデリングされています.
特定のユーザーは、「聖約」、「組織」または「EasyClass」と呼ばれるモデルにロールを持ちます.ロールです.ロールは、複数の特権、すなわち権限で構成されます.
次に、特定のAPI内のどのユーザが特定の権限を持っているかを確認するためにコードを作成しようとします.既存の旧式コードもそうですが、簡単に考えれば構築できるコードは以下の通りです.
この場合、Django Rest Frameworkは権限機能の導入を試みることができる.Django権限について説明します.
公式ファイルに基づいてpermissionsは、認証またはアクセス拒否のリクエストを決定します.そして常にviewの起点で検証します.
Rest Frameworkでpermissionsを使用するには、APIViewを基準にpermission classesで必要な権限を指定するだけです.
check permissionsロジックから見ると、has permissionはすべての権限に対して呼び出され、ある権限が満たされない場合、permission deferred処理が行われる.このときhas permissionは簡単にFalse,Trueを返す.
さらにcheck permissionsロジックはmethod handlerを呼び出す前に呼び出される.
すなわち、APIViewを継承したインプリメンテーションでpermission classes配列で使用するクラスのみが指定されている場合、残りのクラスは親クラスにPermissionクラスオブジェクトを作成し、クラスのhas permission()関数で権限をチェックします.
以下は基本的なBasePermissionクラスです.
今初めて帰って、私は権限管理モデルを設計して、モデルの結果に基づいてどのユーザーがどのテナント、組織、クラスなどに対して特定の権限を持っているかを検証しました.has permission,has object permissionではhas object permissionが実現されている.権限を検証するためには、リクエスト中のuserのほかに他のモデルが必要であるためである.
しかし、このDjango Restフレームワークで提供されているPermissionを利用して開発することで、Permission関連のコードを集約し、ソフトウェアの凝集力を向上させることができると思います.特に私が構成しているLMSシステムには、様々な権限が存在し、これらの権限検証の論理は一つの場所に集中することができ、permission classesを通じてこのAPIを呼び出すために必要な権限は何なのか、一目瞭然です.
そこで、今回LMSシステムの権限検証ロジックを開発し、Django Rest Frameworkが提供するPermission機能を積極的に利用する予定です.
他の開発者も私に似たような要求やDjango RestFrameworkで「権限」に関連するものを管理する必要がある場合は、権限機能の使用をお勧めします.
今日議論する内容はDjango Rest FrameworkのPermission機能です.
私が新しく実現した機能はLMS組織とクラス管理システムです.組織およびクラス管理システムの場合、特定のAPIを呼び出すには、特定の「権限」が必要です.「権限」は、次のようにモデリングされています.
特定のユーザーは、「聖約」、「組織」または「EasyClass」と呼ばれるモデルにロールを持ちます.ロールです.ロールは、複数の特権、すなわち権限で構成されます.
次に、特定のAPI内のどのユーザが特定の権限を持っているかを確認するためにコードを作成しようとします.既存の旧式コードもそうですが、簡単に考えれば構築できるコードは以下の通りです.
class CreateView(generics.ListCreateAPIView):
def perform_create(self, serializer):
if self.request.user.has_some_permission():
return serializer.save(user=self.request.user)
raise PermissionDenied()
しかし、このようにコードを記述すると、チェック権限のすべてのビューにブランチ文が含まれ、チェック権限の論理はuserというモデルのドメイン論理に含まれます.もちろん、これも良い方法かもしれませんが、ユーザーというドメインは通常多くのことをしますが、システムに存在する様々な権限に対して、論理を使うのはよくありません.この場合、Django Rest Frameworkは権限機能の導入を試みることができる.Django権限について説明します.
公式ファイルに基づいてpermissionsは、認証またはアクセス拒否のリクエストを決定します.そして常にviewの起点で検証します.
Rest Frameworkでpermissionsを使用するには、APIViewを基準にpermission classesで必要な権限を指定するだけです.
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)
では、APIViewは、指定したpermission classesの論理をどのように処理するかを表示します.class APIView(View):
# The following policies may be set at either globally, or per-view.
renderer_classes = api_settings.DEFAULT_RENDERER_CLASSES
parser_classes = api_settings.DEFAULT_PARSER_CLASSES
authentication_classes = api_settings.DEFAULT_AUTHENTICATION_CLASSES
throttle_classes = api_settings.DEFAULT_THROTTLE_CLASSES
permission_classes = api_settings.DEFAULT_PERMISSION_CLASSES
...
def get_permissions(self):
"""
Instantiates and returns the list of permissions that this view requires.
"""
return [permission() for permission in self.permission_classes]
...
def check_permissions(self, request):
"""
Check if the request should be permitted.
Raises an appropriate exception if the request is not permitted.
"""
for permission in self.get_permissions():
if not permission.has_permission(request, self):
self.permission_denied(
request,
message=getattr(permission, "message", None),
code=getattr(permission, "code", None),
...
def initial(self, request, *args, **kwargs):
"""
Runs anything that needs to occur prior to calling the method handler.
"""
self.format_kwarg = self.get_format_suffix(**kwargs)
# Perform content negotiation and store the accepted info on the request
neg = self.perform_content_negotiation(request)
request.accepted_renderer, request.accepted_media_type = neg
# Determine the API version, if versioning is in use.
version, scheme = self.determine_version(request, *args, **kwargs)
request.version, request.versioning_scheme = version, scheme
# Ensure that the incoming request is permitted
self.perform_authentication(request)
self.check_permissions(request)
self.check_throttles(request)
APIViewのデフォルトにはpermission classes変数があり、デフォルト値はDjango設定で設定した値です.検証プロセスは、Default値を使用してAPI全体に適用できます.(good)check permissionsロジックから見ると、has permissionはすべての権限に対して呼び出され、ある権限が満たされない場合、permission deferred処理が行われる.このときhas permissionは簡単にFalse,Trueを返す.
さらにcheck permissionsロジックはmethod handlerを呼び出す前に呼び出される.
すなわち、APIViewを継承したインプリメンテーションでpermission classes配列で使用するクラスのみが指定されている場合、残りのクラスは親クラスにPermissionクラスオブジェクトを作成し、クラスのhas permission()関数で権限をチェックします.
以下は基本的なBasePermissionクラスです.
class BasePermission(metaclass=BasePermissionMetaclass):
"""
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
上記のBasePermissionを継承して実装できる権限をカスタマイズします.今初めて帰って、私は権限管理モデルを設計して、モデルの結果に基づいてどのユーザーがどのテナント、組織、クラスなどに対して特定の権限を持っているかを検証しました.has permission,has object permissionではhas object permissionが実現されている.権限を検証するためには、リクエスト中のuserのほかに他のモデルが必要であるためである.
class OrganizationEditPermission:
def has_object_permission(self, request, view, obj: Tenant):
_ = view
user = request.user
if not bool(user and user.is_authenticated):
return False
if not (
Privilege.objects.filter(name=Privilege.Type.ORGANIZATION_EDIT)
.filter(role__user=user)
.filter(role__roleowner__tenant=obj)
.exists()
):
**return False
return True**
実装されたクラスは、Viewで次のように使用されます.class OrganizationView(generics.CreateAPIView):
serializer_class = OrganizationCreateSerializer
permission_classes = [OrganizationEditPermission]
@transaction.atomic
def perform_create(self, serializer):
data = serializer.data
# if permission denied raise Error.
self.check_object_permissions(self.request, data["tenant"])
初めてコードを作成する場合、if文で権限をチェックするのは見たくないので、permission classesでCustom Permissionを定義するだけで余分なコードは必要ないと思いますが、テナントや組織などのユーザーのほかに、他のモデルの参照も必要なので、check object permissionsで明示的に権限チェックを行わないわけにはいきません.しかし、このDjango Restフレームワークで提供されているPermissionを利用して開発することで、Permission関連のコードを集約し、ソフトウェアの凝集力を向上させることができると思います.特に私が構成しているLMSシステムには、様々な権限が存在し、これらの権限検証の論理は一つの場所に集中することができ、permission classesを通じてこのAPIを呼び出すために必要な権限は何なのか、一目瞭然です.
そこで、今回LMSシステムの権限検証ロジックを開発し、Django Rest Frameworkが提供するPermission機能を積極的に利用する予定です.
他の開発者も私に似たような要求やDjango RestFrameworkで「権限」に関連するものを管理する必要がある場合は、権限機能の使用をお勧めします.
Reference
この問題について(Django Rest framework Permissions), 我々は、より多くの情報をここで見つけました https://velog.io/@hoonki/Django-Rest-framework-Permissionsテキストは自由に共有またはコピーできます。ただし、このドキュメントのURLは参考URLとして残しておいてください。
Collection and Share based on the CC Protocol