feat(manager-core,picloud): bearer pic_ keys land in Principal

* auth_middleware: split into resolve_principal → verify_session OR
  verify_api_key (selected by the pic_ prefix). Both paths converge on
  Principal as the request extension; require_admin keeps working as
  a #[deprecated] alias for require_authenticated. AuthState gains an
  api_keys repo; the cookie path is unchanged.
* api-key path takes the first 8 chars after pic_ as the indexed
  lookup key, Argon2-verifies each candidate, soft-rejects deactivated
  users, and updates last_used_at inline.
* auth_api: /auth/me now consumes Extension<Principal> and re-fetches
  the user row so username updates surface immediately.
* picloud: AuthDeps + AuthState wired with PostgresApiKeyRepository;
  the layer call switches to require_authenticated.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
This commit is contained in:
MechaCat02
2026-05-26 21:55:38 +02:00
parent 44db8d107a
commit 5f7ddd23ab
4 changed files with 245 additions and 53 deletions

View File

@@ -52,7 +52,11 @@ pub use auth_api::auth_router;
pub use auth_bootstrap::{
bootstrap_first_admin, bootstrap_first_admin_with, BootstrapEnv, BootstrapError,
};
pub use auth_middleware::{require_admin, AuthState, AuthedAdmin, SESSION_COOKIE};
#[allow(deprecated)]
pub use auth_middleware::{
require_admin, require_authenticated, AuthState, AuthedAdmin, API_KEY_PREFIX,
API_KEY_PREFIX_LEN, SESSION_COOKIE,
};
pub use authz::{can, require, AuthzDenied, AuthzError, AuthzRepo, Capability, Decision};
pub use log_sink::PostgresExecutionLogSink;
pub use repo::{