mirror of
https://github.com/actix/actix-extras.git
synced 2025-03-24 05:32:58 +01:00
fix double serialization in session state
This commit is contained in:
parent
3c5478966f
commit
c74b8451c6
8
.idea/.gitignore
generated
vendored
Normal file
8
.idea/.gitignore
generated
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
# Default ignored files
|
||||
/shelf/
|
||||
/workspace.xml
|
||||
# Editor-based HTTP Client requests
|
||||
/httpRequests/
|
||||
# Datasource local storage ignored files
|
||||
/dataSources/
|
||||
/dataSources.local.xml
|
31
.idea/actix-extras.iml
generated
Normal file
31
.idea/actix-extras.iml
generated
Normal file
@ -0,0 +1,31 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<module type="JAVA_MODULE" version="4">
|
||||
<component name="NewModuleRootManager" inherit-compiler-output="true">
|
||||
<exclude-output />
|
||||
<content url="file://$MODULE_DIR$">
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-cors/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-cors/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-cors/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-identity/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-identity/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-identity/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-limitation/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-limitation/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-protobuf/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-redis/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-redis/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-session/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-session/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-session/tests" isTestSource="true" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-settings/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-settings/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-web-httpauth/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-web-httpauth/src" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-ws/examples" isTestSource="false" />
|
||||
<sourceFolder url="file://$MODULE_DIR$/actix-ws/src" isTestSource="false" />
|
||||
<excludeFolder url="file://$MODULE_DIR$/target" />
|
||||
</content>
|
||||
<orderEntry type="inheritedJdk" />
|
||||
<orderEntry type="sourceFolder" forTests="false" />
|
||||
</component>
|
||||
</module>
|
8
.idea/modules.xml
generated
Normal file
8
.idea/modules.xml
generated
Normal file
@ -0,0 +1,8 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="ProjectModuleManager">
|
||||
<modules>
|
||||
<module fileurl="file://$PROJECT_DIR$/.idea/actix-extras.iml" filepath="$PROJECT_DIR$/.idea/actix-extras.iml" />
|
||||
</modules>
|
||||
</component>
|
||||
</project>
|
6
.idea/vcs.xml
generated
Normal file
6
.idea/vcs.xml
generated
Normal file
@ -0,0 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="VcsDirectoryMappings">
|
||||
<mapping directory="" vcs="Git" />
|
||||
</component>
|
||||
</project>
|
@ -2,6 +2,10 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.7.0
|
||||
|
||||
- Updated the usage of HashMap with serde Map to be compatible with `actix-session@0.9.0`.
|
||||
|
||||
## 0.6.0
|
||||
|
||||
- Add `error` module.
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-identity"
|
||||
version = "0.6.0"
|
||||
version = "0.7.0"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
"Luca Palmieri <rust@lpalmieri.com>",
|
||||
@ -19,19 +19,20 @@ all-features = true
|
||||
|
||||
[dependencies]
|
||||
actix-service = "2"
|
||||
actix-session = "0.8"
|
||||
actix-session = "0.9"
|
||||
actix-utils = "3"
|
||||
actix-web = { version = "4", default-features = false, features = ["cookies", "secure-cookies"] }
|
||||
|
||||
derive_more = "0.99.7"
|
||||
futures-core = "0.3.7"
|
||||
serde = { version = "1", features = ["derive"] }
|
||||
serde_json = "1.0.108"
|
||||
tracing = { version = "0.1.30", default-features = false, features = ["log"] }
|
||||
|
||||
[dev-dependencies]
|
||||
actix-http = "3"
|
||||
actix-web = { version = "4", default-features = false, features = ["macros", "cookies", "secure-cookies"] }
|
||||
actix-session = { version = "0.8", features = ["redis-rs-session", "cookie-session"] }
|
||||
actix-session = { version = "0.9", features = ["redis-rs-session", "cookie-session"] }
|
||||
|
||||
env_logger = "0.10"
|
||||
reqwest = { version = "0.11", default-features = false, features = ["cookies", "json"] }
|
||||
|
@ -6,6 +6,7 @@ use actix_web::{
|
||||
http::StatusCode,
|
||||
Error, FromRequest, HttpMessage, HttpRequest, HttpResponse,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::{
|
||||
config::LogoutBehaviour,
|
||||
@ -153,13 +154,17 @@ impl Identity {
|
||||
/// ```
|
||||
pub fn login(ext: &Extensions, id: String) -> Result<Self, LoginError> {
|
||||
let inner = IdentityInner::extract(ext);
|
||||
inner.session.insert(ID_KEY, id)?;
|
||||
inner.session.insert(ID_KEY, Value::from(id));
|
||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||
if inner.is_login_deadline_enabled {
|
||||
inner.session.insert(LOGIN_UNIX_TIMESTAMP_KEY, now)?;
|
||||
inner
|
||||
.session
|
||||
.insert(LOGIN_UNIX_TIMESTAMP_KEY, Value::from(now));
|
||||
}
|
||||
if inner.is_visit_deadline_enabled {
|
||||
inner.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)?;
|
||||
inner
|
||||
.session
|
||||
.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, Value::from(now));
|
||||
}
|
||||
inner.session.renew();
|
||||
Ok(Self(inner))
|
||||
@ -230,7 +235,9 @@ impl Identity {
|
||||
|
||||
pub(crate) fn set_last_visited_at(&self) -> Result<(), LoginError> {
|
||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||
self.0.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)?;
|
||||
self.0
|
||||
.session
|
||||
.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, Value::from(now));
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ use actix_identity::{config::IdentityMiddlewareBuilder, Identity, IdentityMiddle
|
||||
use actix_session::{Session, SessionStatus};
|
||||
use actix_web::{web, App, HttpMessage, HttpRequest, HttpResponse, HttpServer};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
use crate::fixtures::session_middleware;
|
||||
|
||||
@ -136,7 +137,7 @@ async fn increment(session: Session, user: Option<Identity>) -> HttpResponse {
|
||||
.get::<i32>("counter")
|
||||
.unwrap_or(Some(0))
|
||||
.map_or(1, |inner| inner + 1);
|
||||
session.insert("counter", counter).unwrap();
|
||||
session.insert("counter", Value::from(counter));
|
||||
|
||||
HttpResponse::Ok().json(&EndpointResponse {
|
||||
user_id,
|
||||
|
@ -2,6 +2,11 @@
|
||||
|
||||
## Unreleased
|
||||
|
||||
## 0.9.0
|
||||
|
||||
- Replace the usages of `HashMap` with serde `Map`.
|
||||
- Fix double serialization when inserting values into the session.
|
||||
|
||||
## 0.8.0
|
||||
|
||||
- Set secure attribute when adding a session removal cookie.
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "actix-session"
|
||||
version = "0.8.0"
|
||||
version = "0.9.0"
|
||||
authors = [
|
||||
"Nikolay Kim <fafhrd91@gmail.com>",
|
||||
"Luca Palmieri <rust@lpalmieri.com>",
|
||||
|
@ -5,6 +5,7 @@ use actix_web::{
|
||||
middleware, web, App, Error, HttpResponse, HttpServer, Responder,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::Value;
|
||||
|
||||
#[derive(Deserialize)]
|
||||
struct Credentials {
|
||||
@ -54,7 +55,7 @@ async fn login(
|
||||
let credentials = credentials.into_inner();
|
||||
|
||||
match User::authenticate(credentials) {
|
||||
Ok(user) => session.insert("user_id", user.id).unwrap(),
|
||||
Ok(user) => session.insert("user_id", Value::from(user.id)),
|
||||
Err(err) => return Err(InternalError::from_response("", err).into()),
|
||||
};
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
use actix_session::{storage::RedisActorSessionStore, Session, SessionMiddleware};
|
||||
use actix_web::{cookie::Key, middleware, web, App, Error, HttpRequest, HttpServer, Responder};
|
||||
use serde_json::Value;
|
||||
|
||||
/// simple handler
|
||||
async fn index(req: HttpRequest, session: Session) -> Result<impl Responder, Error> {
|
||||
@ -8,9 +9,9 @@ async fn index(req: HttpRequest, session: Session) -> Result<impl Responder, Err
|
||||
// session
|
||||
if let Some(count) = session.get::<i32>("counter")? {
|
||||
println!("SESSION value: {count}");
|
||||
session.insert("counter", count + 1)?;
|
||||
session.insert("counter", Value::from(count + 1));
|
||||
} else {
|
||||
session.insert("counter", 1)?;
|
||||
session.insert("counter", Value::from(1));
|
||||
}
|
||||
|
||||
Ok("Welcome!")
|
||||
|
@ -69,6 +69,7 @@
|
||||
//!
|
||||
//! ```no_run
|
||||
//! use actix_web::Error;
|
||||
//! use serde_json::Value;
|
||||
//! use actix_session::Session;
|
||||
//!
|
||||
//! fn index(session: Session) -> Result<&'static str, Error> {
|
||||
@ -76,9 +77,9 @@
|
||||
//! if let Some(count) = session.get::<i32>("counter")? {
|
||||
//! println!("SESSION value: {}", count);
|
||||
//! // modify the session state
|
||||
//! session.insert("counter", count + 1)?;
|
||||
//! session.insert("counter", Value::from(count + 1));
|
||||
//! } else {
|
||||
//! session.insert("counter", 1)?;
|
||||
//! session.insert("counter", Value::from(1));
|
||||
//! }
|
||||
//!
|
||||
//! Ok("Welcome!")
|
||||
@ -207,7 +208,7 @@ pub mod test_helpers {
|
||||
App, HttpResponse, Result,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use serde_json::json;
|
||||
use serde_json::{json, Value};
|
||||
|
||||
use crate::{
|
||||
config::{CookieContentSecurity, PersistentSession, TtlExtensionPolicy},
|
||||
@ -238,7 +239,7 @@ pub mod test_helpers {
|
||||
.build(),
|
||||
)
|
||||
.service(web::resource("/").to(|ses: Session| async move {
|
||||
let _ = ses.insert("counter", 100);
|
||||
ses.insert("counter", Value::from(100));
|
||||
"test"
|
||||
}))
|
||||
.service(web::resource("/test/").to(|ses: Session| async move {
|
||||
@ -286,7 +287,7 @@ pub mod test_helpers {
|
||||
.build(),
|
||||
)
|
||||
.service(web::resource("/").to(|ses: Session| async move {
|
||||
let _ = ses.insert("counter", 100);
|
||||
ses.insert("counter", Value::from(100));
|
||||
"test"
|
||||
}))
|
||||
.service(web::resource("/test/").to(|| async move { "no-changes-in-session" })),
|
||||
@ -328,7 +329,7 @@ pub mod test_helpers {
|
||||
.build(),
|
||||
)
|
||||
.service(web::resource("/").to(|ses: Session| async move {
|
||||
let _ = ses.insert("counter", 100);
|
||||
ses.insert("counter", Value::from(100));
|
||||
"test"
|
||||
}))
|
||||
.service(web::resource("/test/").to(|| async move { "no-changes-in-session" })),
|
||||
@ -674,7 +675,7 @@ pub mod test_helpers {
|
||||
.get::<i32>("counter")
|
||||
.unwrap_or(Some(0))
|
||||
.map_or(1, |inner| inner + 1);
|
||||
session.insert("counter", counter)?;
|
||||
session.insert("counter", Value::from(counter));
|
||||
|
||||
Ok(HttpResponse::Ok().json(&IndexResponse { user_id, counter }))
|
||||
}
|
||||
@ -693,7 +694,7 @@ pub mod test_helpers {
|
||||
|
||||
async fn login(user_id: web::Json<Identity>, session: Session) -> Result<HttpResponse> {
|
||||
let id = user_id.into_inner().user_id;
|
||||
session.insert("user_id", &id)?;
|
||||
session.insert("user_id", Value::from(id.clone()));
|
||||
session.renew();
|
||||
|
||||
let counter: i32 = session
|
||||
|
@ -1,5 +1,5 @@
|
||||
use std::{collections::HashMap, convert::TryInto, fmt, future::Future, pin::Pin, rc::Rc};
|
||||
|
||||
use std::{ convert::TryInto, fmt, future::Future, pin::Pin, rc::Rc};
|
||||
use serde_json::{Map,Value};
|
||||
use actix_utils::future::{ready, Ready};
|
||||
use actix_web::{
|
||||
body::MessageBody,
|
||||
@ -360,7 +360,7 @@ fn extract_session_key(req: &ServiceRequest, config: &CookieConfiguration) -> Op
|
||||
async fn load_session_state<Store: SessionStore>(
|
||||
session_key: Option<SessionKey>,
|
||||
storage_backend: &Store,
|
||||
) -> Result<(Option<SessionKey>, HashMap<String, String>), actix_web::Error> {
|
||||
) -> Result<(Option<SessionKey>, Map<String, Value>), actix_web::Error> {
|
||||
if let Some(session_key) = session_key {
|
||||
match storage_backend.load(&session_key).await {
|
||||
Ok(state) => {
|
||||
@ -378,7 +378,7 @@ async fn load_session_state<Store: SessionStore>(
|
||||
empty session."
|
||||
);
|
||||
|
||||
Ok((None, HashMap::new()))
|
||||
Ok((None, Map::new()))
|
||||
}
|
||||
}
|
||||
|
||||
@ -390,14 +390,14 @@ async fn load_session_state<Store: SessionStore>(
|
||||
"Invalid session state, creating a new empty session."
|
||||
);
|
||||
|
||||
Ok((Some(session_key), HashMap::new()))
|
||||
Ok((Some(session_key), Map::new()))
|
||||
}
|
||||
|
||||
LoadError::Other(err) => Err(e500(err)),
|
||||
},
|
||||
}
|
||||
} else {
|
||||
Ok((None, HashMap::new()))
|
||||
Ok((None, Map::new()))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,11 +1,3 @@
|
||||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
collections::HashMap,
|
||||
error::Error as StdError,
|
||||
mem,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
use actix_utils::future::{ready, Ready};
|
||||
use actix_web::{
|
||||
body::BoxBody,
|
||||
@ -15,7 +7,14 @@ use actix_web::{
|
||||
};
|
||||
use anyhow::Context;
|
||||
use derive_more::{Display, From};
|
||||
use serde::{de::DeserializeOwned, Serialize};
|
||||
use serde::de::DeserializeOwned;
|
||||
use serde_json::{Map, Value};
|
||||
use std::{
|
||||
cell::{Ref, RefCell},
|
||||
error::Error as StdError,
|
||||
mem,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
/// The primary interface to access and modify session state.
|
||||
///
|
||||
@ -23,14 +22,15 @@ use serde::{de::DeserializeOwned, Serialize};
|
||||
/// request handlers and it will be automatically extracted from the incoming request.
|
||||
///
|
||||
/// ```
|
||||
/// use serde_json::Value;
|
||||
/// use actix_session::Session;
|
||||
///
|
||||
/// async fn index(session: Session) -> actix_web::Result<&'static str> {
|
||||
/// // access session data
|
||||
/// if let Some(count) = session.get::<i32>("counter")? {
|
||||
/// session.insert("counter", count + 1)?;
|
||||
/// session.insert("counter", Value::from(count + 1));
|
||||
/// } else {
|
||||
/// session.insert("counter", 1)?;
|
||||
/// session.insert("counter", Value::from(1));
|
||||
/// }
|
||||
///
|
||||
/// Ok("Welcome!")
|
||||
@ -70,7 +70,7 @@ pub enum SessionStatus {
|
||||
|
||||
#[derive(Default)]
|
||||
struct SessionInner {
|
||||
state: HashMap<String, String>,
|
||||
state: Map<String, Value>,
|
||||
status: SessionStatus,
|
||||
}
|
||||
|
||||
@ -79,9 +79,9 @@ impl Session {
|
||||
///
|
||||
/// It returns an error if it fails to deserialize as `T` the JSON value associated with `key`.
|
||||
pub fn get<T: DeserializeOwned>(&self, key: &str) -> Result<Option<T>, SessionGetError> {
|
||||
if let Some(val_str) = self.0.borrow().state.get(key) {
|
||||
if let Some(value) = self.0.borrow().state.get(key) {
|
||||
Ok(Some(
|
||||
serde_json::from_str(val_str)
|
||||
serde_json::from_value::<T>(value.clone())
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to deserialize the JSON-encoded session data attached to key \
|
||||
@ -100,7 +100,7 @@ impl Session {
|
||||
/// Get all raw key-value data from the session.
|
||||
///
|
||||
/// Note that values are JSON encoded.
|
||||
pub fn entries(&self) -> Ref<'_, HashMap<String, String>> {
|
||||
pub fn entries(&self) -> Ref<'_, Map<String, Value>> {
|
||||
Ref::map(self.0.borrow(), |inner| &inner.state)
|
||||
}
|
||||
|
||||
@ -111,15 +111,8 @@ impl Session {
|
||||
|
||||
/// Inserts a key-value pair into the session.
|
||||
///
|
||||
/// Any serializable value can be used and will be encoded as JSON in session data, hence why
|
||||
/// only a reference to the value is taken.
|
||||
///
|
||||
/// It returns an error if it fails to serialize `value` to JSON.
|
||||
pub fn insert<T: Serialize>(
|
||||
&self,
|
||||
key: impl Into<String>,
|
||||
value: T,
|
||||
) -> Result<(), SessionInsertError> {
|
||||
/// Any serializable value can be used and will be encoded as JSON in session data.
|
||||
pub fn insert(&self, key: impl Into<String>, value: Value) {
|
||||
let mut inner = self.0.borrow_mut();
|
||||
|
||||
if inner.status != SessionStatus::Purged {
|
||||
@ -127,28 +120,14 @@ impl Session {
|
||||
inner.status = SessionStatus::Changed;
|
||||
}
|
||||
|
||||
let key = key.into();
|
||||
let val = serde_json::to_string(&value)
|
||||
.with_context(|| {
|
||||
format!(
|
||||
"Failed to serialize the provided `{}` type instance as JSON in order to \
|
||||
attach as session data to the `{}` key",
|
||||
std::any::type_name::<T>(),
|
||||
&key
|
||||
)
|
||||
})
|
||||
.map_err(SessionInsertError)?;
|
||||
|
||||
inner.state.insert(key, val);
|
||||
inner.state.insert(key.into(), value);
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Remove value from the session.
|
||||
///
|
||||
/// If present, the JSON encoded value is returned.
|
||||
pub fn remove(&self, key: &str) -> Option<String> {
|
||||
pub fn remove(&self, key: &str) -> Option<Value> {
|
||||
let mut inner = self.0.borrow_mut();
|
||||
|
||||
if inner.status != SessionStatus::Purged {
|
||||
@ -165,9 +144,9 @@ impl Session {
|
||||
///
|
||||
/// Returns `None` if key was not present in session. Returns `T` if deserialization succeeds,
|
||||
/// otherwise returns un-deserialized JSON string.
|
||||
pub fn remove_as<T: DeserializeOwned>(&self, key: &str) -> Option<Result<T, String>> {
|
||||
pub fn remove_as<T: DeserializeOwned>(&self, key: &str) -> Option<Result<T, Value>> {
|
||||
self.remove(key)
|
||||
.map(|val_str| match serde_json::from_str(&val_str) {
|
||||
.map(|value| match serde_json::from_value::<T>(value.clone()) {
|
||||
Ok(val) => Ok(val),
|
||||
Err(_err) => {
|
||||
tracing::debug!(
|
||||
@ -176,7 +155,7 @@ impl Session {
|
||||
std::any::type_name::<T>()
|
||||
);
|
||||
|
||||
Err(val_str)
|
||||
Err(value)
|
||||
}
|
||||
})
|
||||
}
|
||||
@ -216,7 +195,7 @@ impl Session {
|
||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||
pub(crate) fn set_session(
|
||||
req: &mut ServiceRequest,
|
||||
data: impl IntoIterator<Item = (String, String)>,
|
||||
data: impl IntoIterator<Item = (String, Value)>,
|
||||
) {
|
||||
let session = Session::get_session(&mut req.extensions_mut());
|
||||
let mut inner = session.0.borrow_mut();
|
||||
@ -231,7 +210,7 @@ impl Session {
|
||||
#[allow(clippy::needless_pass_by_ref_mut)]
|
||||
pub(crate) fn get_changes<B>(
|
||||
res: &mut ServiceResponse<B>,
|
||||
) -> (SessionStatus, HashMap<String, String>) {
|
||||
) -> (SessionStatus, Map<String, Value>) {
|
||||
if let Some(s_impl) = res
|
||||
.request()
|
||||
.extensions()
|
||||
@ -240,7 +219,7 @@ impl Session {
|
||||
let state = mem::take(&mut s_impl.borrow_mut().state);
|
||||
(s_impl.borrow().status.clone(), state)
|
||||
} else {
|
||||
(SessionStatus::Unchanged, HashMap::new())
|
||||
(SessionStatus::Unchanged, Map::new())
|
||||
}
|
||||
}
|
||||
|
||||
@ -261,15 +240,16 @@ impl Session {
|
||||
/// # Examples
|
||||
/// ```
|
||||
/// # use actix_web::*;
|
||||
/// use serde_json::Value;
|
||||
/// use actix_session::Session;
|
||||
///
|
||||
/// #[get("/")]
|
||||
/// async fn index(session: Session) -> Result<impl Responder> {
|
||||
/// // access session data
|
||||
/// if let Some(count) = session.get::<i32>("counter")? {
|
||||
/// session.insert("counter", count + 1)?;
|
||||
/// session.insert("counter", Value::from(count + 1));
|
||||
/// } else {
|
||||
/// session.insert("counter", 1)?;
|
||||
/// session.insert("counter", Value::from(1));
|
||||
/// }
|
||||
///
|
||||
/// let count = session.get::<i32>("counter")?.unwrap();
|
||||
|
@ -1,11 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use serde_json::{Map,Value};
|
||||
use actix_web::cookie::time::Duration;
|
||||
use derive_more::Display;
|
||||
|
||||
use super::SessionKey;
|
||||
|
||||
pub(crate) type SessionState = HashMap<String, String>;
|
||||
pub(crate) type SessionState = Map<String, Value>;
|
||||
|
||||
/// The interface to retrieve and save the current session data from/to the chosen storage backend.
|
||||
///
|
||||
|
@ -276,9 +276,8 @@ impl SessionStore for RedisActorSessionStore {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix_web::cookie::time::Duration;
|
||||
use serde_json::Map;
|
||||
|
||||
use super::*;
|
||||
use crate::test_helpers::acceptance_test_suite;
|
||||
@ -305,7 +304,7 @@ mod tests {
|
||||
let session_key = generate_session_key();
|
||||
let initial_session_key = session_key.as_ref().to_owned();
|
||||
let updated_session_key = store
|
||||
.update(session_key, HashMap::new(), &Duration::seconds(1))
|
||||
.update(session_key, Map::new(), &Duration::seconds(1))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_ne!(initial_session_key, updated_session_key.as_ref());
|
||||
|
@ -289,10 +289,9 @@ impl RedisSessionStore {
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use std::collections::HashMap;
|
||||
|
||||
use actix_web::cookie::time;
|
||||
use redis::AsyncCommands;
|
||||
use serde_json::Map;
|
||||
|
||||
use super::*;
|
||||
use crate::test_helpers::acceptance_test_suite;
|
||||
@ -338,7 +337,7 @@ mod tests {
|
||||
let session_key = generate_session_key();
|
||||
let initial_session_key = session_key.as_ref().to_owned();
|
||||
let updated_session_key = store
|
||||
.update(session_key, HashMap::new(), &time::Duration::seconds(1))
|
||||
.update(session_key, Map::new(), &time::Duration::seconds(1))
|
||||
.await
|
||||
.unwrap();
|
||||
assert_ne!(initial_session_key, updated_session_key.as_ref());
|
||||
|
@ -3,9 +3,10 @@ use actix_web::{
|
||||
cookie::{time::Duration, Key},
|
||||
test, web, App, Responder,
|
||||
};
|
||||
use serde_json::Value;
|
||||
|
||||
async fn login(session: Session) -> impl Responder {
|
||||
session.insert("user_id", "id").unwrap();
|
||||
session.insert("user_id", Value::from("id"));
|
||||
"Logged in"
|
||||
}
|
||||
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::{collections::HashMap, convert::TryInto};
|
||||
use std::convert::TryInto;
|
||||
|
||||
use actix_session::{
|
||||
storage::{LoadError, SaveError, SessionKey, SessionStore, UpdateError},
|
||||
@ -12,6 +12,7 @@ use actix_web::{
|
||||
test, web, App, Responder,
|
||||
};
|
||||
use anyhow::Error;
|
||||
use serde_json::{Map, Value};
|
||||
|
||||
#[actix_web::test]
|
||||
async fn errors_are_opaque() {
|
||||
@ -49,7 +50,7 @@ impl SessionStore for MockStore {
|
||||
async fn load(
|
||||
&self,
|
||||
_session_key: &SessionKey,
|
||||
) -> Result<Option<HashMap<String, String>>, LoadError> {
|
||||
) -> Result<Option<Map<String, Value>>, LoadError> {
|
||||
Err(LoadError::Other(anyhow::anyhow!(
|
||||
"My error full of implementation details"
|
||||
)))
|
||||
@ -57,7 +58,7 @@ impl SessionStore for MockStore {
|
||||
|
||||
async fn save(
|
||||
&self,
|
||||
_session_state: HashMap<String, String>,
|
||||
_session_state: Map<String, Value>,
|
||||
_ttl: &Duration,
|
||||
) -> Result<SessionKey, SaveError> {
|
||||
Ok("random_value".to_string().try_into().unwrap())
|
||||
@ -66,7 +67,7 @@ impl SessionStore for MockStore {
|
||||
async fn update(
|
||||
&self,
|
||||
_session_key: SessionKey,
|
||||
_session_state: HashMap<String, String>,
|
||||
_session_state: Map<String, Value>,
|
||||
_ttl: &Duration,
|
||||
) -> Result<SessionKey, UpdateError> {
|
||||
#![allow(clippy::diverging_sub_expression)]
|
||||
@ -85,7 +86,7 @@ impl SessionStore for MockStore {
|
||||
}
|
||||
|
||||
async fn create_session(session: Session) -> impl Responder {
|
||||
session.insert("user_id", "id").unwrap();
|
||||
session.insert("user_id", Value::from("id"));
|
||||
"Created"
|
||||
}
|
||||
|
||||
|
@ -1,22 +1,23 @@
|
||||
use actix_session::{SessionExt, SessionStatus};
|
||||
use actix_web::{test, HttpResponse};
|
||||
use serde_json::Value;
|
||||
|
||||
#[actix_web::test]
|
||||
async fn session() {
|
||||
let req = test::TestRequest::default().to_srv_request();
|
||||
let session = req.get_session();
|
||||
session.insert("key", "value").unwrap();
|
||||
session.insert("key", Value::from("value"));
|
||||
let res = session.get::<String>("key").unwrap();
|
||||
assert_eq!(res, Some("value".to_string()));
|
||||
|
||||
session.insert("key2", "value2").unwrap();
|
||||
session.insert("key2", Value::from("value2"));
|
||||
session.remove("key");
|
||||
|
||||
let res = req.into_response(HttpResponse::Ok().finish());
|
||||
let state: Vec<_> = res.get_session().entries().clone().into_iter().collect();
|
||||
assert_eq!(
|
||||
state.as_slice(),
|
||||
[("key2".to_string(), "\"value2\"".to_string())]
|
||||
[("key2".to_string(), Value::from("value2".to_string()))]
|
||||
);
|
||||
}
|
||||
|
||||
@ -25,7 +26,7 @@ async fn get_session() {
|
||||
let req = test::TestRequest::default().to_srv_request();
|
||||
|
||||
let session = req.get_session();
|
||||
session.insert("key", true).unwrap();
|
||||
session.insert("key", Value::from(true));
|
||||
let res = session.get("key").unwrap();
|
||||
assert_eq!(res, Some(true));
|
||||
}
|
||||
@ -35,7 +36,7 @@ async fn get_session_from_request_head() {
|
||||
let req = test::TestRequest::default().to_srv_request();
|
||||
|
||||
let session = req.get_session();
|
||||
session.insert("key", 10).unwrap();
|
||||
session.insert("key", Value::from(10));
|
||||
let res = session.get::<u32>("key").unwrap();
|
||||
assert_eq!(res, Some(10));
|
||||
}
|
||||
@ -62,8 +63,8 @@ async fn renew_session() {
|
||||
async fn session_entries() {
|
||||
let req = test::TestRequest::default().to_srv_request();
|
||||
let session = req.get_session();
|
||||
session.insert("test_str", "val").unwrap();
|
||||
session.insert("test_str", 1).unwrap();
|
||||
session.insert("test_str", Value::from("val"));
|
||||
session.insert("test_str", Value::from(1));
|
||||
let map = session.entries();
|
||||
map.contains_key("test_str");
|
||||
map.contains_key("test_num");
|
||||
@ -73,13 +74,13 @@ async fn session_entries() {
|
||||
async fn insert_session_after_renew() {
|
||||
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||
|
||||
session.insert("test_val", "val").unwrap();
|
||||
session.insert("test_val", Value::from("val"));
|
||||
assert_eq!(session.status(), SessionStatus::Changed);
|
||||
|
||||
session.renew();
|
||||
assert_eq!(session.status(), SessionStatus::Renewed);
|
||||
|
||||
session.insert("test_val1", "val1").unwrap();
|
||||
session.insert("test_val1", Value::from("val1"));
|
||||
assert_eq!(session.status(), SessionStatus::Renewed);
|
||||
}
|
||||
|
||||
@ -87,12 +88,12 @@ async fn insert_session_after_renew() {
|
||||
async fn remove_session_after_renew() {
|
||||
let session = test::TestRequest::default().to_srv_request().get_session();
|
||||
|
||||
session.insert("test_val", "val").unwrap();
|
||||
session.insert("test_val", Value::from("val"));
|
||||
session.remove("test_val").unwrap();
|
||||
assert_eq!(session.status(), SessionStatus::Changed);
|
||||
|
||||
session.renew();
|
||||
session.insert("test_val", "val").unwrap();
|
||||
session.insert("test_val", Value::from("val"));
|
||||
session.remove("test_val").unwrap();
|
||||
assert_eq!(session.status(), SessionStatus::Renewed);
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user