1
0
mirror of https://github.com/actix/actix-extras.git synced 2024-11-24 07:53:00 +01:00

updated session logic to support login and logout functionality

This commit is contained in:
dowwie 2019-06-12 08:14:18 -04:00
parent c7266e3ddd
commit fa531fb03d
2 changed files with 68 additions and 10 deletions

1
.gitignore vendored
View File

@ -2,6 +2,7 @@ Cargo.lock
target/ target/
guide/build/ guide/build/
/gh-pages /gh-pages
/.history
*.so *.so
*.out *.out

View File

@ -1,10 +1,7 @@
use std::collections::HashMap; use std::{collections::HashMap, iter, rc::Rc};
use std::iter;
use std::rc::Rc;
use actix::prelude::*; use actix::prelude::*;
use actix_service::{Service, Transform}; use actix_service::{Service, Transform};
use actix_session::Session; use actix_session::{Session, SessionStatus};
use actix_utils::cloneable::CloneableService; use actix_utils::cloneable::CloneableService;
use actix_web::cookie::{Cookie, CookieJar, Key, SameSite}; use actix_web::cookie::{Cookie, CookieJar, Key, SameSite};
use actix_web::dev::{ServiceRequest, ServiceResponse}; use actix_web::dev::{ServiceRequest, ServiceResponse};
@ -14,7 +11,7 @@ use futures::future::{err, ok, Either, Future, FutureResult};
use futures::Poll; use futures::Poll;
use rand::{distributions::Alphanumeric, rngs::OsRng, Rng}; use rand::{distributions::Alphanumeric, rngs::OsRng, Rng};
use redis_async::resp::RespValue; use redis_async::resp::RespValue;
use time::Duration; use time::{self, Duration};
use crate::redis::{Command, RedisActor}; use crate::redis::{Command, RedisActor};
@ -147,10 +144,32 @@ where
}; };
srv.call(req).and_then(move |mut res| { srv.call(req).and_then(move |mut res| {
if let Some(state) = Session::get_changes(&mut res) { match Session::get_changes(&mut res) {
Either::A(inner.update(res, state, value)) (SessionStatus::Unchanged, _) =>
} else { Either::A(Either::A(ok(res))),
Either::B(ok(res)) (SessionStatus::Changed, Some(state)) =>
Either::B(Either::A(inner.update(res, state, value))),
(SessionStatus::Purged, Some(_)) => {
Either::B(Either::B(
inner.clear_cache(value)
.and_then(move |_|
match inner.remove_cookie(&mut res){
Ok(_) => Either::A(ok(res)),
Err(_err) => Either::B(err(
error::ErrorInternalServerError(_err)))
})
))
},
(SessionStatus::Renewed, Some(state)) => {
Either::A(
Either::B(
inner.clear_cache(value)
.and_then(move |_|
inner.update(res, state, None))
)
)
},
(_, None) => unreachable!()
} }
}) })
})) }))
@ -289,4 +308,42 @@ impl Inner {
), ),
} }
} }
/// removes cache entry
fn clear_cache(&self, value: Option<String>)
-> impl Future<Item=(), Error=Error> {
if let Some(key) = value {
Either::A(
self.addr
.send(Command(resp_array!["DEL", key]))
.map_err(Error::from)
.and_then(|res|
match res {
// redis responds with number of deleted records
Ok(RespValue::Integer(x)) if x > 0 => Ok(()),
_ => Err(error::ErrorInternalServerError(
"failed to remove session from cache"))
}
)
)
} else {
Either::B(err(error::ErrorInternalServerError(
"missing session key - unexpected")))
}
}
/// invalidates session cookie
fn remove_cookie<B>(&self, res: &mut ServiceResponse<B>)
-> Result<(), Error> {
let mut cookie = Cookie::named(self.name.clone());
cookie.set_value("");
cookie.set_max_age(Duration::seconds(0));
cookie.set_expires(time::now() - Duration::days(365));
let val = HeaderValue::from_str(&cookie.to_string())
.map_err(|err| error::ErrorInternalServerError(err))?;
res.headers_mut().append(header::SET_COOKIE, val);
Ok(())
}
} }