- add: logout grpc function

- add: logout packet handler
- add: connection state and service for storing connection data
- add: session service calls to auth-service
- fix: compile error on database service due to moved redis cache
This commit is contained in:
2024-12-20 14:46:00 -05:00
parent 3c1f8c40d6
commit 18afa71d74
22 changed files with 265 additions and 46 deletions

View File

@@ -1,6 +1,9 @@
use std::sync::Arc;
use crate::auth::auth_service_server::AuthService;
use crate::auth::{LoginRequest, LoginResponse, PasswordResetRequest, PasswordResetResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, ValidateTokenRequest, ValidateTokenResponse};
use crate::database_client::{DatabaseClientTrait};
use crate::auth::{LoginRequest, LoginResponse, PasswordResetRequest, PasswordResetResponse, RegisterRequest, RegisterResponse, ResetPasswordRequest, ResetPasswordResponse, ValidateTokenRequest, ValidateTokenResponse, ValidateSessionRequest, ValidateSessionResponse, Empty, LogoutRequest};
use crate::database_client::{DatabaseClient, DatabaseClientTrait};
use crate::session::session_service_client::SessionServiceClient;
use crate::session::{CreateSessionRequest, GetSessionRequest, DeleteSessionRequest};
use crate::jwt::{generate_token, validate_token};
use crate::users::{hash_password, verify_user};
use chrono::{Duration, Utc};
@@ -8,12 +11,13 @@ use rand::Rng;
use tonic::{Request, Response, Status};
use tracing::{error, info, warn};
pub struct MyAuthService<T: DatabaseClientTrait + Clone> {
pub db_client: T,
pub struct MyAuthService {
pub db_client: Arc<DatabaseClient>,
pub session_client: Arc<SessionServiceClient<tonic::transport::Channel>>,
}
#[tonic::async_trait]
impl<T: DatabaseClientTrait + Send + Sync + Clone + 'static> AuthService for MyAuthService<T> {
impl AuthService for MyAuthService {
async fn login(
&self,
request: Request<LoginRequest>,
@@ -22,17 +26,49 @@ impl<T: DatabaseClientTrait + Send + Sync + Clone + 'static> AuthService for MyA
info!("Login attempt for username: {}", req.username);
if let Some(user_id) = verify_user(self.db_client.clone(), &req.username, &req.password).await {
if let Some(user_id) = verify_user(self.db_client.as_ref().clone(), &req.username, &req.password).await {
let token = generate_token(&user_id, vec!["user".to_string()])
.map_err(|_| Status::internal("Token generation failed"))?;
let session_id = uuid::Uuid::new_v4().to_string();
let response = self
.session_client.as_ref().clone()
.create_session(CreateSessionRequest {
session_id: session_id.clone(),
user_id: user_id.parse().unwrap(),
username: req.username.to_string(),
character_id: 0,
ip_address: req.ip_address.to_string(),
})
.await;
let session = match response {
Ok(session) => session,
Err(_) => return Err(Status::internal("Session creation failed")),
};
let session_id = session.into_inner().session_id;
info!("Login successful for username: {}", req.username);
Ok(Response::new(LoginResponse { token, user_id }))
Ok(Response::new(LoginResponse { token, user_id, session_id }))
} else {
warn!("Invalid login attempt for username: {}", req.username);
Err(Status::unauthenticated("Invalid credentials"))
}
}
async fn logout(
&self,
request: Request<LogoutRequest>,
) -> Result<Response<Empty>, Status> {
let req = request.into_inner();
self.session_client.as_ref().clone()
.delete_session(DeleteSessionRequest {
session_id: req.session_id.clone(),
})
.await?;
Ok(Response::new(Empty {}))
}
async fn validate_token(
&self,
@@ -52,6 +88,30 @@ impl<T: DatabaseClientTrait + Send + Sync + Clone + 'static> AuthService for MyA
}
}
async fn validate_session(
&self,
request: Request<ValidateSessionRequest>,
) -> Result<Response<ValidateSessionResponse>, Status> {
let req = request.into_inner();
let response = self
.session_client.as_ref().clone()
.get_session(GetSessionRequest {
session_id: req.session_id,
})
.await;
match response {
Ok(res) => {
println!("Session valid: {:?}", res.into_inner());
Ok(Response::new(ValidateSessionResponse { valid: true }))
}
Err(_) => {
println!("Session invalid or not found");
Ok(Response::new(ValidateSessionResponse { valid: false }))
}
}
}
async fn register(
&self,
request: Request<RegisterRequest>,
@@ -62,7 +122,7 @@ impl<T: DatabaseClientTrait + Send + Sync + Clone + 'static> AuthService for MyA
let hashed_password = hash_password(&req.password);
// Create user in the database
let result = self.db_client.clone().create_user(&req.username, &req.email, &hashed_password)
let result = self.db_client.as_ref().clone().create_user(&req.username, &req.email, &hashed_password)
.await;
match result {
@@ -83,7 +143,7 @@ impl<T: DatabaseClientTrait + Send + Sync + Clone + 'static> AuthService for MyA
) -> Result<Response<PasswordResetResponse>, Status> {
let email = request.into_inner().email;
let user = self.db_client.clone().get_user_by_email(&email).await;
let user = self.db_client.as_ref().clone().get_user_by_email(&email).await;
// Check if the email exists
if user.ok().is_some() {
@@ -98,14 +158,14 @@ impl<T: DatabaseClientTrait + Send + Sync + Clone + 'static> AuthService for MyA
let expires_at = Utc::now() + Duration::hours(1);
// Store the reset token in the database
self.db_client.clone()
self.db_client.as_ref().clone()
.store_password_reset(&email, &reset_token, expires_at)
.await
.map_err(|e| Status::internal(format!("Database error: {}", e)))?;
// Send the reset email
// send_email(&email, "Password Reset Request", &format!(
// "Click the link to reset your password: https://example.com/reset?token={}",
// "Click the link to reset your password: https://azgstudio.com/reset?token={}",
// reset_token
// ))
// .map_err(|e| Status::internal(format!("Email error: {}", e)))?;