Aller au contenu

Auth

Backend

SithModelBackend

Bases: ModelBackend

Custom auth backend for the Sith.

In fact, it's the exact same backend as django.contrib.auth.backend.ModelBackend, with the exception that group permissions are fetched slightly differently. Indeed, django tries by default to fetch the permissions associated with all the django.contrib.auth.models.Group of a user ; however, our User model overrides that, so the actual linked group model is core.models.Group. Instead of having the relation auth_perm --> auth_group <-- core_user, we have auth_perm --> auth_group <-- core_group <-- core_user.

Thus, this backend make the small tweaks necessary to make our custom models interact with the django auth.

Mixins

CanCreateMixin(*args, **kwargs)

Bases: View

Protect any child view that would create an object.

Raises:

Type Description
PermissionDenied

If the user has not the necessary permission to create the object of the view.

Source code in core/auth/mixins.py
def __init__(self, *args, **kwargs):
    warnings.warn(
        f"{self.__class__.__name__} is deprecated and should be replaced "
        "by other permission verification mecanism.",
        DeprecationWarning,
        stacklevel=2,
    )
    super().__init__(*args, **kwargs)

CanEditMixin

Bases: GenericContentPermissionMixinBuilder

Ensure the user has permission to edit this view's object.

Raises:

Type Description
PermissionDenied

if the user cannot edit this view's object.

CanViewMixin

Bases: GenericContentPermissionMixinBuilder

Ensure the user has permission to view this view's object.

Raises:

Type Description
PermissionDenied

if the user cannot edit this view's object.

FormerSubscriberMixin

Bases: AccessMixin

Check if the user was at least an old subscriber.

Raises:

Type Description
PermissionDenied

if the user never subscribed.

PermissionOrAuthorRequiredMixin

Bases: PermissionRequiredMixin

Require that the user has the required perm or is the object author.

This mixin can be used in combination with DetailView, or another base class that implements the get_object method.

Example

In the following code, a user will be able to edit news if he has the com.change_news permission or if he tries to edit his own news :

class NewsEditView(PermissionOrAuthorRequiredMixin, DetailView):
    model = News
    author_field = "author"
    permission_required = "com.change_news"

This is more or less equivalent to :

class NewsEditView(PermissionOrAuthorRequiredMixin, DetailView):
    model = News

    def dispatch(self, request, *args, **kwargs):
        self.object = self.get_object()
        if not (
            user.has_perm("com.change_news")
            or self.object.author == request.user
        ):
            raise PermissionDenied
        return super().dispatch(request, *args, **kwargs)

can_edit_prop(obj, user)

Can the user edit the properties of the object.

Parameters:

Name Type Description Default
obj Any

Object to test for permission

required
user User

core.models.User to test permissions against

required

Returns:

Type Description
bool

True if user is authorized to edit object properties else False

Example
if not can_edit_prop(self.object ,request.user):
    raise PermissionDenied
Source code in core/auth/mixins.py
def can_edit_prop(obj: Any, user: User) -> bool:
    """Can the user edit the properties of the object.

    Args:
        obj: Object to test for permission
        user: core.models.User to test permissions against

    Returns:
        True if user is authorized to edit object properties else False

    Example:
        ```python
        if not can_edit_prop(self.object ,request.user):
            raise PermissionDenied
        ```
    """
    return obj is None or user.is_owner(obj)

can_edit(obj, user)

Can the user edit the object.

Parameters:

Name Type Description Default
obj Any

Object to test for permission

required
user User

core.models.User to test permissions against

required

Returns:

Type Description
bool

True if user is authorized to edit object else False

Example
if not can_edit(self.object, request.user):
    raise PermissionDenied
Source code in core/auth/mixins.py
def can_edit(obj: Any, user: User) -> bool:
    """Can the user edit the object.

    Args:
        obj: Object to test for permission
        user: core.models.User to test permissions against

    Returns:
        True if user is authorized to edit object else False

    Example:
        ```python
        if not can_edit(self.object, request.user):
            raise PermissionDenied
        ```
    """
    if obj is None or user.can_edit(obj):
        return True
    return can_edit_prop(obj, user)

can_view(obj, user)

Can the user see the object.

Parameters:

Name Type Description Default
obj Any

Object to test for permission

required
user User

core.models.User to test permissions against

required

Returns:

Type Description
bool

True if user is authorized to see object else False

Example
if not can_view(self.object ,request.user):
    raise PermissionDenied
Source code in core/auth/mixins.py
def can_view(obj: Any, user: User) -> bool:
    """Can the user see the object.

    Args:
        obj: Object to test for permission
        user: core.models.User to test permissions against

    Returns:
        True if user is authorized to see object else False

    Example:
        ```python
        if not can_view(self.object ,request.user):
            raise PermissionDenied
        ```
    """
    if obj is None or user.can_view(obj):
        return True
    return can_edit(obj, user)

API Permissions

Permission classes to be used within ninja-extra controllers.

Some permissions are global (like IsInGroup or IsRoot), and some others are per-object (like CanView or CanEdit).

Example
# restrict all the routes of this controller
# to subscribed users
@api_controller("/foo", permissions=[IsSubscriber])
class FooController(ControllerBase):
    @route.get("/bar")
    def bar_get(self):
        # This route inherits the permissions of the controller
        # ...

    @route.bar("/bar/{bar_id}", permissions=[CanView])
    def bar_get_one(self, bar_id: int):
        # per-object permission resolution happens
        # when calling either the `get_object_or_exception`
        # or `get_object_or_none` method.
        bar = self.get_object_or_exception(Counter, pk=bar_id)

        # you can also call the `check_object_permission` manually
        other_bar = Counter.objects.first()
        self.check_object_permissions(other_bar)

        # ...

    # This route is restricted to counter admins and root users
    @route.delete(
        "/bar/{bar_id}",
        permissions=[IsRoot | IsInGroup(settings.SITH_GROUP_COUNTER_ADMIN_ID)
    ]
    def bar_delete(self, bar_id: int):
        # ...

CanAccessLookup = IsOldSubscriber | IsRoot | IsLoggedInCounter module-attribute

IsInGroup(group_pk)

Bases: BasePermission

Check that the user is in the group whose primary key is given.

Source code in core/auth/api_permissions.py
def __init__(self, group_pk: int):
    self._group_pk = group_pk

IsRoot

Bases: BasePermission

Check that the user is root.

IsSubscriber

Bases: BasePermission

Check that the user is currently subscribed.

IsOldSubscriber

Bases: BasePermission

Check that the user has at least one subscription in its history.

CanView

Bases: BasePermission

Check that this user has the permission to view the object of this route.

Wrap the user.can_view(obj) method. To see an example, look at the example in the module docstring.

CanEdit

Bases: BasePermission

Check that this user has the permission to edit the object of this route.

Wrap the user.can_edit(obj) method. To see an example, look at the example in the module docstring.

IsOwner

Bases: BasePermission

Check that this user owns the object of this route.

Wrap the user.is_owner(obj) method. To see an example, look at the example in the module docstring.

IsLoggedInCounter

Bases: BasePermission

Check that a user is logged in a counter.