Coverage for src/lexigram/web/security/context.py: 65%

26 statements  

« prev     ^ index     » next       coverage.py v7.15.4, created at 2026-08-25 04:37 +0800

1"""Security context for storing authentication state.""" 

2 

3from __future__ import annotations 

4 

5from dataclasses import dataclass, field 

6from typing import TYPE_CHECKING, Any 

7 

8if TYPE_CHECKING: 

9 from starlette.requests import Request 

10 

11 

12@dataclass 

13class SecurityContext: 

14 """ 

15 Security context containing authentication and authorization info. 

16 

17 Stored in request.state.security for access in guards and handlers. 

18 """ 

19 

20 user: Any | None = None 

21 roles: list[str] = field(default_factory=list) 

22 permissions: list[str] = field(default_factory=list) 

23 metadata: dict[str, Any] = field(default_factory=dict) 

24 

25 @property 

26 def is_authenticated(self) -> bool: 

27 """Check if user is authenticated.""" 

28 return self.user is not None 

29 

30 def has_role(self, role: str) -> bool: 

31 """Check if user has specific role.""" 

32 return role in self.roles 

33 

34 def has_permission(self, permission: str) -> bool: 

35 """Check if user has specific permission.""" 

36 return permission in self.permissions 

37 

38 def has_any_role(self, *roles: str) -> bool: 

39 """Check if user has any of the specified roles.""" 

40 return any(role in self.roles for role in roles) 

41 

42 def has_all_roles(self, *roles: str) -> bool: 

43 """Check if user has all of the specified roles.""" 

44 return all(role in self.roles for role in roles) 

45 

46 

47def get_security_context(request: Request) -> SecurityContext: 

48 """ 

49 Get or create security context from request state. 

50 

51 Args: 

52 request: The HTTP request 

53 

54 Returns: 

55 Security context instance 

56 """ 

57 if not hasattr(request.state, "security"): 

58 request.state.security = SecurityContext() 

59 

60 ctx: SecurityContext = request.state.security 

61 return ctx 

62 

63 

64__all__ = ["SecurityContext", "get_security_context"]