Guards
Check identity, permissions, or quota conditions before an action runs.
A guard decides whether an action is allowed to run. Its constructor is new(Arc<Extensions>), and its decision method is can_activate(&self, &mut Request, ExecutionCancellation).
Role-check example#
The following guard looks for the admin role in a verified principal. AuthGuard must complete authentication first.
use std::sync::Arc;
use lilyrs::http_api::{
ExecutionCancellation, Extensions, GuardInitError, GuardRejection,
GuardTrait, HttpErrorCode, Principal, Request,
};
pub struct AdminGuard;
#[lilyrs::http_api::async_trait::async_trait]
impl GuardTrait for AdminGuard {
async fn new(_: Arc<Extensions>) -> Result<Self, GuardInitError> { Ok(Self) }
async fn can_activate(&self, request: &mut Request, _: ExecutionCancellation)
-> Result<(), GuardRejection>
{
match request.principal() {
Some(principal) if principal.has_role("admin") => Ok(()),
Some(_) => Err(GuardRejection::forbidden(
HttpErrorCode::new("ADMIN_REQUIRED").unwrap(),
).unwrap()),
None => Err(GuardRejection::unauthorized(
HttpErrorCode::new("AUTH_REQUIRED").unwrap(), "Bearer",
).unwrap()),
}
}
}
Attach to an action#
#[get("/admin")]
#[guard(AuthGuard, AdminGuard)]Add these attributes to a controller action. Guards run from left to right. AuthGuard publishes the principal first, then AdminGuard checks its role.
Supply an instance#
AppBuilder::guard(instance) supplies a prebuilt instance of a particular type. This call alone does not run the guard on every endpoint. The corresponding action still needs #[guard(Type)]. If the same prebuilt type is supplied more than once, the last instance is used; CsrfGuard cannot be supplied this way.
Rejection contract#
GuardRejection uses the shared HttpRejection structure. It supports 401 challenges, 403, 429 / Retry-After, 503, bounded problem details, and JSON/text responses. Distinguish expected access denial from a technical runtime failure.
Sources for this page v0.1.0
This guide is based on the reviewed framework commit.