server: Add a extractor for the authenticated user
This commit is contained in:
parent
f50d7c1076
commit
66249a5e82
3 changed files with 78 additions and 4 deletions
|
|
@ -2,11 +2,13 @@ use std::sync::Arc;
|
|||
|
||||
use api::{LoginRequest, LoginResponse};
|
||||
use axum::{
|
||||
extract::State,
|
||||
http::{header::CONTENT_TYPE, HeaderValue, Method, StatusCode},
|
||||
async_trait,
|
||||
extract::{FromRef, FromRequestParts, State},
|
||||
headers::{authorization::Bearer, Authorization},
|
||||
http::{header::CONTENT_TYPE, request::Parts, HeaderValue, Method, StatusCode},
|
||||
response::IntoResponse,
|
||||
routing::post,
|
||||
Json, Router,
|
||||
Json, Router, TypedHeader,
|
||||
};
|
||||
use jwt_simple::prelude::*;
|
||||
use sea_orm::prelude::*;
|
||||
|
|
@ -23,6 +25,10 @@ enum RouteError {
|
|||
Db(#[from] DbErr),
|
||||
#[error("JWT error encountered")]
|
||||
Jwt(#[from] jwt_simple::Error),
|
||||
#[error("User provided JWT token is invalid")]
|
||||
UserJwt(jwt_simple::Error),
|
||||
#[error("Request is missing the bearer token")]
|
||||
MissingAuthorization,
|
||||
}
|
||||
|
||||
impl IntoResponse for RouteError {
|
||||
|
|
@ -31,6 +37,13 @@ impl IntoResponse for RouteError {
|
|||
RouteError::UnknownAccount => {
|
||||
(StatusCode::NOT_FOUND, "Account not found").into_response()
|
||||
}
|
||||
RouteError::MissingAuthorization => {
|
||||
(StatusCode::BAD_REQUEST, "Missing authorization header").into_response()
|
||||
}
|
||||
RouteError::UserJwt(e) => {
|
||||
tracing::debug!("Invalid user JWT: {e:?}");
|
||||
(StatusCode::BAD_REQUEST, "Invalid authorization header").into_response()
|
||||
}
|
||||
e => {
|
||||
tracing::error!("Internal error: {e:?}");
|
||||
StatusCode::INTERNAL_SERVER_ERROR.into_response()
|
||||
|
|
@ -43,6 +56,41 @@ type JsonResult<T, E = RouteError> = Result<Json<T>, E>;
|
|||
|
||||
type AppState = Arc<crate::AppState>;
|
||||
|
||||
#[derive(Debug)]
|
||||
struct AuthenticatedUser {
|
||||
pub id: Uuid,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<S> FromRequestParts<S> for AuthenticatedUser
|
||||
where
|
||||
S: Send + Sync,
|
||||
AppState: FromRef<S>,
|
||||
{
|
||||
type Rejection = RouteError;
|
||||
|
||||
async fn from_request_parts(parts: &mut Parts, state: &S) -> Result<Self, Self::Rejection> {
|
||||
let State(app_state): State<AppState> = State::from_request_parts(parts, state)
|
||||
.await
|
||||
.expect("Could not get state");
|
||||
|
||||
let TypedHeader(Authorization(bearer)) =
|
||||
TypedHeader::<Authorization<Bearer>>::from_request_parts(parts, state)
|
||||
.await
|
||||
.map_err(|_| RouteError::MissingAuthorization)?;
|
||||
|
||||
let claims = app_state
|
||||
.jwt_secret
|
||||
.0
|
||||
.verify_token::<NoCustomClaims>(bearer.token(), None)
|
||||
.map_err(RouteError::UserJwt)?;
|
||||
|
||||
Ok(AuthenticatedUser {
|
||||
id: claims.subject.unwrap().parse().unwrap(),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
async fn login(
|
||||
State(state): State<AppState>,
|
||||
Json(req): Json<LoginRequest>,
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue