feat(auth): add handlers, JWT middleware, RBAC, and module registration
- Auth handlers: login/refresh/logout + user CRUD with tenant isolation - JWT middleware: Bearer token validation → TenantContext injection - RBAC helpers: require_permission, require_any_permission, require_role - AuthModule: implements ErpModule with public/protected route split - AuthState: FromRef pattern avoids circular deps between erp-auth and erp-server - Server: public routes (health+login+refresh) + protected routes (JWT middleware) - ErpModule trait: added as_any() for downcast support - Workspace: added async-trait, sha2 dependencies
This commit is contained in:
@@ -5,8 +5,8 @@ use crate::config::AppConfig;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::module::ModuleRegistry;
|
||||
|
||||
/// Axum 共享应用状态
|
||||
/// 所有 handler 通过 State<AppState> 获取数据库连接、配置等
|
||||
/// Axum shared application state.
|
||||
/// All handlers access database connections, configuration, etc. through `State<AppState>`.
|
||||
#[derive(Clone)]
|
||||
pub struct AppState {
|
||||
pub db: DatabaseConnection,
|
||||
@@ -15,9 +15,38 @@ pub struct AppState {
|
||||
pub module_registry: ModuleRegistry,
|
||||
}
|
||||
|
||||
/// 允许 handler 直接提取子字段
|
||||
/// Allow handlers to extract `DatabaseConnection` directly from `State<AppState>`.
|
||||
impl FromRef<AppState> for DatabaseConnection {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
state.db.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow handlers to extract `EventBus` directly from `State<AppState>`.
|
||||
impl FromRef<AppState> for EventBus {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
state.event_bus.clone()
|
||||
}
|
||||
}
|
||||
|
||||
/// Allow erp-auth handlers to extract their required state without depending on erp-server.
|
||||
///
|
||||
/// This bridges the gap: erp-auth defines `AuthState` with the fields it needs,
|
||||
/// and erp-server fills them from `AppState`.
|
||||
impl FromRef<AppState> for erp_auth::AuthState {
|
||||
fn from_ref(state: &AppState) -> Self {
|
||||
use erp_auth::auth_state::parse_ttl;
|
||||
|
||||
Self {
|
||||
db: state.db.clone(),
|
||||
event_bus: state.event_bus.clone(),
|
||||
jwt_secret: state.config.jwt.secret.clone(),
|
||||
access_ttl_secs: parse_ttl(&state.config.jwt.access_token_ttl),
|
||||
refresh_ttl_secs: parse_ttl(&state.config.jwt.refresh_token_ttl),
|
||||
// Default tenant ID: during bootstrap, use a well-known UUID.
|
||||
// In production, tenant resolution middleware will override this.
|
||||
default_tenant_id: uuid::Uuid::parse_str("00000000-0000-0000-0000-000000000000")
|
||||
.unwrap(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user