fix(auth): Casdoor JWT verification and 401 semantics; add /auth/login password-grant endpoint
- verify kid from the JWT header (pyjwt decode() returns claims, not the header — the old lookup was always None and rejected every token) - convert JWK entries to crypto keys explicitly (pyjwt 2.13 dropped dict keys) and fetch the JWKS from /.well-known/jwks - 401 for missing/invalid/expired/wrong-issuer/wrong-audience tokens (was 403/400); 403 stays for valid-but-roleless users; 503 when Casdoor is unreachable; new CASDOOR_ISSUER setting separates the in-network endpoint from the browser-facing issuer - dev-header fallback in inventory/pm scopes now requires an explicit X-User-Role header (no auth info at all -> 401) - new POST /api/v1/auth/login: password grant against Casdoor, local JWT verification, auto-provisioning, returns token + profile with the role resolved from the app users table
This commit is contained in:
@@ -49,3 +49,17 @@ class ForbiddenError(AppError):
|
||||
|
||||
def __init__(self, message: str, field: str | None = None):
|
||||
super().__init__(403, "FORBIDDEN", message, field)
|
||||
|
||||
|
||||
class UnauthorizedError(AppError):
|
||||
"""401 UNAUTHORIZED — missing, invalid, expired or untrusted credentials."""
|
||||
|
||||
def __init__(self, message: str, field: str | None = None):
|
||||
super().__init__(401, "UNAUTHORIZED", message, field)
|
||||
|
||||
|
||||
class ServiceUnavailableError(AppError):
|
||||
"""503 UPSTREAM_UNAVAILABLE — a dependent service (Casdoor/MinIO) is down."""
|
||||
|
||||
def __init__(self, message: str, field: str | None = None):
|
||||
super().__init__(503, "UPSTREAM_UNAVAILABLE", message, field)
|
||||
|
||||
Reference in New Issue
Block a user