Coverage for src/lexigram/web/security/shortcuts.py: 0%
10 statements
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
« prev ^ index » next coverage.py v7.15.4, created at 2026-08-25 04:37 +0800
1"""Shorthand guard decorators for common authorization patterns.
3Provides concise aliases over :func:`~lexigram.web.security.guards.use_guards`
4for the most frequent use cases.
6Example::
8 from lexigram.web import guard, roles
10 @guard(AuthGuard)
11 async def protected_route(self): ...
13 @roles("admin", "moderator")
14 async def admin_route(self): ...
15"""
17from __future__ import annotations
19from typing import Any
21from lexigram.web.security.guards import RoleGuard, use_guards
24def guard(*guard_classes: type[Any] | Any) -> Any:
25 """Concise alias for :func:`use_guards`.
27 Attaches one or more guards to a route handler or controller class.
28 Guards are executed in order; the first failure returns a 403 response.
30 Args:
31 *guard_classes: GuardProtocol classes or instances to apply.
33 Returns:
34 Decorator that attaches guards to the target.
36 Example::
38 @guard(AuthGuard)
39 async def profile(self): ...
41 @guard(AuthGuard, PermissionGuard("users:write"))
42 async def create_user(self): ...
43 """
44 return use_guards(*guard_classes)
47def roles(*role_names: str, authorizer: Any | None = None) -> Any:
48 """Restrict a handler to users that have at least one of the given roles.
50 The ``authorizer`` dependency must be injected.
52 Args:
53 *role_names: Required role names; user must hold at least one.
54 authorizer: **Required** AuthorizerProtocol instance, typically resolved
55 from the container during application startup.
57 Returns:
58 Decorator that attaches a :class:`RoleGuard` to the target.
60 Example::
62 authorizer = await container.resolve(AuthorizerProtocol)
64 @roles("admin", authorizer=authorizer)
65 async def admin_only(self): ...
67 @roles("admin", "moderator", authorizer=authorizer)
68 async def manage_content(self): ...
69 """
70 if authorizer is None:
71 raise ValueError(
72 "authorizer parameter is required. Inject it from the container at startup."
73 )
74 return use_guards(RoleGuard(*role_names, authorizer=authorizer))
77__all__ = ["guard", "roles"]