Compare commits

...

2 Commits

Author SHA1 Message Date
6692df9aeb New JWT implementation 2023-08-11 15:25:36 +02:00
26dea34054 New JWT implementation 2023-08-11 15:25:26 +02:00
8 changed files with 309 additions and 54 deletions

116
Cargo.lock generated
View File

@ -26,9 +26,9 @@ dependencies = [
"log", "log",
"once_cell", "once_cell",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"smallvec", "smallvec",
"tokio 1.29.1", "tokio 1.30.0",
"tokio-util 0.7.3", "tokio-util 0.7.3",
] ]
@ -81,8 +81,8 @@ dependencies = [
"futures-sink", "futures-sink",
"log", "log",
"memchr", "memchr",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"tokio 1.29.1", "tokio 1.30.0",
"tokio-util 0.7.3", "tokio-util 0.7.3",
] ]
@ -106,7 +106,7 @@ dependencies = [
"mime", "mime",
"mime_guess", "mime_guess",
"percent-encoding", "percent-encoding",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
] ]
[[package]] [[package]]
@ -149,11 +149,11 @@ dependencies = [
"local-channel", "local-channel",
"mime", "mime",
"percent-encoding", "percent-encoding",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"rand 0.8.5", "rand 0.8.5",
"sha1 0.10.1", "sha1 0.10.1",
"smallvec", "smallvec",
"tokio 1.29.1", "tokio 1.30.0",
"tokio-util 0.7.3", "tokio-util 0.7.3",
"tracing", "tracing",
"zstd", "zstd",
@ -172,10 +172,29 @@ dependencies = [
"jsonwebtoken", "jsonwebtoken",
"serde", "serde",
"time 0.3.25", "time 0.3.25",
"tokio 1.29.1", "tokio 1.30.0",
"tracing", "tracing",
] ]
[[package]]
name = "actix-jwt-session"
version = "0.1.0"
dependencies = [
"actix-web",
"async-trait",
"bincode",
"futures",
"futures-lite",
"futures-util",
"jsonwebtoken",
"redis",
"redis-async-pool",
"serde",
"thiserror",
"tokio 1.30.0",
"uuid",
]
[[package]] [[package]]
name = "actix-macros" name = "actix-macros"
version = "0.2.3" version = "0.2.3"
@ -208,7 +227,7 @@ dependencies = [
"serde_json", "serde_json",
"serde_plain", "serde_plain",
"tempfile", "tempfile",
"tokio 1.29.1", "tokio 1.30.0",
] ]
[[package]] [[package]]
@ -246,7 +265,7 @@ checksum = "15265b6b8e2347670eb363c47fc8c75208b4a4994b27192f345fcbe707804f3e"
dependencies = [ dependencies = [
"actix-macros", "actix-macros",
"futures-core", "futures-core",
"tokio 1.29.1", "tokio 1.30.0",
] ]
[[package]] [[package]]
@ -262,8 +281,8 @@ dependencies = [
"futures-util", "futures-util",
"mio 0.8.8", "mio 0.8.8",
"num_cpus", "num_cpus",
"socket2", "socket2 0.4.9",
"tokio 1.29.1", "tokio 1.30.0",
"tracing", "tracing",
] ]
@ -275,7 +294,7 @@ checksum = "3b894941f818cfdc7ccc4b9e60fa7e53b5042a2e8567270f9147d5591893373a"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"paste", "paste",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
] ]
[[package]] [[package]]
@ -320,7 +339,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94" checksum = "e491cbaac2e7fc788dfff99ff48ef317e23b3cf63dbaf7aaab6418f40f92aa94"
dependencies = [ dependencies = [
"local-waker", "local-waker",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
] ]
[[package]] [[package]]
@ -353,13 +372,13 @@ dependencies = [
"log", "log",
"mime", "mime",
"once_cell", "once_cell",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"regex", "regex",
"serde", "serde",
"serde_json", "serde_json",
"serde_urlencoded", "serde_urlencoded",
"smallvec", "smallvec",
"socket2", "socket2 0.4.9",
"time 0.3.25", "time 0.3.25",
"url", "url",
] ]
@ -640,7 +659,7 @@ dependencies = [
"blocking", "blocking",
"futures-lite", "futures-lite",
"once_cell", "once_cell",
"tokio 1.29.1", "tokio 1.30.0",
] ]
[[package]] [[package]]
@ -658,7 +677,7 @@ dependencies = [
"parking", "parking",
"polling", "polling",
"slab", "slab",
"socket2", "socket2 0.4.9",
"waker-fn", "waker-fn",
"winapi 0.3.9", "winapi 0.3.9",
] ]
@ -693,7 +712,7 @@ dependencies = [
"log", "log",
"memchr", "memchr",
"once_cell", "once_cell",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"pin-utils", "pin-utils",
"slab", "slab",
"wasm-bindgen-futures", "wasm-bindgen-futures",
@ -707,7 +726,7 @@ checksum = "cd56dd203fef61ac097dd65721a419ddccb106b2d2b70ba60a6b529f03961a51"
dependencies = [ dependencies = [
"async-stream-impl", "async-stream-impl",
"futures-core", "futures-core",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
] ]
[[package]] [[package]]
@ -1186,7 +1205,7 @@ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"futures-core", "futures-core",
"memchr", "memchr",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"tokio 0.2.25", "tokio 0.2.25",
] ]
@ -1666,7 +1685,7 @@ dependencies = [
"futures-io", "futures-io",
"memchr", "memchr",
"parking", "parking",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"waker-fn", "waker-fn",
] ]
@ -1706,7 +1725,7 @@ dependencies = [
"futures-sink", "futures-sink",
"futures-task", "futures-task",
"memchr", "memchr",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"pin-utils", "pin-utils",
"slab", "slab",
] ]
@ -1837,7 +1856,7 @@ dependencies = [
"http", "http",
"indexmap 1.9.1", "indexmap 1.9.1",
"slab", "slab",
"tokio 1.29.1", "tokio 1.30.0",
"tokio-util 0.7.3", "tokio-util 0.7.3",
"tracing", "tracing",
] ]
@ -2281,7 +2300,7 @@ dependencies = [
"oswilno-contract", "oswilno-contract",
"sea-orm", "sea-orm",
"sea-orm-migration", "sea-orm-migration",
"tokio 1.29.1", "tokio 1.30.0",
] ]
[[package]] [[package]]
@ -2515,7 +2534,7 @@ dependencies = [
"sea-orm", "sea-orm",
"serde", "serde",
"serde_json", "serde_json",
"tokio 1.29.1", "tokio 1.30.0",
"toml 0.7.6", "toml 0.7.6",
"tracing", "tracing",
"tracing-subscriber", "tracing-subscriber",
@ -2577,7 +2596,7 @@ dependencies = [
"sea-orm", "sea-orm",
"serde", "serde",
"serde_json", "serde_json",
"tokio 1.29.1", "tokio 1.30.0",
] ]
[[package]] [[package]]
@ -2604,7 +2623,7 @@ dependencies = [
"sea-orm", "sea-orm",
"serde", "serde",
"time 0.3.25", "time 0.3.25",
"tokio 1.29.1", "tokio 1.30.0",
"tracing", "tracing",
"uuid", "uuid",
] ]
@ -2861,9 +2880,9 @@ checksum = "257b64915a082f7811703966789728173279bdebb956b143dbcd23f6f970a777"
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.9" version = "0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e0a7ae3ac2f1173085d398531c705756c94a4c56843785df85a60c1a0afac116" checksum = "12cc1b0bf1727a77a54b6654e7b5f1af8604923edc8b81885f8ec92f9e3f0a05"
[[package]] [[package]]
name = "pin-utils" name = "pin-utils"
@ -3713,6 +3732,16 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "socket2"
version = "0.5.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2538b18701741680e0322a2302176d3253a35388e2e62f172f64f4f16605f877"
dependencies = [
"libc",
"windows-sys 0.48.0",
]
[[package]] [[package]]
name = "spez" name = "spez"
version = "0.1.2" version = "0.1.2"
@ -3835,7 +3864,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024" checksum = "804d3f245f894e61b1e6263c84b23ca675d96753b5abfd5cc8597d86806e8024"
dependencies = [ dependencies = [
"once_cell", "once_cell",
"tokio 1.29.1", "tokio 1.30.0",
"tokio-rustls", "tokio-rustls",
] ]
@ -4045,25 +4074,24 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "46409491c9375a693ce7032101970a54f8a2010efb77e13f70788f0d84489e39" checksum = "46409491c9375a693ce7032101970a54f8a2010efb77e13f70788f0d84489e39"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
] ]
[[package]] [[package]]
name = "tokio" name = "tokio"
version = "1.29.1" version = "1.30.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "532826ff75199d5833b9d2c5fe410f29235e25704ee5f0ef599fb51c21f4a4da" checksum = "2d3ce25f50619af8b0aec2eb23deebe84249e19e2ddd393a6e16e3300a6dadfd"
dependencies = [ dependencies = [
"autocfg",
"backtrace", "backtrace",
"bytes 1.1.0", "bytes 1.1.0",
"libc", "libc",
"mio 0.8.8", "mio 0.8.8",
"num_cpus", "num_cpus",
"parking_lot 0.12.1", "parking_lot 0.12.1",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"signal-hook-registry", "signal-hook-registry",
"socket2", "socket2 0.5.3",
"tokio-macros", "tokio-macros",
"windows-sys 0.48.0", "windows-sys 0.48.0",
] ]
@ -4086,7 +4114,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59" checksum = "c43ee83903113e03984cb9e5cebe6c04a5116269e900e3ddba8f068a62adda59"
dependencies = [ dependencies = [
"rustls", "rustls",
"tokio 1.29.1", "tokio 1.30.0",
"webpki", "webpki",
] ]
@ -4097,8 +4125,8 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9" checksum = "df54d54117d6fdc4e4fea40fe1e4e566b3505700e148a6827e59b34b0d2600d9"
dependencies = [ dependencies = [
"futures-core", "futures-core",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"tokio 1.29.1", "tokio 1.30.0",
] ]
[[package]] [[package]]
@ -4124,8 +4152,8 @@ dependencies = [
"bytes 1.1.0", "bytes 1.1.0",
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"tokio 1.29.1", "tokio 1.30.0",
"tracing", "tracing",
] ]
@ -4180,7 +4208,7 @@ checksum = "8ce8c33a8d48bd45d624a6e523445fd21ec13d3653cd51f681abf67418f54eb8"
dependencies = [ dependencies = [
"cfg-if 1.0.0", "cfg-if 1.0.0",
"log", "log",
"pin-project-lite 0.2.9", "pin-project-lite 0.2.12",
"tracing-attributes", "tracing-attributes",
"tracing-core", "tracing-core",
] ]
@ -4542,7 +4570,7 @@ dependencies = [
"askama", "askama",
"serde", "serde",
"serde_json", "serde_json",
"tokio 1.29.1", "tokio 1.30.0",
] ]
[[package]] [[package]]

View File

@ -6,4 +6,5 @@ members = [
'./crates/oswilno-parking-space', './crates/oswilno-parking-space',
'./crates/migration', './crates/migration',
'./crates/oswilno-actix-admin', './crates/oswilno-actix-admin',
'./crates/actix-jwt-session',
] ]

View File

@ -0,0 +1,23 @@
[package]
name = "actix-jwt-session"
version = "0.1.0"
edition = "2021"
[features]
default = ['use-redis']
use-redis = ["redis", "redis-async-pool"]
[dependencies]
actix-web = "4"
async-trait = "0.1.72"
bincode = "1.3.3"
futures = "0.3.28"
futures-lite = "1.13.0"
futures-util = { version = "0.3.28", features = ['async-await'] }
jsonwebtoken = "8.3.0"
redis = { version = "0.17", optional = true }
redis-async-pool = { version = "0.2.4", optional = true }
serde = { version = "1.0.183", features = ["derive"] }
thiserror = "1.0.44"
tokio = { version = "1.30.0", features = ["full"] }
uuid = { version = "1.4.1", features = ["v4"] }

View File

@ -0,0 +1,85 @@
use actix_web::dev::ServiceRequest;
use actix_web::HttpMessage;
use jsonwebtoken::{decode, DecodingKey, Validation};
use serde::{de::DeserializeOwned, Serialize};
use std::sync::Arc;
pub trait Claims: PartialEq + DeserializeOwned + Serialize + Clone + Send + Sync + 'static {
fn jti(&self) -> uuid::Uuid;
}
#[derive(Debug, thiserror::Error, PartialEq)]
pub enum Error {
#[error("Failed to obtain redis connection")]
RedisConn,
#[error("Record not found")]
NotFound,
#[error("Record malformed")]
RecordMalformed,
#[error("Invalid session")]
InvalidSession,
#[error("No http authentication header")]
NoAuthHeader,
}
impl actix_web::ResponseError for Error {
fn status_code(&self) -> actix_web::http::StatusCode {
match self {
Self::RedisConn => actix_web::http::StatusCode::INTERNAL_SERVER_ERROR,
_ => actix_web::http::StatusCode::UNAUTHORIZED,
}
}
}
pub struct Authenticated<T>(Arc<T>);
#[async_trait::async_trait(?Send)]
pub trait TokenStorage {
type ClaimsType: Claims;
async fn get_from_jti(self: Arc<Self>, jti: uuid::Uuid) -> Result<Self::ClaimsType, Error>;
}
struct Extractor;
impl Extractor {
async fn extract_bearer_jwt<ClaimsType: Claims>(
req: &ServiceRequest,
jwt_decoding_key: Arc<DecodingKey>,
jwt_validator: Arc<Validation>,
storage: Arc<dyn TokenStorage<ClaimsType = ClaimsType>>,
) -> Result<(), Error> {
let authorisation_header = req
.headers()
.get("Authorization")
.ok_or(Error::NoAuthHeader)?;
let as_str = authorisation_header
.to_str()
.map_err(|_| Error::NoAuthHeader)?;
let decoded_claims = decode::<ClaimsType>(as_str, &*jwt_decoding_key, &*jwt_validator)
.map_err(|_e| {
// let error_message = e.to_string();
Error::InvalidSession
})?;
let stored = storage
.get_from_jti(decoded_claims.claims.jti())
.await
.map_err(|_| Error::InvalidSession)?;
if stored != decoded_claims.claims {
return Err(Error::InvalidSession);
}
req.extensions_mut()
.insert(Authenticated(Arc::new(decoded_claims.claims)));
Ok(())
}
}
#[cfg(feature = "redis")]
mod redis_adapter;
#[cfg(feature = "redis")]
pub use redis_adapter::*;

View File

@ -0,0 +1,100 @@
use super::*;
use actix_web::dev::{forward_ready, Service, ServiceRequest, ServiceResponse};
use futures_util::future::LocalBoxFuture;
use jsonwebtoken::{DecodingKey, Validation};
use redis::AsyncCommands;
use std::marker::PhantomData;
use std::rc::Rc;
use std::sync::Arc;
#[derive(Clone)]
pub struct RedisStorage<ClaimsType: Claims> {
pool: redis_async_pool::RedisPool,
_claims_type_marker: PhantomData<ClaimsType>,
}
impl<ClaimsType: Claims> RedisStorage<ClaimsType> {
pub fn new(pool: redis_async_pool::RedisPool) -> Self {
Self {
pool,
_claims_type_marker: Default::default(),
}
}
}
#[async_trait::async_trait(?Send)]
impl<ClaimsType> TokenStorage for RedisStorage<ClaimsType>
where
ClaimsType: Claims,
{
type ClaimsType = ClaimsType;
async fn get_from_jti(self: Arc<Self>, jti: uuid::Uuid) -> Result<ClaimsType, Error> {
let pool = self.pool.clone();
let mut conn = pool.get().await.map_err(|_| Error::RedisConn)?;
let val = conn
.get::<_, Vec<u8>>(jti.as_bytes())
.await
.map_err(|_| Error::NotFound)?;
bincode::deserialize(&val).map_err(|_| Error::RecordMalformed)
}
}
pub struct RedisMiddleware<S, ClaimsType>
where
ClaimsType: Claims,
{
_claims_type_marker: std::marker::PhantomData<ClaimsType>,
service: Rc<S>,
jwt_decoding_key: Arc<DecodingKey>,
jwt_validator: Arc<Validation>,
storage: Arc<RedisStorage<ClaimsType>>,
}
impl<S, B, ClaimsType> Service<ServiceRequest> for RedisMiddleware<S, ClaimsType>
where
ClaimsType: Claims,
S: Service<ServiceRequest, Response = ServiceResponse<B>, Error = actix_web::Error> + 'static,
{
type Response = ServiceResponse<B>;
type Error = actix_web::Error;
type Future = LocalBoxFuture<'static, Result<Self::Response, Self::Error>>;
forward_ready!(service);
fn call(&self, req: ServiceRequest) -> Self::Future {
use futures_lite::FutureExt;
let svc = self.service.clone();
let jwt_decoding_key = self.jwt_decoding_key.clone();
let validation = self.jwt_validator.clone();
let storage = self.storage.clone();
async move {
Extractor::extract_bearer_jwt(&req, jwt_decoding_key, validation, storage).await?;
let res = svc.call(req).await?;
Ok(res)
}
.boxed_local()
}
}
#[cfg(test)]
mod tests {
use super::*;
use serde::{Deserialize, Serialize};
#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)]
struct Out {
id: uuid::Uuid,
}
impl Claims for Out {
fn jti(&self) -> uuid::Uuid {
self.id
}
}
#[tokio::test]
async fn extract() {
}
}

View File

@ -11,9 +11,7 @@ impl MigrationTrait for Migration {
m.alter_table( m.alter_table(
Table::alter() Table::alter()
.table(ParkingSpace::ParkingSpaces) .table(ParkingSpace::ParkingSpaces)
.add_column( .add_column(ColumnDef::new(ParkingSpace::Spot).integer())
ColumnDef::new(ParkingSpace::Spot)
.integer())
.to_owned(), .to_owned(),
) )
.await?; .await?;

View File

@ -0,0 +1 @@

View File

@ -4,7 +4,7 @@ use std::sync::Arc;
use actix_jwt_authc::*; use actix_jwt_authc::*;
use actix_web::web::{Data, Form, ServiceConfig}; use actix_web::web::{Data, Form, ServiceConfig};
use actix_web::{get, post, HttpResponse}; use actix_web::{get, post, HttpResponse};
use askama_actix::{Template, TemplateToResponse as _}; use askama_actix::Template;
use autometrics::autometrics; use autometrics::autometrics;
use futures::channel::{mpsc, mpsc::Sender}; use futures::channel::{mpsc, mpsc::Sender};
use futures::stream::Stream; use futures::stream::Stream;
@ -20,6 +20,7 @@ use time::ext::*;
use time::OffsetDateTime; use time::OffsetDateTime;
use tokio::sync::Mutex; use tokio::sync::Mutex;
mod extract_session;
mod hashing; mod hashing;
pub use oswilno_view::filters; pub use oswilno_view::filters;
@ -30,11 +31,13 @@ pub type UserSession = Authenticated<Claims>;
pub struct JWTTtl(time::Duration); pub struct JWTTtl(time::Duration);
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
#[serde(rename_all = "snake_case")]
enum Audience { enum Audience {
Web, Web,
} }
#[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)] #[derive(Debug, Serialize, Deserialize, Clone, Eq, PartialEq, Hash)]
#[serde(rename_all = "snake_case")]
pub struct Claims { pub struct Claims {
#[serde(rename = "exp")] #[serde(rename = "exp")]
expires_at: usize, expires_at: usize,
@ -196,7 +199,7 @@ async fn login(
let mut errors = Errors::default(); let mut errors = Errors::default();
match login_inner( match login_inner(
jwt_encoding_key, jwt_encoding_key,
jwt_ttl, jwt_ttl.into_inner(),
payload.into_inner(), payload.into_inner(),
db.into_inner(), db.into_inner(),
redis.into_inner(), redis.into_inner(),
@ -206,7 +209,12 @@ async fn login(
{ {
Ok(res) => Ok(HttpResponse::Ok().json(res)), Ok(res) => Ok(HttpResponse::Ok().json(res)),
Err(form) => Ok(HttpResponse::Ok().body( Err(form) => Ok(HttpResponse::Ok().body(
(SignInPartialTemplate { form, lang, t, errors }) (SignInPartialTemplate {
form,
lang,
t,
errors,
})
.render() .render()
.unwrap(), .unwrap(),
)), )),
@ -215,7 +223,7 @@ async fn login(
async fn login_inner( async fn login_inner(
jwt_encoding_key: Data<EncodingKey>, jwt_encoding_key: Data<EncodingKey>,
jwt_ttl: Data<JWTTtl>, jwt_ttl: Arc<JWTTtl>,
payload: SignInPayload, payload: SignInPayload,
db: Arc<DatabaseConnection>, db: Arc<DatabaseConnection>,
redis: Arc<redis_async_pool::RedisPool>, redis: Arc<redis_async_pool::RedisPool>,
@ -274,8 +282,13 @@ async fn login_inner(
errors.push_global("Failed to sign in. Please try later"); errors.push_global("Failed to sign in. Please try later");
return Err(payload); return Err(payload);
}; };
if let Err(e) = conn if let Err(e) = conn
.set::<'_, _, _, String>(jwt_claims.jwt_id.as_bytes(), bin_value) .set_ex::<'_, _, _, String>(
jwt_claims.jwt_id.as_bytes(),
bin_value,
jwt_ttl.0.as_seconds_f32() as usize,
)
.await .await
{ {
tracing::warn!("Failed to set sign-in claims in redis: {e}"); tracing::warn!("Failed to set sign-in claims in redis: {e}");
@ -298,10 +311,16 @@ async fn session_info(authenticated: UserSession) -> Result<HttpResponse, Error>
#[autometrics] #[autometrics]
#[get("/logout")] #[get("/logout")]
async fn logout( async fn logout(
invalidated_jwts: Data<InvalidatedJWTStore>,
authenticated: Authenticated<Claims>, authenticated: Authenticated<Claims>,
redis: Data<redis_async_pool::RedisPool>,
) -> Result<HttpResponse, Error> { ) -> Result<HttpResponse, Error> {
invalidated_jwts.add_to_invalidated(authenticated).await; {
use redis::AsyncCommands;
let jwt_id = authenticated.claims.jwt_id;
if let Ok(mut conn) = redis.get().await {
if conn.del::<_, String>(jwt_id.as_bytes()).await.is_err() {}
}
}
Ok(HttpResponse::Ok().json(EmptyResponse {})) Ok(HttpResponse::Ok().json(EmptyResponse {}))
} }