From 61de18077e985bd5dc2cf64b98e158cda5545010 Mon Sep 17 00:00:00 2001 From: soul-walker <31162815+soul-walker@users.noreply.github.com> Date: Thu, 7 Nov 2024 23:09:36 +0800 Subject: [PATCH] =?UTF-8?q?1=20=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7?= =?UTF-8?q?=E5=AF=86=E7=A0=81=E5=8A=A0=E5=AF=86=E3=80=81=E9=AA=8C=E8=AF=81?= =?UTF-8?q?=202=20=E6=B7=BB=E5=8A=A0=E7=94=A8=E6=88=B7=E5=90=8D=E3=80=81?= =?UTF-8?q?=E9=82=AE=E7=AE=B1=E7=AD=89=E6=98=AF=E5=90=A6=E5=B7=B2=E7=BB=8F?= =?UTF-8?q?=E5=AD=98=E5=9C=A8=E6=8E=A5=E5=8F=A3?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- Cargo.lock | 35 +++++ crates/rtsa_db/Cargo.toml | 3 + crates/rtsa_db/src/db_access/org_user.rs | 75 ---------- crates/rtsa_db/src/db_access/user.rs | 181 +++++++++++++---------- crates/rtsa_db/src/error.rs | 4 + crates/rtsa_db/src/password_util.rs | 69 ++++++++- manager/src/apis/user.rs | 29 ++++ manager/src/sys_init/mod.rs | 3 +- manager/src/user_auth/mod.rs | 72 +++++---- 9 files changed, 287 insertions(+), 184 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index aadcb44..528cafd 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -125,6 +125,18 @@ version = "1.0.91" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c042108f3ed77fd83760a5fd79b53be043192bb3b9dba91d8c574c0ada7850c8" +[[package]] +name = "argon2" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c3610892ee6e0cbce8ae2700349fcf8f98adb0dbfbee85aec3c9179d29cc072" +dependencies = [ + "base64ct", + "blake2", + "cpufeatures", + "password-hash", +] + [[package]] name = "arraydeque" version = "0.5.1" @@ -602,6 +614,15 @@ dependencies = [ "serde", ] +[[package]] +name = "blake2" +version = "0.10.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46502ad458c9a52b69d4d4d32775c788b7a1b85e8bc9d482d92250fc0e3f8efe" +dependencies = [ + "digest", +] + [[package]] name = "block-buffer" version = "0.10.4" @@ -1907,6 +1928,17 @@ dependencies = [ "windows-targets 0.52.6", ] +[[package]] +name = "password-hash" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "346f04948ba92c43e8469c1ee6736c7563d71012b17d40745260fe106aac2166" +dependencies = [ + "base64ct", + "rand_core", + "subtle", +] + [[package]] name = "paste" version = "1.0.15" @@ -2417,7 +2449,10 @@ name = "rtsa_db" version = "0.1.0" dependencies = [ "anyhow", + "argon2", "lazy_static", + "md-5", + "rand_core", "regex", "rtsa_dto", "rtsa_log", diff --git a/crates/rtsa_db/Cargo.toml b/crates/rtsa_db/Cargo.toml index 647b538..a84569d 100644 --- a/crates/rtsa_db/Cargo.toml +++ b/crates/rtsa_db/Cargo.toml @@ -19,6 +19,9 @@ sqlx = { workspace = true, features = [ thiserror = { workspace = true } lazy_static = { workspace = true } regex = { workspace = true } +argon2 = "0.5.3" +rand_core = { version = "0.6.4", features = ["std"] } +md-5 = "0.10.6" rtsa_dto = { path = "../rtsa_dto" } rtsa_log = { path = "../rtsa_log" } diff --git a/crates/rtsa_db/src/db_access/org_user.rs b/crates/rtsa_db/src/db_access/org_user.rs index d61a26d..d35a506 100644 --- a/crates/rtsa_db/src/db_access/org_user.rs +++ b/crates/rtsa_db/src/db_access/org_user.rs @@ -3,7 +3,6 @@ use sqlx::Postgres; use super::RtsaDbAccessor; use super::{OrgAccessor, RegisterUser, UserAccessor}; -use crate::password_util::verify_password; use crate::{ common::{PageData, PageQuery, TableColumn}, model::{OrganizationUserColumn, OrganizationUserModel, UserModel}, @@ -48,14 +47,6 @@ pub trait OrgUserAccessor { info: Value, updater_id: i32, ) -> Result; - /// 查询组织用户登陆 - /// username: 学工号/用户名/邮箱/手机号 - async fn query_org_user_login( - &self, - org_id: i32, - username: &str, - password: &str, - ) -> Result<(OrganizationUserModel, UserModel), DbAccessError>; /// 获取组织用户 async fn query_org_user( &self, @@ -383,35 +374,6 @@ impl OrgUserAccessor for RtsaDbAccessor { Ok(update) } - async fn query_org_user_login( - &self, - org_id: i32, - username: &str, - password: &str, - ) -> Result<(OrganizationUserModel, UserModel), DbAccessError> { - // 查询用户登陆 - let user = self.query_user_login(username, password).await; - match user { - Err(_) => { - // 用户不存在,查询组织用户学工号+用户密码 - // 通过组织id和学工号查询组织用户 - let org_user = self.query_org_user_by_student_id(org_id, username).await?; - let user = self.query_user(org_user.user_id).await?; - // 检查用户密码 - if verify_password(password, &user.password) { - Ok((org_user, user)) - } else { - Err(DbAccessError::InvalidArgument("密码不匹配".to_string())) - } - } - Ok(user) => { - // 用户存在,查询组织用户 - let org_user = self.query_org_user(org_id, user.id).await?; - Ok((org_user, user)) - } - } - } - async fn query_org_user( &self, org_id: i32, @@ -594,43 +556,6 @@ mod tests { Ok(()) } - #[sqlx::test(migrator = "crate::MIGRATOR")] - async fn test_query_org_user_login(pool: PgPool) -> Result<(), DbAccessError> { - let accessor = RtsaDbAccessor::new(pool); - let (creator, org) = init_default_org_and_user(&accessor).await?; - let create = CreateOrgUser::new( - &org.code.clone().unwrap(), - "test_student_id", - "test_name", - "test_password", - creator.id, - ); - accessor.create_org_user(create.clone()).await?; - // Attempt to log in with student ID - let (org_user, user) = accessor - .query_org_user_login(org.id, "test_student_id", "test_password") - .await?; - assert_eq!(org_user.organization_id, org.id); - assert_eq!(user.nickname, create.nickname()); - // Attempt to log in with username - let (org_user, user) = accessor - .query_org_user_login(org.id, &create.build_username(), "test_password") - .await?; - assert_eq!(org_user.organization_id, org.id); - assert_eq!(user.nickname, create.nickname()); - // Attempt to log in with wrong password - let result = accessor - .query_org_user_login(org.id, "test_student_id", "wrong_password") - .await; - assert!(matches!(result, Err(DbAccessError::InvalidArgument(_)))); - // Attempt to log in with wrong username - let result = accessor - .query_org_user_login(org.id, "wrong_student_id", "test_password") - .await; - assert!(matches!(result, Err(DbAccessError::SqlxError(_)))); - Ok(()) - } - #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_query_org_user_by_student_id(pool: PgPool) -> Result<(), DbAccessError> { let accessor = RtsaDbAccessor::new(pool); diff --git a/crates/rtsa_db/src/db_access/user.rs b/crates/rtsa_db/src/db_access/user.rs index bac041f..94a275c 100644 --- a/crates/rtsa_db/src/db_access/user.rs +++ b/crates/rtsa_db/src/db_access/user.rs @@ -4,7 +4,7 @@ use sqlx::Postgres; use crate::{ common::{PageData, PageQuery, TableColumn}, model::{UserColumn, UserModel}, - password_util::verify_password, + password_util::{self, verify_password}, username_util::{is_email, is_mobile}, DbAccessError, }; @@ -48,6 +48,10 @@ pub trait UserAccessor { async fn query_user(&self, id: i32) -> Result; /// 根据username查询用户数据 async fn query_user_by_username(&self, username: &str) -> Result; + /// 根据email查询用户数据 + async fn query_user_by_email(&self, email: &str) -> Result; + /// 根据mobile查询用户数据 + async fn query_user_by_mobile(&self, mobile: &str) -> Result; /// 是否用户名已经存在 async fn is_user_name_exist(&self, name: &str) -> Result; /// 是否用户email已经存在 @@ -296,7 +300,8 @@ impl UserAccessor for RtsaDbAccessor { Ok(PageData::new(total, rows)) } - async fn register_user(&self, user: RegisterUser) -> Result { + async fn register_user(&self, mut user: RegisterUser) -> Result { + user.password = password_util::hash_password(&user.password)?; self.insert_user(user, &self.pool).await } @@ -305,88 +310,34 @@ impl UserAccessor for RtsaDbAccessor { username: &str, password: &str, ) -> Result { - let table = UserColumn::Table.name(); - let username_column = UserColumn::Username.name(); - let email_column = UserColumn::Email.name(); - let mobile_column = UserColumn::Mobile.name(); + let user: UserModel; if is_email(username) { - let query_clause = format!( - "SELECT * FROM {table} WHERE {email_column} = $1 LIMIT 1", - table = table, - email_column = email_column, - ); - let user: Result = sqlx::query_as(&query_clause) - .bind(username) - .fetch_one(&self.pool) - .await; - match user { - Ok(user) => { - if verify_password(password, &user.password) { - Ok(user) - } else { - Err(DbAccessError::InvalidArgument("密码不匹配".to_string())) - } - } - Err(sqlx::Error::RowNotFound) => Err(DbAccessError::InvalidArgument( - "用户不存在(email)".to_string(), - )), - Err(e) => Err(DbAccessError::SqlxError(e)), + let query_result = self.query_user_by_email(username).await; + if query_result.is_ok() { + user = query_result.unwrap(); + } else { + return Err(DbAccessError::UserNotExist("email".to_string())); } } else if is_mobile(username) { - let query_clause = format!( - "SELECT * FROM {table} WHERE {mobile_column} = $1 LIMIT 1", - table = table, - mobile_column = mobile_column, - ); - let user: Result = sqlx::query_as(&query_clause) - .bind(username) - .fetch_one(&self.pool) - .await; - match user { - Ok(user) => { - if verify_password(password, &user.password) { - return Ok(user); - } else { - return Err(DbAccessError::InvalidArgument("密码不匹配".to_string())); - } - } - Err(sqlx::Error::RowNotFound) => { - return Err(DbAccessError::InvalidArgument( - "用户不存在(mobile)".to_string(), - )); - } - Err(e) => { - return Err(DbAccessError::SqlxError(e)); - } + let query_result = self.query_user_by_mobile(username).await; + if query_result.is_ok() { + user = query_result.unwrap(); + } else { + return Err(DbAccessError::UserNotExist("mobile".to_string())); } } else { - let query_clause = format!( - "SELECT * FROM {table} WHERE {username_column} = $1 LIMIT 1", - table = table, - username_column = username_column, - ); - let user: Result = sqlx::query_as(&query_clause) - .bind(username) - .fetch_one(&self.pool) - .await; - match user { - Ok(user) => { - if verify_password(password, &user.password) { - return Ok(user); - } else { - return Err(DbAccessError::InvalidArgument("密码不匹配".to_string())); - } - } - Err(sqlx::Error::RowNotFound) => { - return Err(DbAccessError::InvalidArgument( - "用户不存在(username)".to_string(), - )); - } - Err(e) => { - return Err(DbAccessError::SqlxError(e)); - } + let query_result = self.query_user_by_username(username).await; + if query_result.is_ok() { + user = query_result.unwrap(); + } else { + return Err(DbAccessError::UserNotExist("username".to_string())); } } + if verify_password(password, &user.password).is_ok() { + Ok(user) + } else { + Err(DbAccessError::PasswordNotMatch) + } } async fn query_user(&self, id: i32) -> Result { @@ -415,6 +366,36 @@ impl UserAccessor for RtsaDbAccessor { Ok(user) } + async fn query_user_by_email(&self, email: &str) -> Result { + let table = UserColumn::Table.name(); + let email_column = UserColumn::Email.name(); + let query_clause = format!( + "SELECT * FROM {table} WHERE {email_column} = $1 LIMIT 1", + table = table, + email_column = email_column, + ); + let user = sqlx::query_as(&query_clause) + .bind(email) + .fetch_one(&self.pool) + .await?; + Ok(user) + } + + async fn query_user_by_mobile(&self, mobile: &str) -> Result { + let table = UserColumn::Table.name(); + let mobile_column = UserColumn::Mobile.name(); + let query_clause = format!( + "SELECT * FROM {table} WHERE {mobile_column} = $1 LIMIT 1", + table = table, + mobile_column = mobile_column, + ); + let user = sqlx::query_as(&query_clause) + .bind(mobile) + .fetch_one(&self.pool) + .await?; + Ok(user) + } + async fn update_user_info(&self, id: i32, info: Value) -> Result { let table = UserColumn::Table.name(); let id_column = UserColumn::Id.name(); @@ -451,15 +432,16 @@ impl UserAccessor for RtsaDbAccessor { "new_password is too long".to_string(), )); } + let hashed = password_util::hash_password(new_password)?; let table = UserColumn::Table.name(); let id_column = UserColumn::Id.name(); let password_column = UserColumn::Password.name(); let updated_at_column = UserColumn::UpdatedAt.name(); let update_clause = format!( - "UPDATE {table} SET {password_column} = '{new_password}', {updated_at_column} = 'now()' WHERE {id_column} = {id} RETURNING *", + "UPDATE {table} SET {password_column} = '{hashed}', {updated_at_column} = 'now()' WHERE {id_column} = {id} RETURNING *", table = table, password_column = password_column, - new_password = new_password, + hashed = hashed, id_column = id_column, id = id ); @@ -609,12 +591,14 @@ impl UserAccessor for RtsaDbAccessor { #[cfg(test)] mod tests { use rtsa_dto::common::Role; + use rtsa_log::tracing::info; use sqlx::PgPool; use super::*; #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_register_user(pool: PgPool) -> Result<(), DbAccessError> { + rtsa_log::Logging::default().init(); let accessor = RtsaDbAccessor { pool }; let new_user = RegisterUser::new("test_user", "test_password") @@ -627,6 +611,7 @@ mod tests { let queried_user = accessor .query_user_login("test_user@example.com", "test_password") .await?; + info!("queried_user: {:?}", queried_user); assert_eq!(queried_user.username, "test_user"); assert_eq!( queried_user.email, @@ -781,6 +766,42 @@ mod tests { Ok(()) } + #[sqlx::test(migrator = "crate::MIGRATOR")] + async fn test_query_user_by_email(pool: PgPool) -> Result<(), DbAccessError> { + let accessor = RtsaDbAccessor { pool }; + + // 准备测试数据 + let new_user = RegisterUser::new("test_user", "test_password").with_email("test@test.cn"); + let um = accessor.register_user(new_user).await?; + + // Assume a user with email exists + let user = accessor.query_user_by_email("test@test.cn").await?; + assert_eq!(user.id, um.id); + + // Assume a user with email does not exist + let result = accessor.query_user_by_email("dev@test.cn").await; + assert!(result.is_err()); + Ok(()) + } + + #[sqlx::test(migrator = "crate::MIGRATOR")] + async fn test_query_user_by_mobile(pool: PgPool) -> Result<(), DbAccessError> { + let accessor = RtsaDbAccessor { pool }; + + // 准备测试数据 + let new_user = RegisterUser::new("test_user", "test_password").with_mobile("13345678901"); + let um = accessor.register_user(new_user).await?; + + // Assume a user with mobile exists + let user = accessor.query_user_by_mobile("13345678901").await?; + assert_eq!(user.id, um.id); + + // Assume a user with mobile does not exist + let result = accessor.query_user_by_mobile("13345678902").await; + assert!(result.is_err()); + Ok(()) + } + #[sqlx::test(migrator = "crate::MIGRATOR")] async fn test_query_user_login(pool: PgPool) -> Result<(), DbAccessError> { let accessor = RtsaDbAccessor { pool }; @@ -809,7 +830,7 @@ mod tests { // Test with incorrect credentials let result = accessor - .query_user_login("test_user@example.com", "wrongpassword") + .query_user_login("test_user@example.com", "wrong_password") .await; assert!(result.is_err()); Ok(()) diff --git a/crates/rtsa_db/src/error.rs b/crates/rtsa_db/src/error.rs index 6673c76..e6f9a5c 100644 --- a/crates/rtsa_db/src/error.rs +++ b/crates/rtsa_db/src/error.rs @@ -14,4 +14,8 @@ pub enum DbAccessError { DataError(String), #[error("非法参数:{0}")] InvalidArgument(String), + #[error("用户不存在:{0}")] + UserNotExist(String), + #[error("密码不正确")] + PasswordNotMatch, } diff --git a/crates/rtsa_db/src/password_util.rs b/crates/rtsa_db/src/password_util.rs index c53c40c..83ce24d 100644 --- a/crates/rtsa_db/src/password_util.rs +++ b/crates/rtsa_db/src/password_util.rs @@ -1,4 +1,69 @@ +use argon2::{ + password_hash::{PasswordHash, PasswordHasher, PasswordVerifier, SaltString}, + Argon2, +}; +use rand_core::OsRng; + +use md5::{Digest, Md5}; + +use crate::DbAccessError; + /// 验证密码是否正确 -pub fn verify_password(password: &str, hash: &str) -> bool { - password == hash +pub fn verify_password(password: &str, hash: &str) -> Result<(), DbAccessError> { + // Verify password against PHC string. + // NOTE: hash params from `parsed_hash` are used instead of what is configured in the + // `Argon2` instance. + let parsed_hash = PasswordHash::new(hash); + match parsed_hash { + Ok(parsed_hash) => Argon2::default() + .verify_password(password.as_bytes(), &parsed_hash) + .map_err(|e| DbAccessError::InvalidArgument(format!("password verify error: {}", e))), + Err(e) => Err(DbAccessError::InvalidArgument(format!( + "password hash error: {}", + e + ))), + } +} + +pub fn hash_password(password: &str) -> Result { + let salt = SaltString::generate(&mut OsRng); + + // Argon2 with default params (Argon2id v19) + let argon2 = Argon2::default(); + + // Hash password to PHC string ($argon2id$v=19$...) + let password_hash = argon2.hash_password(password.as_bytes(), &salt); + match password_hash { + Ok(ph) => Ok(ph.to_string()), + Err(e) => Err(DbAccessError::InvalidArgument(format!( + "password hash error: {}", + e + ))), + } +} + +pub fn md5(input: &str) -> String { + let mut hasher = Md5::new(); + hasher.update(input); + let result = hasher.finalize(); + format!("{:x}", result) +} + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn test_hash_password() { + let password = "password"; + let hash = hash_password(password).unwrap(); + assert!(verify_password(password, &hash).is_ok()); + } + + #[test] + fn test_md5() { + let input = "hello"; + let output = md5(input); + assert_eq!(output, "5d41402abc4b2a76b9719d911017c592"); + } } diff --git a/manager/src/apis/user.rs b/manager/src/apis/user.rs index a9059a5..8b615e1 100644 --- a/manager/src/apis/user.rs +++ b/manager/src/apis/user.rs @@ -41,6 +41,35 @@ impl UserQuery { Ok(user.into()) } + /// 用户名是否存在 + async fn username_exists( + &self, + ctx: &Context<'_>, + username: String, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let exist = db_accessor.is_user_name_exist(&username).await?; + Ok(exist) + } + + /// 邮箱是否存在 + async fn email_exists(&self, ctx: &Context<'_>, email: String) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let exist = db_accessor.is_user_email_exist(&email).await?; + Ok(exist) + } + + /// 手机号是否存在 + async fn mobile_exists( + &self, + ctx: &Context<'_>, + mobile: String, + ) -> async_graphql::Result { + let db_accessor = ctx.data::()?; + let exist = db_accessor.is_user_mobile_exist(&mobile).await?; + Ok(exist) + } + /// 分页查询用户(系统管理) #[graphql(guard = "RoleGuard::new(Role::Admin)")] async fn user_paging( diff --git a/manager/src/sys_init/mod.rs b/manager/src/sys_init/mod.rs index 7968eb4..204c7e0 100644 --- a/manager/src/sys_init/mod.rs +++ b/manager/src/sys_init/mod.rs @@ -6,7 +6,7 @@ use rtsa_log::tracing::{debug, error, info}; use serde_json::json; pub const ADMIN_USER_NAME: &str = "_jl_admin_"; -pub const ADMIN_USER_PASSWORD: &str = "joylink0503"; +pub const ADMIN_USER_PASSWORD: &str = "4a6d74126bfd06d69406fcccb7e7d5d9"; pub const DEFAULT_ORG_CODE: &str = "default"; const DEFAULT_ORG_NAME: &str = "默认机构"; @@ -64,7 +64,6 @@ mod tests { let db_accessor = rtsa_db::get_default_db_accessor(); let user = db_accessor.query_user_by_username(ADMIN_USER_NAME).await?; assert_eq!(user.username, ADMIN_USER_NAME); - assert_eq!(user.password, ADMIN_USER_PASSWORD); assert_eq!(user.nickname, ADMIN_USER_NAME); assert_eq!(user.roles, json!([Role::Admin])); diff --git a/manager/src/user_auth/mod.rs b/manager/src/user_auth/mod.rs index bcab119..54961af 100644 --- a/manager/src/user_auth/mod.rs +++ b/manager/src/user_auth/mod.rs @@ -1,7 +1,7 @@ use async_graphql::Guard; use rtsa_db::prelude::*; use rtsa_dto::common::Role; -use rtsa_log::tracing::warn; +use rtsa_log::tracing::{info, warn}; mod jwt_auth; use crate::{apis::UserLoginDto, error::BusinessError, sys_init::DEFAULT_ORG_CODE}; @@ -53,10 +53,10 @@ impl Guard for RoleGuard { /// 处理用户登录 pub(crate) async fn handle_login( db_accessor: &RtsaDbAccessor, - info: UserLoginDto, + user_login_dto: UserLoginDto, ) -> Result { let org_id; - if let Some(oid) = info.org_id { + if let Some(oid) = user_login_dto.org_id { org_id = oid; } else { let default_org = db_accessor.query_org_by_code(DEFAULT_ORG_CODE).await?; @@ -64,35 +64,57 @@ pub(crate) async fn handle_login( } // 查询用户登陆 let user = db_accessor - .query_user_login(&info.username, &info.password) + .query_user_login(&user_login_dto.username, &user_login_dto.password) .await; match user { Ok(user) => { // 用户存在 Ok(Jwt::build_from(Claims::new(user.id, org_id))?) } - Err(_) => { - // 用户不存在,查询组织用户学工号+用户密码 - // 通过组织id和学工号查询组织用户 - let org_user = db_accessor - .query_org_user_by_student_id(org_id, &info.username) - .await; - if org_user.is_err() { - warn!("用户不存在: username={}, org_id={}", info.username, org_id); - return Err(BusinessError::AuthError( + Err(e) => { + match e { + DbAccessError::UserNotExist(e) => { + info!( + "用户不存在: {}, 尝试查询组织学工号用户: username={}, org_id={}", + e, user_login_dto.username, org_id + ); + // 用户不存在,查询组织用户学工号+用户密码 + // 通过组织id和学工号查询组织用户 + let org_user = db_accessor + .query_org_user_by_student_id(org_id, &user_login_dto.username) + .await; + if org_user.is_err() { + warn!( + "用户不存在: username={}, org_id={}", + user_login_dto.username, org_id + ); + return Err(BusinessError::AuthError( + "用户不存在或密码不正确".to_string(), + )); + } + let org_user = org_user.unwrap(); + let user = db_accessor.query_user(org_user.user_id).await?; + // 检查用户密码 + if rtsa_db::password_util::verify_password( + &user_login_dto.password, + &user.password, + ) + .is_ok() + { + Ok(Jwt::build_from(Claims::new(user.id, org_id))?) + } else { + warn!( + "密码不匹配: username={}, org_id={}", + user_login_dto.username, org_id + ); + Err(BusinessError::AuthError( + "用户不存在或密码不正确".to_string(), + )) + } + } + _ => Err(BusinessError::AuthError( "用户不存在或密码不正确".to_string(), - )); - } - let org_user = org_user.unwrap(); - let user = db_accessor.query_user(org_user.user_id).await?; - // 检查用户密码 - if rtsa_db::password_util::verify_password(&info.password, &user.password) { - Ok(Jwt::build_from(Claims::new(user.id, org_id))?) - } else { - warn!("密码不匹配: username={}, org_id={}", info.username, org_id); - Err(BusinessError::AuthError( - "用户不存在或密码不正确".to_string(), - )) + )), } } }