feat: Enhance validation and permissions handling across controllers
- Added `ValidatedJson` extractor for automatic JSON validation in `events_controller.rs`, `testimonials_controller.rs`, `mentors_controller.rs`, `gacha_items_controller.rs`, and `hackathon_controller.rs`. - Replaced manual permission checks with `require_permissions!` and `require_auth!` macros in relevant controllers to streamline permission handling. - Introduced `sanitization` utilities in `sanitization.rs` for improved input sanitization. - Added `permission_macros.rs` to encapsulate permission checking logic and reduce boilerplate. - Updated dependencies in `Cargo.toml` to include `serde_json` and `validator`. - Implemented error handling improvements in `notification_service.rs` for better response management.
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
pub mod v1;
|
||||
pub mod permission_macros;
|
||||
|
||||
// Re-export core entity types used throughout the IAM module
|
||||
pub use imphnen_entities::{
|
||||
@@ -71,6 +72,9 @@ pub use v1::{
|
||||
permissions_guard,
|
||||
};
|
||||
|
||||
// Export permission macros
|
||||
pub use permission_macros::{check_permissions, check_authenticated};
|
||||
|
||||
// Export IAM-specific types
|
||||
pub use v1::auth::{
|
||||
AuthRepository, AuthOtpSchema,
|
||||
|
||||
@@ -0,0 +1,115 @@
|
||||
//! Permission guard utilities and macros to reduce boilerplate
|
||||
//!
|
||||
//! This module provides utilities to simplify permission checking in handlers
|
||||
|
||||
use axum::{
|
||||
extract::Extension,
|
||||
http::HeaderMap,
|
||||
response::Response,
|
||||
};
|
||||
use imphnen_entities::PermissionsEnum;
|
||||
use crate::AppState;
|
||||
use crate::permissions_guard;
|
||||
use imphnen_libs::jsonwebtoken::Claims;
|
||||
|
||||
/// Result type for permission-guarded handlers
|
||||
pub type PermissionGuardResult<T> = Result<(T, AppState), Response>;
|
||||
|
||||
/// Helper function to extract user and check permissions
|
||||
///
|
||||
/// This is a cleaner wrapper around the existing permissions_guard
|
||||
pub async fn check_permissions(
|
||||
headers: HeaderMap,
|
||||
state: Extension<AppState>,
|
||||
required_permissions: Vec<PermissionsEnum>,
|
||||
) -> PermissionGuardResult<Claims> {
|
||||
match permissions_guard(headers, state, required_permissions).await {
|
||||
Ok((user, state)) => Ok((user, state)),
|
||||
Err(response) => Err(response),
|
||||
}
|
||||
}
|
||||
|
||||
/// Helper function for endpoints that don't require specific permissions
|
||||
/// but still need authentication
|
||||
pub async fn check_authenticated(
|
||||
headers: HeaderMap,
|
||||
state: Extension<AppState>,
|
||||
) -> PermissionGuardResult<Claims> {
|
||||
check_permissions(headers, state, vec![]).await
|
||||
}
|
||||
|
||||
/// Macro to reduce boilerplate in permission-guarded handlers
|
||||
///
|
||||
/// # Example
|
||||
/// ```rust
|
||||
/// use imphnen_iam::require_permissions;
|
||||
/// use imphnen_entities::PermissionsEnum;
|
||||
///
|
||||
/// pub async fn get_user_list(
|
||||
/// headers: HeaderMap,
|
||||
/// Extension(state): Extension<AppState>,
|
||||
/// Query(meta): Query<MetaRequestDto>,
|
||||
/// ) -> Response {
|
||||
/// require_permissions!(headers, state, [PermissionsEnum::ReadListUsers], {
|
||||
/// UsersService::get_user_list(&state, meta).await
|
||||
/// })
|
||||
/// }
|
||||
/// ```
|
||||
#[macro_export]
|
||||
macro_rules! require_permissions {
|
||||
($headers:expr, $state:expr, [$($perm:expr),*], $body:block) => {
|
||||
{
|
||||
let state_clone = $state.clone();
|
||||
match $crate::permissions_guard(
|
||||
$headers,
|
||||
axum::extract::Extension(state_clone),
|
||||
vec![$($perm),*],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok((_user, _state_inner)) => {
|
||||
let state = &$state;
|
||||
$body
|
||||
}
|
||||
Err(response) => response,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Macro for authenticated-only handlers (no specific permissions)
|
||||
#[macro_export]
|
||||
macro_rules! require_auth {
|
||||
($headers:expr, $state:expr, $body:block) => {
|
||||
{
|
||||
let state_clone = $state.clone();
|
||||
match $crate::permissions_guard($headers, axum::extract::Extension(state_clone), vec![]).await {
|
||||
Ok((_user, _state_inner)) => {
|
||||
let state = &$state;
|
||||
$body
|
||||
}
|
||||
Err(response) => response,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Macro for handlers that need access to the authenticated user
|
||||
#[macro_export]
|
||||
macro_rules! with_user {
|
||||
($headers:expr, $state:expr, [$($perm:expr),*], |$user:ident, $state_var:ident| $body:block) => {
|
||||
{
|
||||
let state_clone = $state.clone();
|
||||
match $crate::permissions_guard(
|
||||
$headers,
|
||||
axum::extract::Extension(state_clone),
|
||||
vec![$($perm),*],
|
||||
)
|
||||
.await
|
||||
{
|
||||
Ok(($user, $state_var)) => $body,
|
||||
Err(response) => response,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user