mirror of
https://github.com/actix/actix-extras.git
synced 2024-11-30 18:34:36 +01:00
add support for session access from guards (#234)
This commit is contained in:
parent
8db1088345
commit
4d77e26e1e
@ -1,11 +1,13 @@
|
|||||||
# Changes
|
# Changes
|
||||||
|
|
||||||
## Unreleased - 2021-xx-xx
|
## Unreleased - 2021-xx-xx
|
||||||
### Fixed
|
- Implement `SessionExt` for `GuardContext`. [#234]
|
||||||
- Do not leak internal implementation details to callers when errors occur. [#236]
|
- Do not leak internal implementation details to callers when errors occur. [#236]
|
||||||
|
|
||||||
|
[#234]: https://github.com/actix/actix-extras/pull/234
|
||||||
[#236]: https://github.com/actix/actix-extras/pull/236
|
[#236]: https://github.com/actix/actix-extras/pull/236
|
||||||
|
|
||||||
|
|
||||||
## 0.6.1 - 2022-03-21
|
## 0.6.1 - 2022-03-21
|
||||||
- No significant changes since `0.6.0`.
|
- No significant changes since `0.6.0`.
|
||||||
|
|
||||||
|
@ -193,13 +193,14 @@ pub mod test_helpers {
|
|||||||
*policy,
|
*policy,
|
||||||
)
|
)
|
||||||
.await;
|
.await;
|
||||||
|
acceptance_tests::guard(store_builder.clone(), *policy).await;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
mod acceptance_tests {
|
mod acceptance_tests {
|
||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::Service,
|
dev::Service,
|
||||||
middleware, test,
|
guard, middleware, test,
|
||||||
web::{self, get, post, resource, Bytes},
|
web::{self, get, post, resource, Bytes},
|
||||||
App, HttpResponse, Result,
|
App, HttpResponse, Result,
|
||||||
};
|
};
|
||||||
@ -209,7 +210,7 @@ pub mod test_helpers {
|
|||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
middleware::SessionLength, storage::SessionStore, test_helpers::key,
|
middleware::SessionLength, storage::SessionStore, test_helpers::key,
|
||||||
CookieContentSecurity, Session, SessionMiddleware,
|
CookieContentSecurity, Session, SessionExt, SessionMiddleware,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(super) async fn basic_workflow<F, Store>(
|
pub(super) async fn basic_workflow<F, Store>(
|
||||||
@ -308,6 +309,91 @@ pub mod test_helpers {
|
|||||||
assert_eq!(cookie_2.max_age(), Some(Duration::seconds(60)));
|
assert_eq!(cookie_2.max_age(), Some(Duration::seconds(60)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub(super) async fn guard<F, Store>(store_builder: F, policy: CookieContentSecurity)
|
||||||
|
where
|
||||||
|
Store: SessionStore + 'static,
|
||||||
|
F: Fn() -> Store + Clone + Send + 'static,
|
||||||
|
{
|
||||||
|
let srv = actix_test::start(move || {
|
||||||
|
App::new()
|
||||||
|
.wrap(
|
||||||
|
SessionMiddleware::builder(store_builder(), key())
|
||||||
|
.cookie_name("test-session".into())
|
||||||
|
.cookie_content_security(policy)
|
||||||
|
.session_length(SessionLength::Predetermined {
|
||||||
|
max_session_length: Some(time::Duration::days(7)),
|
||||||
|
})
|
||||||
|
.build(),
|
||||||
|
)
|
||||||
|
.wrap(middleware::Logger::default())
|
||||||
|
.service(resource("/").route(get().to(index)))
|
||||||
|
.service(resource("/do_something").route(post().to(do_something)))
|
||||||
|
.service(resource("/login").route(post().to(login)))
|
||||||
|
.service(resource("/logout").route(post().to(logout)))
|
||||||
|
.service(
|
||||||
|
web::scope("/protected")
|
||||||
|
.guard(guard::fn_guard(|g| {
|
||||||
|
g.get_session().get::<String>("user_id").unwrap().is_some()
|
||||||
|
}))
|
||||||
|
.service(resource("/count").route(get().to(count))),
|
||||||
|
)
|
||||||
|
});
|
||||||
|
|
||||||
|
// Step 1: GET without session info
|
||||||
|
// - response should be a unsuccessful status
|
||||||
|
let req_1 = srv.get("/protected/count").send();
|
||||||
|
let resp_1 = req_1.await.unwrap();
|
||||||
|
assert!(!resp_1.status().is_success());
|
||||||
|
|
||||||
|
// Step 2: POST to login
|
||||||
|
// - set-cookie actix-session will be in response (session cookie #1)
|
||||||
|
// - updates session state: {"counter": 0, "user_id": "ferris"}
|
||||||
|
let req_2 = srv.post("/login").send_json(&json!({"user_id": "ferris"}));
|
||||||
|
let resp_2 = req_2.await.unwrap();
|
||||||
|
let cookie_1 = resp_2
|
||||||
|
.cookies()
|
||||||
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.find(|c| c.name() == "test-session")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Step 3: POST to do_something
|
||||||
|
// - adds new session state: {"counter": 1, "user_id": "ferris" }
|
||||||
|
// - set-cookie actix-session should be in response (session cookie #2)
|
||||||
|
// - response should be: {"counter": 1, "user_id": None}
|
||||||
|
let req_3 = srv.post("/do_something").cookie(cookie_1.clone()).send();
|
||||||
|
let mut resp_3 = req_3.await.unwrap();
|
||||||
|
let result_3 = resp_3.json::<IndexResponse>().await.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
result_3,
|
||||||
|
IndexResponse {
|
||||||
|
user_id: Some("ferris".into()),
|
||||||
|
counter: 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
let cookie_2 = resp_3
|
||||||
|
.cookies()
|
||||||
|
.unwrap()
|
||||||
|
.clone()
|
||||||
|
.into_iter()
|
||||||
|
.find(|c| c.name() == "test-session")
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Step 4: GET using a existing user id
|
||||||
|
// - response should be: {"counter": 3, "user_id": "ferris"}
|
||||||
|
let req_4 = srv.get("/protected/count").cookie(cookie_2.clone()).send();
|
||||||
|
let mut resp_4 = req_4.await.unwrap();
|
||||||
|
let result_4 = resp_4.json::<IndexResponse>().await.unwrap();
|
||||||
|
assert_eq!(
|
||||||
|
result_4,
|
||||||
|
IndexResponse {
|
||||||
|
user_id: Some("ferris".into()),
|
||||||
|
counter: 1
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
pub(super) async fn complex_workflow<F, Store>(
|
pub(super) async fn complex_workflow<F, Store>(
|
||||||
store_builder: F,
|
store_builder: F,
|
||||||
is_invalidation_supported: bool,
|
is_invalidation_supported: bool,
|
||||||
@ -549,6 +635,13 @@ pub mod test_helpers {
|
|||||||
Ok(HttpResponse::Ok().json(&IndexResponse { user_id, counter }))
|
Ok(HttpResponse::Ok().json(&IndexResponse { user_id, counter }))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn count(session: Session) -> Result<HttpResponse> {
|
||||||
|
let user_id: Option<String> = session.get::<String>("user_id").unwrap();
|
||||||
|
let counter: i32 = session.get::<i32>("counter").unwrap().unwrap();
|
||||||
|
|
||||||
|
Ok(HttpResponse::Ok().json(&IndexResponse { user_id, counter }))
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Deserialize)]
|
#[derive(Deserialize)]
|
||||||
struct Identity {
|
struct Identity {
|
||||||
user_id: String,
|
user_id: String,
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
use actix_web::{
|
use actix_web::{
|
||||||
dev::{ServiceRequest, ServiceResponse},
|
dev::{ServiceRequest, ServiceResponse},
|
||||||
|
guard::GuardContext,
|
||||||
HttpMessage, HttpRequest,
|
HttpMessage, HttpRequest,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -29,3 +30,9 @@ impl SessionExt for ServiceResponse {
|
|||||||
self.request().get_session()
|
self.request().get_session()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a> SessionExt for GuardContext<'a> {
|
||||||
|
fn get_session(&self) -> Session {
|
||||||
|
Session::get_session(&mut *self.req_data_mut())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user