fix(workspace): validate Keycloak JWT for production auth
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
parent
a483b47369
commit
a846b3e7f1
@ -22,14 +22,22 @@ class Settings(BaseSettings):
|
||||
auth_required: bool = True
|
||||
entitlement_stub: bool = True
|
||||
keycloak_enabled: bool = True
|
||||
keycloak_server_url: str = "http://localhost:8080"
|
||||
keycloak_public_url: str = ""
|
||||
keycloak_realm: str = "superapp"
|
||||
keycloak_server_url: str = Field(default="http://localhost:8080", validation_alias="KEYCLOAK_SERVER_URL")
|
||||
keycloak_public_url: str = Field(default="", validation_alias="KEYCLOAK_PUBLIC_URL")
|
||||
keycloak_realm: str = Field(default="superapp", validation_alias="KEYCLOAK_REALM")
|
||||
jwt_algorithm: str = "RS256"
|
||||
jwt_audience: str = "account"
|
||||
jwt_verify_signature: bool = True
|
||||
cors_origins: str = "http://localhost:3000,http://127.0.0.1:3000"
|
||||
|
||||
@property
|
||||
def keycloak_public_base(self) -> str:
|
||||
return (self.keycloak_public_url or self.keycloak_server_url).rstrip("/")
|
||||
|
||||
@property
|
||||
def keycloak_public_realm_url(self) -> str:
|
||||
return f"{self.keycloak_public_base}/realms/{self.keycloak_realm}"
|
||||
|
||||
@property
|
||||
def cors_origin_list(self):
|
||||
return [x.strip() for x in self.cors_origins.split(",") if x.strip()]
|
||||
|
||||
@ -1,16 +1,34 @@
|
||||
from functools import lru_cache
|
||||
|
||||
from fastapi import Depends
|
||||
from fastapi.security import HTTPAuthorizationCredentials, HTTPBearer
|
||||
|
||||
from app.core.config import settings
|
||||
from shared.auth import JWTSettings, JWTValidator
|
||||
from shared.exceptions import UnauthorizedError
|
||||
from shared.security import CurrentUser
|
||||
|
||||
bearer = HTTPBearer(auto_error=False)
|
||||
|
||||
|
||||
@lru_cache
|
||||
def get_jwt_validator() -> JWTValidator:
|
||||
return JWTValidator(
|
||||
JWTSettings(
|
||||
keycloak_enabled=settings.keycloak_enabled,
|
||||
keycloak_server_url=settings.keycloak_server_url,
|
||||
keycloak_realm=settings.keycloak_realm,
|
||||
jwt_algorithm=settings.jwt_algorithm,
|
||||
jwt_audience=settings.jwt_audience,
|
||||
jwt_verify_signature=settings.jwt_verify_signature,
|
||||
jwt_issuer=settings.keycloak_public_realm_url,
|
||||
)
|
||||
)
|
||||
|
||||
|
||||
async def get_current_user(credentials: HTTPAuthorizationCredentials | None = Depends(bearer)):
|
||||
if not settings.auth_required:
|
||||
return CurrentUser(user_id="test-user", username="test", roles=["tenant_admin"])
|
||||
if not credentials:
|
||||
raise UnauthorizedError("Authentication required")
|
||||
return CurrentUser(user_id="token-user", username="token", roles=[])
|
||||
if credentials is None or not credentials.credentials:
|
||||
raise UnauthorizedError("توکن احراز هویت ارائه نشده است")
|
||||
return await get_jwt_validator().validate(credentials.credentials)
|
||||
|
||||
@ -460,6 +460,10 @@ services:
|
||||
WORKSPACE_DATABASE_URL_SYNC: ${WORKSPACE_DATABASE_URL_SYNC:-postgresql+psycopg://superapp:superapp_password@postgres:5432/workspace_db}
|
||||
CORE_SERVICE_URL: ${CORE_SERVICE_URL:-http://core-service:8000}
|
||||
AUTH_REQUIRED: ${AUTH_REQUIRED:-true}
|
||||
KEYCLOAK_SERVER_URL: ${KEYCLOAK_SERVER_URL:-http://keycloak:8080}
|
||||
KEYCLOAK_PUBLIC_URL: ${KEYCLOAK_PUBLIC_URL:-http://localhost:8080}
|
||||
KEYCLOAK_REALM: ${KEYCLOAK_REALM:-superapp}
|
||||
JWT_VERIFY_SIGNATURE: ${JWT_VERIFY_SIGNATURE:-true}
|
||||
ports:
|
||||
- "8013:8013"
|
||||
volumes:
|
||||
|
||||
Loading…
Reference in New Issue
Block a user