feat(auth): migrate to Keycloak metadata auth

This commit is contained in:
2026-06-12 10:18:41 +08:00
parent 2a762e63a7
commit 23c008f602
27 changed files with 178 additions and 1712 deletions
+26 -43
View File
@@ -8,35 +8,41 @@ from jose import JWTError, jwt
from app.core.config import settings
oauth2_optional = OAuth2PasswordBearer(
tokenUrl=f"{settings.API_V1_STR}/auth/login", auto_error=False
tokenUrl="keycloak", auto_error=False
)
# logger = logging.getLogger(__name__)
async def get_current_keycloak_sub(
def _decode_keycloak_token(token: str) -> dict:
if not settings.KEYCLOAK_PUBLIC_KEY:
raise HTTPException(
status_code=status.HTTP_503_SERVICE_UNAVAILABLE,
detail="Keycloak public key is not configured",
)
key = settings.KEYCLOAK_PUBLIC_KEY.replace("\\n", "\n")
return jwt.decode(
token,
key,
algorithms=[settings.KEYCLOAK_ALGORITHM],
audience=settings.KEYCLOAK_AUDIENCE or None,
)
async def get_current_keycloak_payload(
token: str | None = Depends(oauth2_optional),
) -> UUID:
) -> dict:
if not token:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not authenticated",
headers={"WWW-Authenticate": "Bearer"},
)
if settings.KEYCLOAK_PUBLIC_KEY:
key = settings.KEYCLOAK_PUBLIC_KEY.replace("\\n", "\n")
algorithms = [settings.KEYCLOAK_ALGORITHM]
else:
key = settings.SECRET_KEY
algorithms = [settings.ALGORITHM]
try:
payload = jwt.decode(
token,
key,
algorithms=algorithms,
audience=settings.KEYCLOAK_AUDIENCE or None,
)
return _decode_keycloak_token(token)
except JWTError as exc:
# logger.warning("Keycloak token validation failed: %s", exc)
raise HTTPException(
@@ -45,6 +51,10 @@ async def get_current_keycloak_sub(
headers={"WWW-Authenticate": "Bearer"},
) from exc
async def get_current_keycloak_sub(
payload: dict = Depends(get_current_keycloak_payload),
) -> UUID:
sub = payload.get("sub")
if not sub:
raise HTTPException(
@@ -64,35 +74,8 @@ async def get_current_keycloak_sub(
async def get_current_keycloak_username(
token: str | None = Depends(oauth2_optional),
payload: dict = Depends(get_current_keycloak_payload),
) -> str:
if not token:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Not authenticated",
headers={"WWW-Authenticate": "Bearer"},
)
if settings.KEYCLOAK_PUBLIC_KEY:
key = settings.KEYCLOAK_PUBLIC_KEY.replace("\\n", "\n")
algorithms = [settings.KEYCLOAK_ALGORITHM]
else:
key = settings.SECRET_KEY
algorithms = [settings.ALGORITHM]
try:
payload = jwt.decode(
token,
key,
algorithms=algorithms,
audience=settings.KEYCLOAK_AUDIENCE or None,
)
except JWTError as exc:
raise HTTPException(
status_code=status.HTTP_401_UNAUTHORIZED,
detail="Invalid token",
headers={"WWW-Authenticate": "Bearer"},
) from exc
username = payload.get("preferred_username") or payload.get("username")
if not username:
raise HTTPException(