Skip to content
Clone
fad06fd
110 lines 2.6 KB Rust
use std::fmt::Debug;
use serde::{Deserialize, Serialize};
use session::{DatabasePool, ReadOnlySession as AxumReadOnlySession, Session as AxumSession};
use uuid::Uuid;
pub const UID_KEY: &str = "auth:uid";
pub const USERS_KEY: &str = "auth:users";
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AuthUser {
pub uid: Uuid,
pub username: String,
pub display_name: Option<String>,
pub avatar_url: Option<String>,
pub email: String,
}
pub trait SessionUser {
fn uid(&self) -> Option<Uuid>;
fn user(&self) -> Option<AuthUser> {
let uid = self.uid()?;
self.users().into_iter().find(|user| user.uid == uid)
}
fn users(&self) -> Vec<AuthUser>;
fn is_authenticated(&self) -> bool {
self.uid().is_some()
}
}
pub trait SessionUserMut: SessionUser {
fn login_user(&self, user: AuthUser);
fn switch_uid(&self, uid: Uuid) -> bool;
fn clear_uid(&self);
fn logout_user(&self, uid: Uuid) -> bool;
}
macro_rules! impl_session_user {
($ty:ident) => {
impl<D> SessionUser for $ty<D>
where
D: DatabasePool + Clone + Debug + Sync + Send + 'static,
{
fn uid(&self) -> Option<Uuid> {
self.get::<Uuid>(UID_KEY)
}
fn users(&self) -> Vec<AuthUser> {
self.get::<Vec<AuthUser>>(USERS_KEY).unwrap_or_default()
}
}
};
}
impl_session_user!(AxumSession);
impl_session_user!(AxumReadOnlySession);
impl<D> SessionUserMut for AxumSession<D>
where
D: DatabasePool + Clone + Debug + Sync + Send + 'static,
{
fn login_user(&self, user: AuthUser) {
let uid = user.uid;
let mut users = self.users();
users.retain(|existing| existing.uid != uid);
users.push(user);
self.set(USERS_KEY, users);
self.set(UID_KEY, uid);
}
fn switch_uid(&self, uid: Uuid) -> bool {
if self.users().iter().any(|user| user.uid == uid) {
self.set(UID_KEY, uid);
true
} else {
false
}
}
fn clear_uid(&self) {
self.remove(UID_KEY);
}
fn logout_user(&self, uid: Uuid) -> bool {
let mut users = self.users();
let was_active = self.uid() == Some(uid);
let before = users.len();
users.retain(|user| user.uid != uid);
if users.len() == before {
return false;
}
if was_active {
match users.last() {
Some(remainder) => self.set(UID_KEY, remainder.uid),
None => self.remove(UID_KEY),
}
}
self.set(USERS_KEY, users);
true
}
}