API Permission Check
10/30/24Less than 1 minute
API Permission Check
Permission verification based on the "Role-API-Method" exact matching model, implemented in middleware.
Architecture & Flow
Middleware Chain:
request_log_fn_mid: Logs method, path, query, UA, Content-Type, body (max 1000 chars)auth_fn_mid: Builds and injectsReqCtx(path without /api prefix, query string, method)api_fn_mid: GetsUserInfoandReqCtxfrom extensions, calls permission service
Permission Model:
- Table:
sys_role_api - Dimensions:
role_id + api + methodexact match - Super role: Roles in
APPCOFIG.system.super_rolelist are unconditionally allowed
- Table:
Core Structs & Functions
Request Context ReqCtx
#[derive(Clone, Debug, Default)]
pub struct ReqCtx {
pub ori_uri: String, // Original URI (with /api + query)
pub path: String, // Path without /api prefix
pub path_params: String, // Original query
pub method: String, // HTTP method
}Auth Middleware
pub async fn auth_fn_mid(req: Request, next: Next) -> Result<impl IntoResponse, (StatusCode, String)> {
// Extract URI, path, method, query params
// Read and rebuild request body
// Build ReqCtx and inject into extensions
}Permission Check Middleware
pub async fn api_fn_mid(req: Request, next: Next) -> Result<Response, (StatusCode, String)> {
let user = req.extensions().get::<UserInfo>().unwrap();
let ctx = req.extensions().get::<ReqCtx>().unwrap();
let has_perm = s_sys_role_api::check_api(/* ... */).await;
if has_perm { Ok(next.run(req).await) }
else { Err((StatusCode::NOT_FOUND, "No API permission".into())) }
}Data Standards
- method: Store in uppercase (GET/POST/PUT/DELETE/PATCH...) matching ctx.method
- api: Store path without /api prefix, e.g., request
/api/sys/role/list→ store/sys/role/list - Super role: Configured in
APPCOFIG.system.super_role, matched by rid