feat: add user registry

add hash password
This commit is contained in:
xfy
2024-11-08 17:04:40 +08:00
parent c07562749f
commit dcd66933aa
6 changed files with 93 additions and 8 deletions

View File

@ -958,6 +958,7 @@ dependencies = [
"dotenvy",
"jsonwebtoken",
"rand",
"regex",
"serde",
"serde_json",
"serde_repr",

View File

@ -18,6 +18,7 @@ thiserror = "2.0.0"
dotenvy = "0.15.7"
argon2 = "0.5.3"
rand = "0.8.5"
regex = "1.11.1"
serde = { version = "1.0.214", features = ["derive", "serde_derive"] }
serde_json = { version = "1.0.132" }
serde_repr = "0.1.19"

View File

@ -15,6 +15,8 @@ pub enum AppError {
#[error("{0}")]
Any(#[from] anyhow::Error),
#[error(transparent)]
ValidationError(#[from] validator::ValidationErrors),
// axum
#[error(transparent)]
AxumFormRejection(#[from] FormRejection),
@ -80,7 +82,10 @@ impl IntoResponse for AppError {
ParameterIncorrect,
self.to_string(),
),
// route
AppError::ValidationError(_) => {
let message = format!("Input validation error: [{self}]").replace('\n', ", ");
(StatusCode::BAD_REQUEST, ParameterIncorrect, message)
} // route
// AppError::AuthorizeFailed(err) => {
// (StatusCode::UNAUTHORIZED, AuthorizeFailed, err.to_string())
// }

View File

@ -1,12 +1,22 @@
use crate::utils::password::hash;
use axum::{routing::post, Json, Router};
use serde::{Deserialize, Serialize};
use validator::Validate;
use crate::utils::validator::EMAIL_REGEX;
use super::{RouteResponse, RouteResult};
#[derive(Serialize, Deserialize)]
#[derive(Serialize, Deserialize, Validate)]
pub struct UserResigtry {
#[validate(length(min = 1, message = "Can not be empty"))]
pub username: String,
#[validate(regex(
path = *EMAIL_REGEX,
message = "邮箱格式不正确"
))]
pub email: String,
#[validate(length(min = 6, max = 100, message = "Can not be empty"))]
pub password: String,
}
@ -14,13 +24,23 @@ pub struct UserResigtry {
pub struct UserResigtryRes {
pub username: String,
pub email: String,
pub password: String,
pub token: String,
}
pub async fn registry(Json(user_param): Json<UserResigtry>) -> RouteResult<UserResigtryRes> {
let UserResigtry {
email,
password,
username,
} = user_param;
let hashed = hash(password).await?;
let data = UserResigtryRes {
username: "xfy".to_string(),
email: "i@rua.plus".to_string(),
username,
email,
password: hashed,
token: "abc".to_string(),
};
let res = RouteResponse {

View File

@ -3,6 +3,7 @@ use tracing_subscriber::{fmt, prelude::*, registry, EnvFilter};
pub mod jwt;
pub mod password;
pub mod validator;
/// Initializes the logger for tracing.
pub fn init_logger() {

View File

@ -0,0 +1,57 @@
use std::sync::LazyLock;
use axum::{
async_trait,
extract::{
rejection::{FormRejection, JsonRejection},
FromRequest, Request,
},
Form, Json,
};
use regex::Regex;
use serde::de::DeserializeOwned;
use validator::Validate;
use crate::error::AppError;
#[derive(Debug, Clone, Copy, Default)]
pub struct ValidatedForm<T>(pub T);
#[async_trait]
impl<T, S> FromRequest<S> for ValidatedForm<T>
where
T: DeserializeOwned + Validate,
S: Send + Sync,
Form<T>: FromRequest<S, Rejection = FormRejection>,
{
type Rejection = AppError;
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
let Form(value) = Form::<T>::from_request(req, state).await?;
value.validate()?;
Ok(ValidatedForm(value))
}
}
#[derive(Debug, Clone, Copy, Default)]
pub struct ValidatedJson<T>(pub T);
#[async_trait]
impl<T, S> FromRequest<S> for ValidatedJson<T>
where
T: DeserializeOwned + Validate,
S: Send + Sync,
Json<T>: FromRequest<S, Rejection = JsonRejection>,
{
type Rejection = AppError;
async fn from_request(req: Request, state: &S) -> Result<Self, Self::Rejection> {
let Json(value) = Json::<T>::from_request(req, state).await?;
value.validate()?;
Ok(ValidatedJson(value))
}
}
pub static EMAIL_REGEX: LazyLock<Regex> = LazyLock::new(|| {
Regex::new(r"^[a-zA-Z0-9_.+-]+@[a-zA-Z0-9-]+\.[a-zA-Z0-9-.]+$").expect("Regex is valid")
});