rama::http::layer::auth

Module async_require_authorization

Expand description

Authorize requests using the Authorization header asynchronously.

§Example

use bytes::Bytes;

use rama_http::layer::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest};
use rama_http::{Body, Request, Response, StatusCode, header::AUTHORIZATION};
use rama_core::service::service_fn;
use rama_core::{Context, Service, Layer};
use rama_core::error::BoxError;

#[derive(Clone, Copy)]
struct MyAuth;

impl<S, B> AsyncAuthorizeRequest<S, B> for MyAuth
where
    S: Clone + Send + Sync + 'static,
    B: Send + Sync + 'static,
{
    type RequestBody = B;
    type ResponseBody = Body;

    async fn authorize(&self, mut ctx: Context<S>, request: Request<B>) -> Result<(Context<S>, Request<B>), Response<Self::ResponseBody>> {
        if let Some(user_id) = check_auth(&request).await {
            // Set `user_id` as a request extension so it can be accessed by other
            // services down the stack.
            ctx.insert(user_id);

            Ok((ctx, request))
        } else {
            let unauthorized_response = Response::builder()
                .status(StatusCode::UNAUTHORIZED)
                .body(Body::default())
                .unwrap();

            Err(unauthorized_response)
        }
    }
}

async fn check_auth<B>(request: &Request<B>) -> Option<UserId> {
    // ...
}

#[derive(Clone, Debug)]
struct UserId(String);

async fn handle<S>(ctx: Context<S>, _request: Request) -> Result<Response, BoxError> {
    // Access the `UserId` that was set in `on_authorized`. If `handle` gets called the
    // request was authorized and `UserId` will be present.
    let user_id = ctx
        .get::<UserId>()
        .expect("UserId will be there if request was authorized");

    println!("request from {:?}", user_id);

    Ok(Response::new(Body::default()))
}

let service = (
    // Authorize requests using `MyAuth`
    AsyncRequireAuthorizationLayer::new(MyAuth),
).layer(service_fn(handle::<()>));

Or using a closure:

use bytes::Bytes;

use rama_http::layer::auth::{AsyncRequireAuthorizationLayer, AsyncAuthorizeRequest};
use rama_http::{Body, Request, Response, StatusCode};
use rama_core::service::service_fn;
use rama_core::{Service, Layer};
use rama_core::error::BoxError;

async fn check_auth<B>(request: &Request<B>) -> Option<UserId> {
    // ...
}

#[derive(Debug)]
struct UserId(String);

async fn handle(request: Request) -> Result<Response, BoxError> {
    // ...
}

let service =
    AsyncRequireAuthorizationLayer::new(|request: Request| async move {
        if let Some(user_id) = check_auth(&request).await {
            Ok(request)
        } else {
            let unauthorized_response = Response::builder()
                .status(StatusCode::UNAUTHORIZED)
                .body(Body::default())
                .unwrap();

            Err(unauthorized_response)
        }
    })
    .layer(service_fn(handle));

Structs§

Traits§