pub struct SignedCookieJar<K = Key> { /* private fields */ }
cookie-signed
and cookie
only.Expand description
Extractor that grabs signed cookies from the request and manages the jar.
All cookies will be signed and verified with a Key
. Do not use this to store private data
as the values are still transmitted in plaintext.
Note that methods like SignedCookieJar::add
, SignedCookieJar::remove
, etc updates the
SignedCookieJar
and returns it. This value must be returned from the handler as part of
the response for the changes to be propagated.
§Example
use axum::{
Router,
routing::{post, get},
extract::FromRef,
response::{IntoResponse, Redirect},
http::StatusCode,
};
use axum_extra::{
TypedHeader,
headers::authorization::{Authorization, Bearer},
extract::cookie::{SignedCookieJar, Cookie, Key},
};
async fn create_session(
TypedHeader(auth): TypedHeader<Authorization<Bearer>>,
jar: SignedCookieJar,
) -> Result<(SignedCookieJar, Redirect), StatusCode> {
if let Some(session_id) = authorize_and_create_session(auth.token()).await {
Ok((
// the updated jar must be returned for the changes
// to be included in the response
jar.add(Cookie::new("session_id", session_id)),
Redirect::to("/me"),
))
} else {
Err(StatusCode::UNAUTHORIZED)
}
}
async fn me(jar: SignedCookieJar) -> Result<(), StatusCode> {
if let Some(session_id) = jar.get("session_id") {
// fetch and render user...
} else {
Err(StatusCode::UNAUTHORIZED)
}
}
async fn authorize_and_create_session(token: &str) -> Option<String> {
// authorize the user and create a session...
}
// our application state
#[derive(Clone)]
struct AppState {
// that holds the key used to sign cookies
key: Key,
}
// this impl tells `SignedCookieJar` how to access the key from our state
impl FromRef<AppState> for Key {
fn from_ref(state: &AppState) -> Self {
state.key.clone()
}
}
let state = AppState {
// Generate a secure key
//
// You probably don't wanna generate a new one each time the app starts though
key: Key::generate(),
};
let app = Router::new()
.route("/sessions", post(create_session))
.route("/me", get(me))
.with_state(state);
If you have been using Arc<AppState>
you cannot implement FromRef<Arc<AppState>> for Key
.
You can use a new type instead:
use std::sync::Arc;
use std::ops::Deref;
#[derive(Clone)]
struct AppState(Arc<InnerState>);
// deref so you can still access the inner fields easily
impl Deref for AppState {
type Target = InnerState;
fn deref(&self) -> &Self::Target {
&*self.0
}
}
struct InnerState {
key: Key
}
impl FromRef<AppState> for Key {
fn from_ref(state: &AppState) -> Self {
state.0.key.clone()
}
}
Implementations§
Source§impl SignedCookieJar
impl SignedCookieJar
Sourcepub fn from_headers(headers: &HeaderMap, key: Key) -> Self
pub fn from_headers(headers: &HeaderMap, key: Key) -> Self
Create a new SignedCookieJar
from a map of request headers.
The valid cookies in headers
will be added to the jar.
This is intended to be used in middleware and other places where it might be difficult to
run extractors. Normally you should create SignedCookieJar
s through FromRequestParts
.
Sourcepub fn new(key: Key) -> Self
pub fn new(key: Key) -> Self
Create a new empty SignedCookieJar
.
This is intended to be used in middleware and other places where it might be difficult to
run extractors. Normally you should create SignedCookieJar
s through FromRequestParts
.
Source§impl<K> SignedCookieJar<K>
impl<K> SignedCookieJar<K>
Sourcepub fn get(&self, name: &str) -> Option<Cookie<'static>>
pub fn get(&self, name: &str) -> Option<Cookie<'static>>
Get a cookie from the jar.
If the cookie exists and its authenticity and integrity can be verified then it is returned in plaintext.
§Example
use axum_extra::extract::cookie::SignedCookieJar;
use axum::response::IntoResponse;
async fn handle(jar: SignedCookieJar) {
let value: Option<String> = jar
.get("foo")
.map(|cookie| cookie.value().to_owned());
}
Sourcepub fn remove<C: Into<Cookie<'static>>>(self, cookie: C) -> Self
pub fn remove<C: Into<Cookie<'static>>>(self, cookie: C) -> Self
Remove a cookie from the jar.
§Example
use axum_extra::extract::cookie::{SignedCookieJar, Cookie};
use axum::response::IntoResponse;
async fn handle(jar: SignedCookieJar) -> SignedCookieJar {
jar.remove(Cookie::from("foo"))
}
Sourcepub fn add<C: Into<Cookie<'static>>>(self, cookie: C) -> Self
pub fn add<C: Into<Cookie<'static>>>(self, cookie: C) -> Self
Add a cookie to the jar.
The value will automatically be percent-encoded.
§Example
use axum_extra::extract::cookie::{SignedCookieJar, Cookie};
use axum::response::IntoResponse;
async fn handle(jar: SignedCookieJar) -> SignedCookieJar {
jar.add(Cookie::new("foo", "bar"))
}
Trait Implementations§
Source§impl<K> Clone for SignedCookieJar<K>
impl<K> Clone for SignedCookieJar<K>
Source§impl<K> Debug for SignedCookieJar<K>
impl<K> Debug for SignedCookieJar<K>
Source§impl<S, K> FromRequestParts<S> for SignedCookieJar<K>
impl<S, K> FromRequestParts<S> for SignedCookieJar<K>
Source§type Rejection = Infallible
type Rejection = Infallible
Source§impl<K> IntoResponse for SignedCookieJar<K>
impl<K> IntoResponse for SignedCookieJar<K>
Source§fn into_response(self) -> Response
fn into_response(self) -> Response
Source§impl<K> IntoResponseParts for SignedCookieJar<K>
impl<K> IntoResponseParts for SignedCookieJar<K>
Source§type Error = Infallible
type Error = Infallible
Source§fn into_response_parts(
self,
res: ResponseParts,
) -> Result<ResponseParts, Self::Error>
fn into_response_parts( self, res: ResponseParts, ) -> Result<ResponseParts, Self::Error>
Auto Trait Implementations§
impl<K> Freeze for SignedCookieJar<K>
impl<K> RefUnwindSafe for SignedCookieJar<K>where
K: RefUnwindSafe,
impl<K> Send for SignedCookieJar<K>where
K: Send,
impl<K> Sync for SignedCookieJar<K>where
K: Sync,
impl<K> Unpin for SignedCookieJar<K>where
K: Unpin,
impl<K> UnwindSafe for SignedCookieJar<K>where
K: UnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
Source§impl<S, T> FromRequest<S, ViaParts> for T
impl<S, T> FromRequest<S, ViaParts> for T
Source§type Rejection = <T as FromRequestParts<S>>::Rejection
type Rejection = <T as FromRequestParts<S>>::Rejection
Source§impl<T, S> Handler<IntoResponseHandler, S> for T
impl<T, S> Handler<IntoResponseHandler, S> for T
Source§fn call(
self,
_req: Request<Body>,
_state: S,
) -> <T as Handler<IntoResponseHandler, S>>::Future
fn call( self, _req: Request<Body>, _state: S, ) -> <T as Handler<IntoResponseHandler, S>>::Future
Source§fn layer<L>(self, layer: L) -> Layered<L, Self, T, S>where
L: Layer<HandlerService<Self, T, S>> + Clone,
<L as Layer<HandlerService<Self, T, S>>>::Service: Service<Request<Body>>,
fn layer<L>(self, layer: L) -> Layered<L, Self, T, S>where
L: Layer<HandlerService<Self, T, S>> + Clone,
<L as Layer<HandlerService<Self, T, S>>>::Service: Service<Request<Body>>,
tower::Layer
to the handler. Read moreSource§fn with_state(self, state: S) -> HandlerService<Self, T, S>
fn with_state(self, state: S) -> HandlerService<Self, T, S>
Service
by providing the stateSource§impl<H, T> HandlerWithoutStateExt<T> for H
impl<H, T> HandlerWithoutStateExt<T> for H
Source§fn into_service(self) -> HandlerService<H, T, ()>
fn into_service(self) -> HandlerService<H, T, ()>
Service
and no state.Source§fn into_make_service(self) -> IntoMakeService<HandlerService<H, T, ()>>
fn into_make_service(self) -> IntoMakeService<HandlerService<H, T, ()>>
MakeService
and no state. Read more