| 14 | |
| 15 | |
| 16 | class AuthBearer(BaseHTTPMiddleware): |
| 17 | EXCLUDED_PATHS = [ |
| 18 | "/docs", |
| 19 | "/redoc", |
| 20 | "/openapi.json", |
| 21 | "/auth/login", |
| 22 | "/auth/refresh", |
| 23 | "/auth/signup", |
| 24 | "/auth/re-send-confirm-email", |
| 25 | "/auth/confirm-email", |
| 26 | "/health", |
| 27 | "/ws", |
| 28 | ] |
| 29 | |
| 30 | def __init__(self, app: ASGIApp, user_service: UserService, hash_service: HashService) -> None: |
| 31 | super().__init__(app=app) |
| 32 | self.hash_service = hash_service |
| 33 | self.user_service = user_service |
| 34 | self.bearer_scheme = HTTPBearer(auto_error=False) |
| 35 | self.logger = logging.getLogger(__name__) |
| 36 | |
| 37 | async def dispatch(self, request: Request, call_next: RequestResponseEndpoint) -> Response: |
| 38 | request.state.is_authenticated = False |
| 39 | if request.method == "OPTIONS" or AuthBearer._is_excluded_path(request.url.path): |
| 40 | return await call_next(request) |
| 41 | |
| 42 | authorization = request.headers.get("Authorization") |
| 43 | if not authorization: |
| 44 | raise UnauthorizedException(error_no=ErrorNo.AUTHORIZATION_HEADER_NOT_FOUND, message="Unauthorized!") |
| 45 | |
| 46 | try: |
| 47 | scheme, token = authorization.split(" ", 1) |
| 48 | if scheme.lower() != "bearer": |
| 49 | raise UnauthorizedException(error_no=ErrorNo.AUTHORIZATION_BEARER_FORMAT_ERROR, message="Unauthorized!") |
| 50 | except ValueError as e: |
| 51 | self.logger.error(str(e), exc_info=e) |
| 52 | raise UnauthorizedException(error_no=ErrorNo.AUTHORIZATION_BEARER_INVALID, message="Unauthorized!") |
| 53 | |
| 54 | payload = self.hash_service.verify_token(token) |
| 55 | if not payload: |
| 56 | raise UnauthorizedException( |
| 57 | error_no=ErrorNo.AUTHORIZATION_BEARER_TOKEN_INVALID_OR_EXPIRED, message="Unauthorized!" |
| 58 | ) |
| 59 | |
| 60 | user = await self.user_service.get_by_id(int(payload.subject)) |
| 61 | if not user: |
| 62 | raise UnauthorizedException(error_no=ErrorNo.AUTHORIZATION_USER_NOT_FOUND, message="Unauthorized!") |
| 63 | if user.status != UserStatus.ACTIVE: |
| 64 | raise UnauthorizedException(error_no=ErrorNo.AUTHORIZATION_USER_NOT_ACTIVE, message="Unauthorized!") |
| 65 | if user.session != payload.session: |
| 66 | raise UnauthorizedException(error_no=ErrorNo.AUTHORIZATION_USER_SESSION_INVALID, message="Unauthorized!") |
| 67 | |
| 68 | request.state.user = user |
| 69 | request.state.is_authenticated = True |
| 70 | |
| 71 | return await call_next(request) |
| 72 | |
| 73 | @staticmethod |
nothing calls this directly
no outgoing calls
no test coverage detected