1use async_trait::async_trait;
4use axum::http::request::Parts;
5use axum::response::{IntoResponse, Response};
6use serde_json::json;
7
8#[derive(Debug, Clone)]
10pub enum GuardError {
11 Unauthorized(String),
12 Forbidden(String),
13}
14
15impl GuardError {
16 pub fn unauthorized(message: impl Into<String>) -> Self {
17 Self::Unauthorized(message.into())
18 }
19
20 pub fn forbidden(message: impl Into<String>) -> Self {
21 Self::Forbidden(message.into())
22 }
23}
24
25impl IntoResponse for GuardError {
26 fn into_response(self) -> Response {
27 let (status, message, error_label) = match &self {
28 GuardError::Unauthorized(m) => (
29 axum::http::StatusCode::UNAUTHORIZED,
30 m.clone(),
31 "Unauthorized",
32 ),
33 GuardError::Forbidden(m) => (axum::http::StatusCode::FORBIDDEN, m.clone(), "Forbidden"),
34 };
35 let body = axum::Json(json!({
36 "statusCode": status.as_u16(),
37 "message": message,
38 "error": error_label,
39 }));
40 (status, body).into_response()
41 }
42}
43
44#[async_trait]
51pub trait CanActivate: Default + Send + Sync + 'static {
52 async fn can_activate(&self, parts: &Parts) -> Result<(), GuardError>;
53}