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:
104
crates/erp-auth/src/module.rs
Normal file
104
crates/erp-auth/src/module.rs
Normal file
@@ -0,0 +1,104 @@
|
||||
use axum::Router;
|
||||
use uuid::Uuid;
|
||||
|
||||
use erp_core::error::AppResult;
|
||||
use erp_core::events::EventBus;
|
||||
use erp_core::module::ErpModule;
|
||||
|
||||
use crate::handler::{auth_handler, user_handler};
|
||||
|
||||
/// Auth module implementing the `ErpModule` trait.
|
||||
///
|
||||
/// Manages identity, authentication, and user CRUD within the ERP platform.
|
||||
/// This module has no dependencies on other business modules.
|
||||
pub struct AuthModule;
|
||||
|
||||
impl AuthModule {
|
||||
pub fn new() -> Self {
|
||||
Self
|
||||
}
|
||||
|
||||
/// Build public (unauthenticated) routes for the auth module.
|
||||
///
|
||||
/// These routes do not require a valid JWT token.
|
||||
/// The caller wraps this into whatever state type the application uses.
|
||||
pub fn public_routes<S>() -> Router<S>
|
||||
where
|
||||
crate::auth_state::AuthState: axum::extract::FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
Router::new()
|
||||
.route("/auth/login", axum::routing::post(auth_handler::login))
|
||||
.route("/auth/refresh", axum::routing::post(auth_handler::refresh))
|
||||
}
|
||||
|
||||
/// Build protected (authenticated) routes for the auth module.
|
||||
///
|
||||
/// These routes require a valid JWT token, verified by the middleware layer.
|
||||
/// The caller wraps this into whatever state type the application uses.
|
||||
pub fn protected_routes<S>() -> Router<S>
|
||||
where
|
||||
crate::auth_state::AuthState: axum::extract::FromRef<S>,
|
||||
S: Clone + Send + Sync + 'static,
|
||||
{
|
||||
Router::new()
|
||||
.route("/auth/logout", axum::routing::post(auth_handler::logout))
|
||||
.route(
|
||||
"/users",
|
||||
axum::routing::get(user_handler::list_users).post(user_handler::create_user),
|
||||
)
|
||||
.route(
|
||||
"/users/{id}",
|
||||
axum::routing::get(user_handler::get_user)
|
||||
.put(user_handler::update_user)
|
||||
.delete(user_handler::delete_user),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl Default for AuthModule {
|
||||
fn default() -> Self {
|
||||
Self::new()
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl ErpModule for AuthModule {
|
||||
fn name(&self) -> &str {
|
||||
"auth"
|
||||
}
|
||||
|
||||
fn version(&self) -> &str {
|
||||
env!("CARGO_PKG_VERSION")
|
||||
}
|
||||
|
||||
fn dependencies(&self) -> Vec<&str> {
|
||||
// Auth is a foundational module with no business-module dependencies.
|
||||
vec![]
|
||||
}
|
||||
|
||||
fn register_routes(&self, router: Router) -> Router {
|
||||
// The ErpModule trait uses Router<()> (no state type).
|
||||
// Actual route registration with typed state is done
|
||||
// via public_routes() and protected_routes(), called by erp-server.
|
||||
router
|
||||
}
|
||||
|
||||
fn register_event_handlers(&self, _bus: &EventBus) {
|
||||
// Phase 2: subscribe to events from other modules if needed
|
||||
}
|
||||
|
||||
async fn on_tenant_created(&self, _tenant_id: Uuid) -> AppResult<()> {
|
||||
// Phase 2+: create default roles and admin user for new tenant
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn on_tenant_deleted(&self, _tenant_id: Uuid) -> AppResult<()> {
|
||||
// Phase 2+: soft-delete all users belonging to the tenant
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn as_any(&self) -> &dyn std::any::Any {
|
||||
self
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user