Lack of dynamic scope handling in TokenHasScope
Closed this issue · 1 comments
birddevelper commented
The Current Limitation
In the current implementation of TokenHasScope, the get_scopes method retrieves the required scopes using this method:
def get_scopes(self, request, view):
try:
return getattr(view, "required_scopes")
except AttributeError:
raise ImproperlyConfigured(
"TokenHasScope requires the view to define the required_scopes attribute"
)This approach assumes a static required_scopes attribute on the view. However, this design doesn't support cases where the required scope changes dynamically such as different scopes for GET, PUT, PATCH, or DELETE methods in RetrieveUpdateDestroyAPIView like following example:
class StudentRetrieveUpdateDestroyAPIView(generics.RetrieveUpdateDestroyAPIView):
permission_classes = [TokenHasScope]
def get_required_scopes(self):
if self.request.method in ["PUT", "PATCH"]:
return ["student_data_update"]
elif self.request.method == "GET":
return ["student_data_read"]
elif self.request.method == "DELETE":
return ["student_data_delete"]Solutions
-
Modifying
TokenHasScopeto support aget_required_scopesmethod in addition to the existingrequired_scopesattribute. The new behavior could be:- Check if the view has a get_required_scopes method.
- If the method exists, call it and use its return value as the required scopes.
- If the method does not exist, fall back to the static required_scopes attribute.
Here’s how the updated get_scopes implementation might look:
def get_scopes(self, request, view):
if hasattr(view, "get_required_scopes"):
return view.get_required_scopes()
try:
return getattr(view, "required_scopes")
except AttributeError:
raise ImproperlyConfigured(
"TokenHasScope requires the view to define either the required_scopes attribute or the get_required_scopes method"
)- Another solution is to adjust
TokenHasScopeto check forget_scopes()in the view, if the view usesScopedResourceMixin, Instead of directly checking for therequired_scopesattribute
n2ygk commented