1

I am using django-ninja and django-ninja-extra for an api.

Currently I have some Schema like so

from ninja import schema
class SchemaA(Schema)
   fruit_id: int
   other_data: str

and a controller like so

class HasFruitAccess(permissions.BasePermission):
    def has_permission(self, request: HttpRequest, controller: ControllerBase):
        controller.context.compute_route_parameters()
        data = controller.context.kwargs.get('data')
        fruit = Fruit.objects.get(pk=data.fruit_id)
        if fruit.user.pk == request.user.pk:
           return True
        return False

@api_controller("/fruits", permissions=[IsAuthenticated])
class FruitController(ControllerBase):
    """Controller class for test runs."""

    @route.post("/", auth=JWTAuth(), response=str, permissions=[HasFruitAccess()])
    def do_fruity_labour(self, data: SchemaA) -> str:
       #Check fruit exists.
       fruit = get_object_or_404(Fruit, data.fruit_id)
       #do work
       return "abc"

And a model like

class Fruit(models.Model):
   user = models.ForeignKey(User)
   ...

What I wanted to do here was check the user is related to the fruit and then we authorize them to do whatever on this object. Is this a good idea, is this best practice or is it better to just validate in the api route itself? Because permissions will obviously run before we check if fruit is even a valid object in the db so I might be trying to "authorize" a user with invalid data. How can one go about authorizing users for a specific api route which relies on db models through permissions (I would prefer it if I could use permissions since I can reuse it for multiple routes or even controllers easily) or maybe this approach isn't what should be done?

Was going off https://eadwincode.github.io/django-ninja-extra/api_controller/api_controller_permission/#basic-route-context-usage

1 Answer 1

1

You’re mixing validation and authorization. Permissions in Ninja run before schema validation, so data.fruit_id isn’t guaranteed to exist or be valid yet, that’s why this pattern fails.

If you want to keep reusability, you’ve got two clean options:

  1. Do the DB check inside the route, after validation, safer, avoids wasted queries on bad input.

  2. Or write a decorator or mixin that runs after request parsing, not as a permission class.

In short: using DB objects inside has_permission() isn’t best practice. Permissions should only check request/user context, not depend on unvalidated input.

Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.