feat: refresh token
This commit is contained in:
4
crates/domain/src/auth/mod.rs
Normal file
4
crates/domain/src/auth/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod ports;
|
||||
pub mod refresh_session;
|
||||
|
||||
pub use refresh_session::{RefreshSession, RefreshSessionId};
|
||||
14
crates/domain/src/auth/ports.rs
Normal file
14
crates/domain/src/auth/ports.rs
Normal file
@@ -0,0 +1,14 @@
|
||||
use async_trait::async_trait;
|
||||
|
||||
use super::RefreshSession;
|
||||
use crate::errors::DomainResult;
|
||||
use crate::user::UserId;
|
||||
|
||||
#[async_trait]
|
||||
pub trait RefreshSessionRepository: Send + Sync {
|
||||
async fn create(&self, session: &RefreshSession) -> DomainResult<()>;
|
||||
async fn find_by_token(&self, token: &str) -> DomainResult<Option<RefreshSession>>;
|
||||
async fn revoke(&self, token: &str) -> DomainResult<()>;
|
||||
async fn revoke_all_for_user(&self, user_id: &UserId) -> DomainResult<()>;
|
||||
async fn delete_expired(&self) -> DomainResult<u64>;
|
||||
}
|
||||
83
crates/domain/src/auth/refresh_session.rs
Normal file
83
crates/domain/src/auth/refresh_session.rs
Normal file
@@ -0,0 +1,83 @@
|
||||
use chrono::{DateTime, Duration, Utc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use crate::user::UserId;
|
||||
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
|
||||
pub struct RefreshSessionId(Uuid);
|
||||
|
||||
impl RefreshSessionId {
|
||||
pub fn generate() -> Self {
|
||||
Self(Uuid::new_v4())
|
||||
}
|
||||
|
||||
pub fn from_uuid(id: Uuid) -> Self {
|
||||
Self(id)
|
||||
}
|
||||
|
||||
pub fn as_uuid(self) -> Uuid {
|
||||
self.0
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct RefreshSession {
|
||||
id: RefreshSessionId,
|
||||
user_id: UserId,
|
||||
token: String,
|
||||
expires_at: DateTime<Utc>,
|
||||
created_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
impl RefreshSession {
|
||||
pub fn new(user_id: UserId, ttl_seconds: i64) -> Self {
|
||||
let now = Utc::now();
|
||||
Self {
|
||||
id: RefreshSessionId::generate(),
|
||||
user_id,
|
||||
token: Uuid::new_v4().to_string(),
|
||||
expires_at: now + Duration::seconds(ttl_seconds),
|
||||
created_at: now,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn from_persistence(
|
||||
id: RefreshSessionId,
|
||||
user_id: UserId,
|
||||
token: String,
|
||||
expires_at: DateTime<Utc>,
|
||||
created_at: DateTime<Utc>,
|
||||
) -> Self {
|
||||
Self {
|
||||
id,
|
||||
user_id,
|
||||
token,
|
||||
expires_at,
|
||||
created_at,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn id(&self) -> RefreshSessionId {
|
||||
self.id
|
||||
}
|
||||
|
||||
pub fn user_id(&self) -> UserId {
|
||||
self.user_id
|
||||
}
|
||||
|
||||
pub fn token(&self) -> &str {
|
||||
&self.token
|
||||
}
|
||||
|
||||
pub fn expires_at(&self) -> DateTime<Utc> {
|
||||
self.expires_at
|
||||
}
|
||||
|
||||
pub fn created_at(&self) -> DateTime<Utc> {
|
||||
self.created_at
|
||||
}
|
||||
|
||||
pub fn is_expired(&self) -> bool {
|
||||
Utc::now() > self.expires_at
|
||||
}
|
||||
}
|
||||
@@ -8,6 +8,8 @@ pub enum DomainError {
|
||||
Conflict(String),
|
||||
#[error("forbidden: {0}")]
|
||||
Forbidden(String),
|
||||
#[error("unauthorized: {0}")]
|
||||
Unauthorized(String),
|
||||
#[error("validation: {0}")]
|
||||
Validation(String),
|
||||
#[error("repository: {0}")]
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
pub mod auth;
|
||||
pub mod errors;
|
||||
pub mod events;
|
||||
pub mod note;
|
||||
|
||||
Reference in New Issue
Block a user