Display an error when attempting to log in to an account that doesn't exist
This commit is contained in:
parent
680114f467
commit
e24cf5c0b8
5 changed files with 67 additions and 17 deletions
|
@ -53,30 +53,32 @@ pub async fn insert_new_user(
|
|||
.bind(name)
|
||||
.fetch_one(pool).await
|
||||
.map_err(|err| {
|
||||
error!(%err, record = ?new_user, "Cannot insert new user record");
|
||||
error!(?err, record = ?new_user, "Cannot insert new user record");
|
||||
|
||||
AppError::from(err)
|
||||
})
|
||||
}
|
||||
|
||||
#[derive(Debug, FromRow)]
|
||||
pub struct UserIdAndHashedPassword {
|
||||
pub struct UserAndHashedPassword {
|
||||
pub id: i32,
|
||||
pub username: String,
|
||||
pub name: String,
|
||||
pub password: String,
|
||||
}
|
||||
|
||||
pub async fn get_username_and_password_by_username(
|
||||
pool: &DbPool,
|
||||
username: String,
|
||||
) -> Result<UserIdAndHashedPassword, AppError> {
|
||||
sqlx::query_as::<_, UserIdAndHashedPassword>(
|
||||
"SELECT id, password FROM public.user WHERE username = $1;",
|
||||
) -> Result<UserAndHashedPassword, AppError> {
|
||||
sqlx::query_as::<_, UserAndHashedPassword>(
|
||||
"SELECT id, username, name, password FROM public.user WHERE username = $1;",
|
||||
)
|
||||
.bind(username)
|
||||
.fetch_one(pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!(%err, "Unable to find user");
|
||||
error!(?err, "Unable to find user");
|
||||
AppError::from(err)
|
||||
})
|
||||
}
|
||||
|
@ -87,7 +89,7 @@ pub async fn verify_user(pool: &DbPool, user_id: i32) -> Result<(), AppError> {
|
|||
.execute(pool)
|
||||
.await
|
||||
.map_err(|err| {
|
||||
error!(%err, user_id, "Error verifying user");
|
||||
error!(?err, user_id, "Error verifying user");
|
||||
AppError::from(err)
|
||||
})
|
||||
.map(|_| ())
|
||||
|
|
|
@ -81,6 +81,7 @@ impl From<MigrateError> for AppError {
|
|||
impl From<SqlxError> for AppError {
|
||||
fn from(other: SqlxError) -> Self {
|
||||
match &other {
|
||||
SqlxError::RowNotFound => ErrorKind::NoDbRecordFound,
|
||||
SqlxError::Database(db_err) => {
|
||||
if let Some(err_code) = db_err.code() {
|
||||
map_db_error_code_to_error_kind(err_code, db_err)
|
||||
|
@ -137,6 +138,7 @@ impl Display for AppError {
|
|||
f,
|
||||
"Cannot retrieve session: missing required field: {field}"
|
||||
),
|
||||
ErrorKind::NoDbRecordFound => write!(f, "No database record found"),
|
||||
ErrorKind::NoSessionFound => write!(f, "No session found"),
|
||||
ErrorKind::Sqlx(err) => write!(f, "{err}"),
|
||||
ErrorKind::TokenKey => write!(
|
||||
|
@ -161,6 +163,7 @@ enum ErrorKind {
|
|||
InvalidToken,
|
||||
MissingEnvironmentVariables(Vec<&'static str>),
|
||||
MissingSessionField(&'static str),
|
||||
NoDbRecordFound,
|
||||
NoSessionFound,
|
||||
Sqlx(SqlxError),
|
||||
TokenKey,
|
||||
|
@ -181,6 +184,10 @@ impl IntoResponse for AppError {
|
|||
StatusCode::UNAUTHORIZED,
|
||||
ApiResponse::new_with_error(self).into_json_response(),
|
||||
),
|
||||
&ErrorKind::NoDbRecordFound => (
|
||||
StatusCode::NOT_FOUND,
|
||||
ApiResponse::new_with_error(self).into_json_response(),
|
||||
),
|
||||
_ => (
|
||||
StatusCode::INTERNAL_SERVER_ERROR,
|
||||
ApiResponse::new_with_error(self).into_json_response(),
|
||||
|
|
|
@ -4,13 +4,21 @@ use axum::{
|
|||
response::{IntoResponse, Response},
|
||||
Json,
|
||||
};
|
||||
use http::StatusCode;
|
||||
use pasetors::{keys::SymmetricKey, version4::V4};
|
||||
use tracing::debug;
|
||||
|
||||
use crate::{
|
||||
db::{get_username_and_password_by_username, DbPool, UserIdAndHashedPassword},
|
||||
models::AppError,
|
||||
requests::AppState,
|
||||
services::verify_password,
|
||||
db::{get_username_and_password_by_username, DbPool, UserAndHashedPassword},
|
||||
models::{ApiResponse, AppError},
|
||||
requests::{
|
||||
auth::login::models::{AuthLoginResponse, AuthLoginTokenData},
|
||||
AppState,
|
||||
},
|
||||
services::{
|
||||
auth_token::{generate_access_token, generate_auth_token},
|
||||
verify_password,
|
||||
},
|
||||
};
|
||||
|
||||
use super::models::AuthLoginRequest;
|
||||
|
@ -21,19 +29,50 @@ pub async fn auth_login_post_handler(
|
|||
Json(body): Json<AuthLoginRequest>,
|
||||
) -> Result<Response, AppError> {
|
||||
let pool = state.db_pool();
|
||||
auth_login_request(pool, body).await
|
||||
let token_key = state.env().token_key();
|
||||
auth_login_request(pool, token_key, body).await
|
||||
}
|
||||
|
||||
async fn auth_login_request(pool: &DbPool, body: AuthLoginRequest) -> Result<Response, AppError> {
|
||||
async fn auth_login_request(
|
||||
pool: &DbPool,
|
||||
token_key: &SymmetricKey<V4>,
|
||||
body: AuthLoginRequest,
|
||||
) -> Result<Response, AppError> {
|
||||
debug!(?body);
|
||||
|
||||
let AuthLoginRequest { username, password } = body;
|
||||
let UserIdAndHashedPassword {
|
||||
id: _id,
|
||||
let UserAndHashedPassword {
|
||||
id: user_id,
|
||||
username,
|
||||
name,
|
||||
password: hashed_password,
|
||||
} = get_username_and_password_by_username(pool, username).await?;
|
||||
|
||||
verify_password(password, hashed_password)?;
|
||||
|
||||
Ok(().into_response())
|
||||
let (access_token, _access_token_id, access_token_expiration) =
|
||||
generate_access_token(token_key, user_id);
|
||||
|
||||
let (auth_token, _auth_token_id, auth_token_expiration) =
|
||||
generate_auth_token(token_key, user_id);
|
||||
|
||||
let response = AuthLoginResponse {
|
||||
user_id,
|
||||
username,
|
||||
name,
|
||||
access: AuthLoginTokenData {
|
||||
token: access_token,
|
||||
expiration: access_token_expiration,
|
||||
},
|
||||
auth: AuthLoginTokenData {
|
||||
token: auth_token,
|
||||
expiration: auth_token_expiration,
|
||||
},
|
||||
};
|
||||
|
||||
Ok((
|
||||
StatusCode::OK,
|
||||
ApiResponse::new(response).into_json_response(),
|
||||
)
|
||||
.into_response())
|
||||
}
|
||||
|
|
|
@ -2,4 +2,4 @@ mod request;
|
|||
mod response;
|
||||
|
||||
pub use request::*;
|
||||
// pub use response::*;
|
||||
pub use response::*;
|
||||
|
|
|
@ -6,6 +6,8 @@ use serde::Serialize;
|
|||
#[serde(rename_all = "camelCase")]
|
||||
pub struct AuthLoginResponse {
|
||||
pub user_id: i32,
|
||||
pub username: String,
|
||||
pub name: String,
|
||||
pub access: AuthLoginTokenData,
|
||||
pub auth: AuthLoginTokenData,
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue