axum_security/jwt/
session.rs1use std::convert::Infallible;
2
3use axum::{
4 extract::{FromRequestParts, OptionalFromRequestParts},
5 http::{Extensions, StatusCode, request::Parts},
6};
7
8#[derive(Clone, Debug)]
13pub struct Jwt<T>(pub T);
14
15impl<T: Send + Sync + 'static> Jwt<T> {
16 pub fn from_extensions(extensions: &mut Extensions) -> Option<Self> {
17 extensions.remove()
18 }
19}
20
21impl<S, T> FromRequestParts<S> for Jwt<T>
22where
23 S: Send + Sync,
24 T: Send + Sync + 'static,
25{
26 type Rejection = StatusCode;
27
28 async fn from_request_parts(parts: &mut Parts, _state: &S) -> Result<Self, Self::Rejection> {
29 if let Some(session) = <Jwt<T>>::from_extensions(&mut parts.extensions) {
30 Ok(session)
31 } else {
32 Err(StatusCode::UNAUTHORIZED)
33 }
34 }
35}
36
37impl<S, T> OptionalFromRequestParts<S> for Jwt<T>
38where
39 S: Send + Sync,
40 T: Send + Sync + 'static,
41{
42 type Rejection = Infallible;
43
44 async fn from_request_parts(
45 parts: &mut Parts,
46 _state: &S,
47 ) -> Result<Option<Self>, Self::Rejection> {
48 Ok(<Jwt<T>>::from_extensions(&mut parts.extensions))
49 }
50}
51
52#[cfg(test)]
53mod extract_jwt {
54 use axum::{
55 extract::FromRequestParts,
56 http::{Request, StatusCode},
57 };
58
59 use crate::jwt::Jwt;
60
61 #[tokio::test]
62 async fn extract() {
63 let jwt = Jwt(1i32);
64
65 let (mut parts, _) = Request::builder()
66 .extension(jwt.clone())
67 .body(())
68 .unwrap()
69 .into_parts();
70
71 let extracted_jwt = Jwt::<i32>::from_request_parts(&mut parts, &())
72 .await
73 .unwrap();
74
75 assert!(jwt.0 == extracted_jwt.0);
76 }
77
78 #[tokio::test]
79 async fn extract_rejection() {
80 let (mut parts, _) = Request::builder().body(()).unwrap().into_parts();
81
82 let rejection = Jwt::<i32>::from_request_parts(&mut parts, &())
83 .await
84 .unwrap_err();
85
86 assert!(rejection == StatusCode::UNAUTHORIZED);
87 }
88}