feat(auth): implement user registration and login with JWT authentication

- Added `bcrypt`, `jsonwebtoken`, and `once_cell` dependencies to manage password hashing and JWT handling.
- Created `Claims` struct for JWT claims and implemented token generation in the login route.
- Implemented user registration and authentication logic in the `auth` module.
- Updated error handling to include validation errors.
- Created new routes for user registration and login, and integrated them into the main router.
- Added tests for the authentication flow, including registration and login scenarios.
- Updated user model to include a password hash field.
- Refactored user creation logic to include password validation.
- Adjusted feed and user routes to utilize JWT for authentication.
This commit is contained in:
2025-09-06 00:06:30 +02:00
parent d70015c887
commit 3d73c7f198
33 changed files with 575 additions and 136 deletions

View File

@@ -0,0 +1,23 @@
use api::{
models::{ApiErrorResponse, ParamsErrorResponse},
routers::auth::*,
};
use models::{
params::auth::{LoginParams, RegisterParams},
schemas::user::UserSchema,
};
use utoipa::OpenApi;
#[derive(OpenApi)]
#[openapi(
paths(register, login),
components(schemas(
RegisterParams,
LoginParams,
UserSchema,
TokenResponse,
ApiErrorResponse,
ParamsErrorResponse,
))
)]
pub(super) struct AuthApi;

View File

@@ -1,8 +1,12 @@
use axum::Router;
use utoipa::OpenApi;
use utoipa::{
openapi::security::{ApiKey, ApiKeyValue, Http, SecurityScheme},
Modify, OpenApi,
};
use utoipa_scalar::{Scalar, Servable as ScalarServable};
use utoipa_swagger_ui::SwaggerUi;
mod auth;
mod feed;
mod root;
mod thought;
@@ -12,19 +16,37 @@ mod user;
#[openapi(
nest(
(path = "/", api = root::RootApi),
(path = "/auth", api = auth::AuthApi),
(path = "/users", api = user::UserApi),
(path = "/thoughts", api = thought::ThoughtApi),
(path = "/feed", api = feed::FeedApi),
),
tags(
(name = "root", description = "Root API"),
(name = "auth", description = "Authentication API"),
(name = "user", description = "User & Social API"),
(name = "thought", description = "Thoughts API"),
(name = "feed", description = "Feed API"),
),
modifiers(&SecurityAddon),
)]
struct _ApiDoc;
struct SecurityAddon;
impl Modify for SecurityAddon {
fn modify(&self, openapi: &mut utoipa::openapi::OpenApi) {
let components = openapi.components.get_or_insert_with(Default::default);
components.add_security_scheme(
"bearer_auth",
SecurityScheme::Http(Http::new(utoipa::openapi::security::HttpAuthScheme::Bearer)),
);
components.add_security_scheme(
"api_key",
SecurityScheme::ApiKey(ApiKey::Header(ApiKeyValue::new("Authorization"))),
);
}
}
pub trait ApiDoc {
fn attach_doc(self) -> Self;
}

View File

@@ -13,7 +13,6 @@ use models::schemas::{
paths(
users_get,
users_id_get,
users_post,
user_thoughts_get,
user_follow_post,
user_follow_delete