|
| 1 | +use std::sync::Arc; |
| 2 | + |
| 3 | +use async_trait::async_trait; |
| 4 | +use derive_new::new; |
| 5 | +use kernel::{ |
| 6 | + model::{ |
| 7 | + auth::{AccessToken, event::CreateToken}, |
| 8 | + id::UserId, |
| 9 | + }, |
| 10 | + repository::auth::AuthRepository, |
| 11 | +}; |
| 12 | +use shared::error::{AppError, AppResult}; |
| 13 | + |
| 14 | +use crate::{ |
| 15 | + database::{ |
| 16 | + ConnectionPool, |
| 17 | + model::auth::{AuthorizationKey, AuthorizedUserId, UserItem, from}, |
| 18 | + }, |
| 19 | + redis::RedisClient, |
| 20 | +}; |
| 21 | + |
| 22 | +#[derive(new)] |
| 23 | +pub struct AuthRepositoryImpl { |
| 24 | + db: ConnectionPool, |
| 25 | + kv: Arc<RedisClient>, |
| 26 | + ttl: u64, |
| 27 | +} |
| 28 | + |
| 29 | +#[async_trait] |
| 30 | +impl AuthRepository for AuthRepositoryImpl { |
| 31 | + async fn fetch_user_id_from_token( |
| 32 | + &self, |
| 33 | + access_token: &AccessToken, |
| 34 | + ) -> AppResult<Option<UserId>> { |
| 35 | + let key: AuthorizationKey = access_token.into(); |
| 36 | + self.kv |
| 37 | + .get(&key) |
| 38 | + .await |
| 39 | + .map(|x| x.map(AuthorizedUserId::into_inner)) |
| 40 | + } |
| 41 | + |
| 42 | + async fn verify_user(&self, email: &str, password: &str) -> AppResult<UserId> { |
| 43 | + let user_item = sqlx::query_as!( |
| 44 | + UserItem, |
| 45 | + r#" |
| 46 | + SELECT user_id, password_hash FROM users |
| 47 | + WHERE email = $1; |
| 48 | + "#, |
| 49 | + email |
| 50 | + ) |
| 51 | + .fetch_one(self.db.inner_ref()) |
| 52 | + .await |
| 53 | + .map_err(AppError::SpecificOperationError)?; |
| 54 | + |
| 55 | + let valid = bcrypt::verify(password, &user_item.password_hash)?; |
| 56 | + |
| 57 | + if !valid { |
| 58 | + return Err(AppError::UnauthenticatedError); |
| 59 | + } |
| 60 | + |
| 61 | + Ok(user_item.user_id) |
| 62 | + } |
| 63 | + |
| 64 | + async fn create_token(&self, event: CreateToken) -> AppResult<AccessToken> { |
| 65 | + let (key, value) = from(event); |
| 66 | + self.kv.set_ex(&key, &value, self.ttl).await?; |
| 67 | + Ok(key.into()) |
| 68 | + } |
| 69 | + |
| 70 | + async fn delete_token(&self, access_token: AccessToken) -> AppResult<()> { |
| 71 | + let key: AuthorizationKey = access_token.into(); |
| 72 | + self.kv.delete(&key).await |
| 73 | + } |
| 74 | +} |
0 commit comments