Request Guards
Request guards are one of Rocket’s most powerful instruments. As the name might imply, a request guard protects a handler from being called erroneously based on information contained in an incoming request. More specifically, a request guard is a type that represents an arbitrary validation policy. The validation policy is implemented through the FromRequest trait. Every type that implements FromRequest
is a request guard.
Request guards appear as inputs to handlers. An arbitrary number of request guards can appear as arguments in a route handler. Rocket will automatically invoke the FromRequest implementation for request guards before calling the handler. Rocket only dispatches requests to a handler when all of its guards pass.
As an example, the following dummy handler makes use of three request guards, A
, B
, and C
. An input can be identified as a request guard if it is not named in the route attribute. This is why param
is not a request guard.
#[get("/<param>")]
fn index(param: isize, a: A, b: B, c: C) -> ... { ... }
Request guards always fire in left-to-right declaration order. In the example above, the order will be A
followed by B
followed by C
. Failure is short-circuiting; if one guard fails, the remaining are not attempted. To learn more about request guards and implementing them, see the FromRequest documentation.
Custom Guards
You can implement FromRequest
for your own types. For instance, to protect a sensitive
route from running unless an ApiKey
is present in the request headers, you might create an ApiKey
type that implements FromRequest
and then use it as a request guard:
#[get("/sensitive")]
fn sensitive(key: ApiKey) -> &'static str { ... }
You might also implement FromRequest
for an AdminUser
type that authenticates an administrator using incoming cookies. Then, any handler with an AdminUser
or ApiKey
type in its argument list is assured to only be invoked if the appropriate conditions are met. Request guards centralize policies, resulting in a simpler, safer, and more secure applications.
Forwarding Guards
Request guards and forwarding are a powerful combination for enforcing policies. To illustrate, we consider how a simple authorization system might be implemented using these mechanisms.
We start with two request guards:
User
: A regular, authenticated user.The
FromRequest
implementation forUser
checks that a cookie identifies a user and returns aUser
value if so. If no user can be authenticated, the guard forwards.AdminUser
: A user authenticated as an administrator.The
FromRequest
implementation forAdminUser
checks that a cookie identifies an administrative user and returns anAdminUser
value if so. If no user can be authenticated, the guard forwards.
We now use these two guards in combination with forwarding to implement the following three routes, each leading to an administrative control panel at /admin
:
#[get("/admin")]
fn admin_panel(admin: AdminUser) -> &'static str {
"Hello, administrator. This is the admin panel!"
}
#[get("/admin", rank = 2)]
fn admin_panel_user(user: User) -> &'static str {
"Sorry, you must be an administrator to access this page."
}
#[get("/admin", rank = 3)]
fn admin_panel_redirect() -> Redirect {
Redirect::to("/login")
}
The three routes above encode authentication and authorization. The admin_panel
route only succeeds if an administrator is logged in. Only then is the admin panel displayed. If the user is not an admin, the AdminUser
route will forward. Since the admin_panel_user
route is ranked next highest, it is attempted next. This route succeeds if there is any user signed in, and an authorization failure message is displayed. Finally, if a user isn’t signed in, the admin_panel_redirect
route is attempted. Since this route has no guards, it always succeeds. The user is redirected to a log in page.