Skip to content

Composite Permission Checker

composite_permission_checker

Composite permission checker with OR logic.

CompositePermissionChecker

Bases: PermissionChecker[PermissionCheckContext]

Combines multiple PermissionChecker instances with OR logic.

Class Type Parameters:

Name Bound or Constraints Description Default
PermissionCheckContext

The application-defined context for permission checks.

required
Example
class User:
    def __init__(self, roles: set[Permission]) -> None:
        self.roles = roles


class ReadChecker(PermissionChecker[User]):
    async def check(self, context: User, permission: Permission) -> bool:
        return permission == Permission.READ


class WriteChecker(PermissionChecker[User]):
    async def check(self, context: User, permission: Permission) -> bool:
        return permission == Permission.WRITE


composite = CompositePermissionChecker([ReadChecker(), WriteChecker()])
user = User(roles={Permission.READ})
granted = await composite.check(user, Permission.READ)
Source code in src/forging_blocks/domain/permissions/composite_permission_checker.py
class CompositePermissionChecker[PermissionCheckContext](PermissionChecker[PermissionCheckContext]):
    """Combines multiple `PermissionChecker` instances with OR logic.

    Type Args:
        PermissionCheckContext: The application-defined context for permission checks.

    Example:
        ```python
        class User:
            def __init__(self, roles: set[Permission]) -> None:
                self.roles = roles


        class ReadChecker(PermissionChecker[User]):
            async def check(self, context: User, permission: Permission) -> bool:
                return permission == Permission.READ


        class WriteChecker(PermissionChecker[User]):
            async def check(self, context: User, permission: Permission) -> bool:
                return permission == Permission.WRITE


        composite = CompositePermissionChecker([ReadChecker(), WriteChecker()])
        user = User(roles={Permission.READ})
        granted = await composite.check(user, Permission.READ)
        ```
    """

    __match_args__ = ("_checkers",)

    def __init__(self, checkers: list[PermissionChecker[PermissionCheckContext]]) -> None:
        self._checkers = checkers

    async def check(self, context: PermissionCheckContext, permission: Permission) -> bool:
        for checker in self._checkers:
            if await checker.check(context, permission):
                return True
        return False