mirror of
https://github.com/actix/actix-extras.git
synced 2025-02-17 08:33:30 +01:00
Add the ability to change the keys (#348)
* feat: add the ability to change the session key store in redis * feat: change everywhere the constants are used * refactor: add formatting with cargo fmt --------- Co-authored-by: Dany Gagnon <danygagnon@Danys-MacBook-Pro.local>
This commit is contained in:
parent
daffc24245
commit
5414e2655b
@ -9,6 +9,9 @@ pub(crate) struct Configuration {
|
|||||||
pub(crate) on_logout: LogoutBehaviour,
|
pub(crate) on_logout: LogoutBehaviour,
|
||||||
pub(crate) login_deadline: Option<Duration>,
|
pub(crate) login_deadline: Option<Duration>,
|
||||||
pub(crate) visit_deadline: Option<Duration>,
|
pub(crate) visit_deadline: Option<Duration>,
|
||||||
|
pub(crate) id_key: &'static str,
|
||||||
|
pub(crate) last_visit_unix_timestamp_key: &'static str,
|
||||||
|
pub(crate) login_unix_timestamp_key: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Configuration {
|
impl Default for Configuration {
|
||||||
@ -17,6 +20,9 @@ impl Default for Configuration {
|
|||||||
on_logout: LogoutBehaviour::PurgeSession,
|
on_logout: LogoutBehaviour::PurgeSession,
|
||||||
login_deadline: None,
|
login_deadline: None,
|
||||||
visit_deadline: None,
|
visit_deadline: None,
|
||||||
|
id_key: "actix_identity.user_id",
|
||||||
|
last_visit_unix_timestamp_key: "actix_identity.last_visited_at",
|
||||||
|
login_unix_timestamp_key: "actix_identity.logged_in_at",
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -58,6 +64,24 @@ impl IdentityMiddlewareBuilder {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a custom key to identify the user in the session.
|
||||||
|
pub fn id_key(mut self, key: &'static str) -> Self {
|
||||||
|
self.configuration.id_key = key;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a custom key to store the last visited unix timestamp.
|
||||||
|
pub fn last_visit_unix_timestamp_key(mut self, key: &'static str) -> Self {
|
||||||
|
self.configuration.last_visit_unix_timestamp_key = key;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Set a custom key to store the login unix timestamp.
|
||||||
|
pub fn login_unix_timestamp_key(mut self, key: &'static str) -> Self {
|
||||||
|
self.configuration.login_unix_timestamp_key = key;
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
/// Determines how [`Identity::logout`](crate::Identity::logout) affects the current session.
|
/// Determines how [`Identity::logout`](crate::Identity::logout) affects the current session.
|
||||||
///
|
///
|
||||||
/// By default, the current session is purged ([`LogoutBehaviour::PurgeSession`]).
|
/// By default, the current session is purged ([`LogoutBehaviour::PurgeSession`]).
|
||||||
|
@ -82,6 +82,9 @@ pub(crate) struct IdentityInner {
|
|||||||
pub(crate) logout_behaviour: LogoutBehaviour,
|
pub(crate) logout_behaviour: LogoutBehaviour,
|
||||||
pub(crate) is_login_deadline_enabled: bool,
|
pub(crate) is_login_deadline_enabled: bool,
|
||||||
pub(crate) is_visit_deadline_enabled: bool,
|
pub(crate) is_visit_deadline_enabled: bool,
|
||||||
|
pub(crate) id_key: &'static str,
|
||||||
|
pub(crate) last_visit_unix_timestamp_key: &'static str,
|
||||||
|
pub(crate) login_unix_timestamp_key: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl IdentityInner {
|
impl IdentityInner {
|
||||||
@ -101,15 +104,11 @@ impl IdentityInner {
|
|||||||
/// Retrieve the user id attached to the current session.
|
/// Retrieve the user id attached to the current session.
|
||||||
fn get_identity(&self) -> Result<String, GetIdentityError> {
|
fn get_identity(&self) -> Result<String, GetIdentityError> {
|
||||||
self.session
|
self.session
|
||||||
.get::<String>(ID_KEY)?
|
.get::<String>(self.id_key)?
|
||||||
.ok_or_else(|| MissingIdentityError.into())
|
.ok_or_else(|| MissingIdentityError.into())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) const ID_KEY: &str = "actix_identity.user_id";
|
|
||||||
pub(crate) const LAST_VISIT_UNIX_TIMESTAMP_KEY: &str = "actix_identity.last_visited_at";
|
|
||||||
pub(crate) const LOGIN_UNIX_TIMESTAMP_KEY: &str = "actix_identity.logged_in_at";
|
|
||||||
|
|
||||||
impl Identity {
|
impl Identity {
|
||||||
/// Return the user id associated to the current session.
|
/// Return the user id associated to the current session.
|
||||||
///
|
///
|
||||||
@ -130,7 +129,7 @@ impl Identity {
|
|||||||
pub fn id(&self) -> Result<String, GetIdentityError> {
|
pub fn id(&self) -> Result<String, GetIdentityError> {
|
||||||
self.0
|
self.0
|
||||||
.session
|
.session
|
||||||
.get(ID_KEY)?
|
.get(self.0.id_key)?
|
||||||
.ok_or_else(|| LostIdentityError.into())
|
.ok_or_else(|| LostIdentityError.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -153,13 +152,15 @@ impl Identity {
|
|||||||
/// ```
|
/// ```
|
||||||
pub fn login(ext: &Extensions, id: String) -> Result<Self, LoginError> {
|
pub fn login(ext: &Extensions, id: String) -> Result<Self, LoginError> {
|
||||||
let inner = IdentityInner::extract(ext);
|
let inner = IdentityInner::extract(ext);
|
||||||
inner.session.insert(ID_KEY, id)?;
|
inner.session.insert(inner.id_key, id)?;
|
||||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||||
if inner.is_login_deadline_enabled {
|
if inner.is_login_deadline_enabled {
|
||||||
inner.session.insert(LOGIN_UNIX_TIMESTAMP_KEY, now)?;
|
inner.session.insert(inner.login_unix_timestamp_key, now)?;
|
||||||
}
|
}
|
||||||
if inner.is_visit_deadline_enabled {
|
if inner.is_visit_deadline_enabled {
|
||||||
inner.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)?;
|
inner
|
||||||
|
.session
|
||||||
|
.insert(inner.last_visit_unix_timestamp_key, now)?;
|
||||||
}
|
}
|
||||||
inner.session.renew();
|
inner.session.renew();
|
||||||
Ok(Self(inner))
|
Ok(Self(inner))
|
||||||
@ -191,12 +192,12 @@ impl Identity {
|
|||||||
self.0.session.purge();
|
self.0.session.purge();
|
||||||
}
|
}
|
||||||
LogoutBehaviour::DeleteIdentityKeys => {
|
LogoutBehaviour::DeleteIdentityKeys => {
|
||||||
self.0.session.remove(ID_KEY);
|
self.0.session.remove(self.0.id_key);
|
||||||
if self.0.is_login_deadline_enabled {
|
if self.0.is_login_deadline_enabled {
|
||||||
self.0.session.remove(LOGIN_UNIX_TIMESTAMP_KEY);
|
self.0.session.remove(self.0.login_unix_timestamp_key);
|
||||||
}
|
}
|
||||||
if self.0.is_visit_deadline_enabled {
|
if self.0.is_visit_deadline_enabled {
|
||||||
self.0.session.remove(LAST_VISIT_UNIX_TIMESTAMP_KEY);
|
self.0.session.remove(self.0.last_visit_unix_timestamp_key);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -212,7 +213,7 @@ impl Identity {
|
|||||||
Ok(self
|
Ok(self
|
||||||
.0
|
.0
|
||||||
.session
|
.session
|
||||||
.get(LOGIN_UNIX_TIMESTAMP_KEY)?
|
.get(self.0.login_unix_timestamp_key)?
|
||||||
.map(OffsetDateTime::from_unix_timestamp)
|
.map(OffsetDateTime::from_unix_timestamp)
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(SessionExpiryError)?)
|
.map_err(SessionExpiryError)?)
|
||||||
@ -222,7 +223,7 @@ impl Identity {
|
|||||||
Ok(self
|
Ok(self
|
||||||
.0
|
.0
|
||||||
.session
|
.session
|
||||||
.get(LAST_VISIT_UNIX_TIMESTAMP_KEY)?
|
.get(self.0.last_visit_unix_timestamp_key)?
|
||||||
.map(OffsetDateTime::from_unix_timestamp)
|
.map(OffsetDateTime::from_unix_timestamp)
|
||||||
.transpose()
|
.transpose()
|
||||||
.map_err(SessionExpiryError)?)
|
.map_err(SessionExpiryError)?)
|
||||||
@ -230,7 +231,9 @@ impl Identity {
|
|||||||
|
|
||||||
pub(crate) fn set_last_visited_at(&self) -> Result<(), LoginError> {
|
pub(crate) fn set_last_visited_at(&self) -> Result<(), LoginError> {
|
||||||
let now = OffsetDateTime::now_utc().unix_timestamp();
|
let now = OffsetDateTime::now_utc().unix_timestamp();
|
||||||
self.0.session.insert(LAST_VISIT_UNIX_TIMESTAMP_KEY, now)?;
|
self.0
|
||||||
|
.session
|
||||||
|
.insert(self.0.last_visit_unix_timestamp_key, now)?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -114,6 +114,9 @@ where
|
|||||||
logout_behaviour: configuration.on_logout.clone(),
|
logout_behaviour: configuration.on_logout.clone(),
|
||||||
is_login_deadline_enabled: configuration.login_deadline.is_some(),
|
is_login_deadline_enabled: configuration.login_deadline.is_some(),
|
||||||
is_visit_deadline_enabled: configuration.visit_deadline.is_some(),
|
is_visit_deadline_enabled: configuration.visit_deadline.is_some(),
|
||||||
|
id_key: configuration.id_key,
|
||||||
|
last_visit_unix_timestamp_key: configuration.last_visit_unix_timestamp_key,
|
||||||
|
login_unix_timestamp_key: configuration.login_unix_timestamp_key,
|
||||||
};
|
};
|
||||||
req.extensions_mut().insert(identity_inner);
|
req.extensions_mut().insert(identity_inner);
|
||||||
enforce_policies(&req, &configuration);
|
enforce_policies(&req, &configuration);
|
||||||
|
@ -28,6 +28,33 @@ async fn login_works() {
|
|||||||
assert!(response.status().is_success());
|
assert!(response.status().is_success());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[actix_web::test]
|
||||||
|
async fn custom_keys_work_as_expected() {
|
||||||
|
let custom_id_key = "custom.user_id";
|
||||||
|
let custom_last_visited_key = "custom.last_visited_at";
|
||||||
|
let custom_logged_in_key = "custom.logged_in_at";
|
||||||
|
|
||||||
|
let app = TestApp::spawn_with_config(
|
||||||
|
IdentityMiddleware::builder()
|
||||||
|
.id_key(custom_id_key)
|
||||||
|
.last_visit_unix_timestamp_key(custom_last_visited_key)
|
||||||
|
.login_unix_timestamp_key(custom_logged_in_key),
|
||||||
|
);
|
||||||
|
let user_id = user_id();
|
||||||
|
|
||||||
|
let body = app.post_login(user_id.clone()).await;
|
||||||
|
assert_eq!(body.user_id, Some(user_id.clone()));
|
||||||
|
|
||||||
|
let response = app.get_identity_required().await;
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
let response = app.post_logout().await;
|
||||||
|
assert!(response.status().is_success());
|
||||||
|
|
||||||
|
let response = app.get_identity_required().await;
|
||||||
|
assert_eq!(response.status(), StatusCode::UNAUTHORIZED);
|
||||||
|
}
|
||||||
|
|
||||||
#[actix_web::test]
|
#[actix_web::test]
|
||||||
async fn logging_in_again_replaces_the_current_identity() {
|
async fn logging_in_again_replaces_the_current_identity() {
|
||||||
let app = TestApp::spawn();
|
let app = TestApp::spawn();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user