mirror of
https://github.com/tokio-rs/axum.git
synced 2026-09-07 00:00:12 +02:00
Add sync constructors to CookieJar, SignedCookieJar, and PrivateCookieJar (#1264)
* Add sync constructors to `CookieJar`, `SignedCookieJar`, and `PrivateCookieJar` * Move to constructor * use `RequestParts::extract`
This commit is contained in:
@@ -18,6 +18,8 @@ and this project adheres to [Semantic Versioning].
|
|||||||
- **added:** Support chaining handlers with `HandlerCallWithExtractors::or` ([#1170])
|
- **added:** Support chaining handlers with `HandlerCallWithExtractors::or` ([#1170])
|
||||||
- **change:** axum-extra's MSRV is now 1.60 ([#1239])
|
- **change:** axum-extra's MSRV is now 1.60 ([#1239])
|
||||||
- **added:** Add Protocol Buffer extractor and response ([#1239])
|
- **added:** Add Protocol Buffer extractor and response ([#1239])
|
||||||
|
- **added:** Add sync constructors to `CookieJar`, `PrivateCookieJar`, and
|
||||||
|
`SignedCookieJar` so they're easier to use in custom middleware
|
||||||
|
|
||||||
[#1086]: https://github.com/tokio-rs/axum/pull/1086
|
[#1086]: https://github.com/tokio-rs/axum/pull/1086
|
||||||
[#1119]: https://github.com/tokio-rs/axum/pull/1119
|
[#1119]: https://github.com/tokio-rs/axum/pull/1119
|
||||||
|
|||||||
@@ -82,7 +82,7 @@ pub use cookie::Key;
|
|||||||
/// .route("/me", get(me));
|
/// .route("/me", get(me));
|
||||||
/// # let app: Router<axum::body::Body> = app;
|
/// # let app: Router<axum::body::Body> = app;
|
||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug)]
|
#[derive(Debug, Default)]
|
||||||
pub struct CookieJar {
|
pub struct CookieJar {
|
||||||
jar: cookie::CookieJar,
|
jar: cookie::CookieJar,
|
||||||
}
|
}
|
||||||
@@ -95,18 +95,12 @@ where
|
|||||||
type Rejection = Infallible;
|
type Rejection = Infallible;
|
||||||
|
|
||||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||||
let mut jar = cookie::CookieJar::new();
|
Ok(Self::from_headers(req.headers()))
|
||||||
for cookie in cookies_from_request(req) {
|
|
||||||
jar.add_original(cookie);
|
|
||||||
}
|
|
||||||
Ok(Self { jar })
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn cookies_from_request<B>(
|
fn cookies_from_request(headers: &HeaderMap) -> impl Iterator<Item = Cookie<'static>> + '_ {
|
||||||
req: &mut RequestParts<B>,
|
headers
|
||||||
) -> impl Iterator<Item = Cookie<'static>> + '_ {
|
|
||||||
req.headers()
|
|
||||||
.get_all(COOKIE)
|
.get_all(COOKIE)
|
||||||
.into_iter()
|
.into_iter()
|
||||||
.filter_map(|value| value.to_str().ok())
|
.filter_map(|value| value.to_str().ok())
|
||||||
@@ -115,6 +109,31 @@ fn cookies_from_request<B>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl CookieJar {
|
impl CookieJar {
|
||||||
|
/// Create a new `CookieJar` from a map of request headers.
|
||||||
|
///
|
||||||
|
/// The cookies in `headers` will be added to the jar.
|
||||||
|
///
|
||||||
|
/// This is inteded to be used in middleware and other places where it might be difficult to
|
||||||
|
/// run extractors. Normally you should create `CookieJar`s through [`FromRequest`].
|
||||||
|
pub fn from_headers(headers: &HeaderMap) -> Self {
|
||||||
|
let mut jar = cookie::CookieJar::new();
|
||||||
|
for cookie in cookies_from_request(headers) {
|
||||||
|
jar.add_original(cookie);
|
||||||
|
}
|
||||||
|
Self { jar }
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new empty `CookieJar`.
|
||||||
|
///
|
||||||
|
/// This is inteded to be used in middleware and other places where it might be difficult to
|
||||||
|
/// run extractors. Normally you should create `CookieJar`s through [`FromRequest`].
|
||||||
|
///
|
||||||
|
/// If you need a jar that contains the headers from a request use `impl From<&HeaderMap> for
|
||||||
|
/// CookieJar`.
|
||||||
|
pub fn new() -> Self {
|
||||||
|
Self::default()
|
||||||
|
}
|
||||||
|
|
||||||
/// Get a cookie from the jar.
|
/// Get a cookie from the jar.
|
||||||
///
|
///
|
||||||
/// # Example
|
/// # Example
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ use axum::{
|
|||||||
Extension,
|
Extension,
|
||||||
};
|
};
|
||||||
use cookie::PrivateJar;
|
use cookie::PrivateJar;
|
||||||
|
use http::HeaderMap;
|
||||||
use std::{convert::Infallible, fmt, marker::PhantomData};
|
use std::{convert::Infallible, fmt, marker::PhantomData};
|
||||||
|
|
||||||
/// Extractor that grabs private cookies from the request and manages the jar.
|
/// Extractor that grabs private cookies from the request and manages the jar.
|
||||||
@@ -82,21 +83,53 @@ where
|
|||||||
type Rejection = <axum::Extension<K> as FromRequest<B>>::Rejection;
|
type Rejection = <axum::Extension<K> as FromRequest<B>>::Rejection;
|
||||||
|
|
||||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||||
let key = Extension::<K>::from_request(req).await?.0.into();
|
let key = req.extract::<Extension<K>>().await?.0.into();
|
||||||
|
let PrivateCookieJar {
|
||||||
|
jar,
|
||||||
|
key,
|
||||||
|
_marker: _,
|
||||||
|
} = PrivateCookieJar::from_headers(req.headers(), key);
|
||||||
|
Ok(PrivateCookieJar {
|
||||||
|
jar,
|
||||||
|
key,
|
||||||
|
_marker: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PrivateCookieJar {
|
||||||
|
/// Create a new `PrivateCookieJar` from a map of request headers.
|
||||||
|
///
|
||||||
|
/// The valid cookies in `headers` will be added to the jar.
|
||||||
|
///
|
||||||
|
/// This is inteded to be used in middleware and other where places it might be difficult to
|
||||||
|
/// run extractors. Normally you should create `PrivateCookieJar`s through [`FromRequest`].
|
||||||
|
pub fn from_headers(headers: &HeaderMap, key: Key) -> Self {
|
||||||
let mut jar = cookie::CookieJar::new();
|
let mut jar = cookie::CookieJar::new();
|
||||||
let mut private_jar = jar.private_mut(&key);
|
let mut private_jar = jar.private_mut(&key);
|
||||||
for cookie in cookies_from_request(req) {
|
for cookie in cookies_from_request(headers) {
|
||||||
if let Some(cookie) = private_jar.decrypt(cookie) {
|
if let Some(cookie) = private_jar.decrypt(cookie) {
|
||||||
private_jar.add_original(cookie);
|
private_jar.add_original(cookie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Self {
|
||||||
jar,
|
jar,
|
||||||
key,
|
key,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new empty `PrivateCookieJarIter`.
|
||||||
|
///
|
||||||
|
/// This is inteded to be used in middleware and other places where it might be difficult to
|
||||||
|
/// run extractors. Normally you should create `PrivateCookieJar`s through [`FromRequest`].
|
||||||
|
pub fn new(key: Key) -> Self {
|
||||||
|
Self {
|
||||||
|
jar: Default::default(),
|
||||||
|
key,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ use axum::{
|
|||||||
};
|
};
|
||||||
use cookie::SignedJar;
|
use cookie::SignedJar;
|
||||||
use cookie::{Cookie, Key};
|
use cookie::{Cookie, Key};
|
||||||
|
use http::HeaderMap;
|
||||||
use std::{convert::Infallible, fmt, marker::PhantomData};
|
use std::{convert::Infallible, fmt, marker::PhantomData};
|
||||||
|
|
||||||
/// Extractor that grabs signed cookies from the request and manages the jar.
|
/// Extractor that grabs signed cookies from the request and manages the jar.
|
||||||
@@ -100,21 +101,53 @@ where
|
|||||||
type Rejection = <axum::Extension<K> as FromRequest<B>>::Rejection;
|
type Rejection = <axum::Extension<K> as FromRequest<B>>::Rejection;
|
||||||
|
|
||||||
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
async fn from_request(req: &mut RequestParts<B>) -> Result<Self, Self::Rejection> {
|
||||||
let key = Extension::<K>::from_request(req).await?.0.into();
|
let key = req.extract::<Extension<K>>().await?.0.into();
|
||||||
|
let SignedCookieJar {
|
||||||
|
jar,
|
||||||
|
key,
|
||||||
|
_marker: _,
|
||||||
|
} = SignedCookieJar::from_headers(req.headers(), key);
|
||||||
|
Ok(SignedCookieJar {
|
||||||
|
jar,
|
||||||
|
key,
|
||||||
|
_marker: PhantomData,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SignedCookieJar {
|
||||||
|
/// Create a new `SignedCookieJar` from a map of request headers.
|
||||||
|
///
|
||||||
|
/// The valid cookies in `headers` will be added to the jar.
|
||||||
|
///
|
||||||
|
/// This is inteded to be used in middleware and other places where it might be difficult to
|
||||||
|
/// run extractors. Normally you should create `SignedCookieJar`s through [`FromRequest`].
|
||||||
|
pub fn from_headers(headers: &HeaderMap, key: Key) -> Self {
|
||||||
let mut jar = cookie::CookieJar::new();
|
let mut jar = cookie::CookieJar::new();
|
||||||
let mut signed_jar = jar.signed_mut(&key);
|
let mut signed_jar = jar.signed_mut(&key);
|
||||||
for cookie in cookies_from_request(req) {
|
for cookie in cookies_from_request(headers) {
|
||||||
if let Some(cookie) = signed_jar.verify(cookie) {
|
if let Some(cookie) = signed_jar.verify(cookie) {
|
||||||
signed_jar.add_original(cookie);
|
signed_jar.add_original(cookie);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(Self {
|
Self {
|
||||||
jar,
|
jar,
|
||||||
key,
|
key,
|
||||||
_marker: PhantomData,
|
_marker: PhantomData,
|
||||||
})
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Create a new empty `SignedCookieJar`.
|
||||||
|
///
|
||||||
|
/// This is inteded to be used in middleware and other places where it might be difficult to
|
||||||
|
/// run extractors. Normally you should create `SignedCookieJar`s through [`FromRequest`].
|
||||||
|
pub fn new(key: Key) -> Self {
|
||||||
|
Self {
|
||||||
|
jar: Default::default(),
|
||||||
|
key,
|
||||||
|
_marker: PhantomData,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user