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:
@@ -4,13 +4,16 @@ mod handlers;
|
||||
mod state;
|
||||
|
||||
use axum::Router;
|
||||
use axum::middleware;
|
||||
use config::AppConfig;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::module::ModuleRegistry;
|
||||
use erp_server_migration::MigratorTrait;
|
||||
use erp_auth::middleware::jwt_auth_middleware_fn;
|
||||
use state::AppState;
|
||||
use tracing_subscriber::EnvFilter;
|
||||
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::module::{ErpModule, ModuleRegistry};
|
||||
use erp_server_migration::MigratorTrait;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> anyhow::Result<()> {
|
||||
// Load config
|
||||
@@ -41,10 +44,12 @@ async fn main() -> anyhow::Result<()> {
|
||||
// Initialize event bus (capacity 1024 events)
|
||||
let event_bus = EventBus::new(1024);
|
||||
|
||||
// Initialize module registry
|
||||
let registry = ModuleRegistry::new();
|
||||
// Phase 2+ will register modules here:
|
||||
// let registry = registry.register(Box::new(erp_auth::AuthModule::new(db.clone())));
|
||||
// Initialize auth module
|
||||
let auth_module = erp_auth::AuthModule::new();
|
||||
tracing::info!(module = auth_module.name(), version = auth_module.version(), "Auth module initialized");
|
||||
|
||||
// Initialize module registry and register auth module
|
||||
let registry = ModuleRegistry::new().register(auth_module);
|
||||
tracing::info!(module_count = registry.modules().len(), "Modules registered");
|
||||
|
||||
// Register event handlers
|
||||
@@ -53,6 +58,9 @@ async fn main() -> anyhow::Result<()> {
|
||||
let host = config.server.host.clone();
|
||||
let port = config.server.port;
|
||||
|
||||
// Extract JWT secret for middleware construction
|
||||
let jwt_secret = config.jwt.secret.clone();
|
||||
|
||||
// Build shared state
|
||||
let state = AppState {
|
||||
db,
|
||||
@@ -61,11 +69,31 @@ async fn main() -> anyhow::Result<()> {
|
||||
module_registry: registry,
|
||||
};
|
||||
|
||||
// Build API router with versioning
|
||||
let api_v1 = Router::new().merge(handlers::health::health_check_router());
|
||||
// --- Build the router ---
|
||||
//
|
||||
// The router is split into two layers:
|
||||
// 1. Public routes: no JWT required (health, login, refresh)
|
||||
// 2. Protected routes: JWT required (user CRUD, logout)
|
||||
//
|
||||
// Both layers share the same AppState. The protected layer wraps routes
|
||||
// with the jwt_auth_middleware_fn.
|
||||
|
||||
// Build application router
|
||||
let app = Router::new().merge(api_v1).with_state(state);
|
||||
// Public routes (no authentication)
|
||||
let public_routes = Router::new()
|
||||
.merge(handlers::health::health_check_router())
|
||||
.merge(erp_auth::AuthModule::public_routes())
|
||||
.with_state(state.clone());
|
||||
|
||||
// Protected routes (JWT authentication required)
|
||||
let protected_routes = erp_auth::AuthModule::protected_routes()
|
||||
.layer(middleware::from_fn(move |req, next| {
|
||||
let secret = jwt_secret.clone();
|
||||
async move { jwt_auth_middleware_fn(secret, req, next).await }
|
||||
}))
|
||||
.with_state(state.clone());
|
||||
|
||||
// Merge public + protected into the final application router
|
||||
let app = Router::new().merge(public_routes).merge(protected_routes);
|
||||
|
||||
let addr = format!("{}:{}", host, port);
|
||||
let listener = tokio::net::TcpListener::bind(&addr).await?;
|
||||
|
||||
Reference in New Issue
Block a user