feat(auth): implement JWT authentication and user registration
- Added JWT authentication with token generation and validation. - Introduced user registration functionality with email and password. - Integrated Argon2 for password hashing. - Created SQLite user repository for user data persistence. - Updated application context to include user repository and configuration settings. - Added environment variable support for JWT secret and registration allowance. - Enhanced error handling for unauthorized access and validation errors. - Updated presentation layer to handle login and registration requests.
This commit is contained in:
39
crates/application/src/use_cases/login.rs
Normal file
39
crates/application/src/use_cases/login.rs
Normal file
@@ -0,0 +1,39 @@
|
||||
use chrono::{DateTime, Utc};
|
||||
use uuid::Uuid;
|
||||
|
||||
use domain::{errors::DomainError, value_objects::Email};
|
||||
|
||||
use crate::{commands::LoginCommand, context::AppContext};
|
||||
|
||||
pub struct LoginResult {
|
||||
pub token: String,
|
||||
pub user_id: Uuid,
|
||||
pub email: String,
|
||||
pub expires_at: DateTime<Utc>,
|
||||
}
|
||||
|
||||
pub async fn execute(ctx: &AppContext, cmd: LoginCommand) -> Result<LoginResult, DomainError> {
|
||||
let email = Email::new(cmd.email)?;
|
||||
let user = ctx
|
||||
.user_repository
|
||||
.find_by_email(&email)
|
||||
.await?
|
||||
.ok_or_else(|| DomainError::Unauthorized("Invalid credentials".into()))?;
|
||||
|
||||
let valid = ctx
|
||||
.password_hasher
|
||||
.verify(&cmd.password, user.password_hash())
|
||||
.await?;
|
||||
if !valid {
|
||||
return Err(DomainError::Unauthorized("Invalid credentials".into()));
|
||||
}
|
||||
|
||||
let generated = ctx.auth_service.generate_token(user.id()).await?;
|
||||
|
||||
Ok(LoginResult {
|
||||
token: generated.token,
|
||||
user_id: user.id().value(),
|
||||
email: user.email().value().to_string(),
|
||||
expires_at: generated.expires_at,
|
||||
})
|
||||
}
|
||||
@@ -1,4 +1,6 @@
|
||||
pub mod get_diary;
|
||||
pub mod get_review_history;
|
||||
pub mod log_review;
|
||||
pub mod login;
|
||||
pub mod register;
|
||||
pub mod sync_poster;
|
||||
|
||||
18
crates/application/src/use_cases/register.rs
Normal file
18
crates/application/src/use_cases/register.rs
Normal file
@@ -0,0 +1,18 @@
|
||||
use domain::{errors::DomainError, models::User, value_objects::Email};
|
||||
|
||||
use crate::{commands::RegisterCommand, context::AppContext};
|
||||
|
||||
pub async fn execute(ctx: &AppContext, cmd: RegisterCommand) -> Result<(), DomainError> {
|
||||
if !ctx.config.allow_registration {
|
||||
return Err(DomainError::Unauthorized("Registration is disabled".into()));
|
||||
}
|
||||
|
||||
let email = Email::new(cmd.email)?;
|
||||
|
||||
if ctx.user_repository.find_by_email(&email).await?.is_some() {
|
||||
return Err(DomainError::ValidationError("Email already registered".into()));
|
||||
}
|
||||
|
||||
let hash = ctx.password_hasher.hash(&cmd.password).await?;
|
||||
ctx.user_repository.save(&User::new(email, hash)).await
|
||||
}
|
||||
Reference in New Issue
Block a user