151 lines
4.1 KiB
Rust
151 lines
4.1 KiB
Rust
// NAC资产一键上链系统 - 认证API处理器
|
||
|
||
use actix_web::{web, HttpResponse};
|
||
use serde::{Deserialize, Serialize};
|
||
use jsonwebtoken::{encode, EncodingKey, Header};
|
||
use bcrypt::{hash, verify, DEFAULT_COST};
|
||
|
||
use crate::database::DbPool;
|
||
use crate::error::Result;
|
||
use crate::models::User;
|
||
use crate::middleware::Claims;
|
||
use crate::response::ApiResponse;
|
||
|
||
/// 注册请求
|
||
#[derive(Debug, Deserialize)]
|
||
pub struct RegisterRequest {
|
||
pub username: String,
|
||
pub password: String,
|
||
pub email: String,
|
||
pub full_name: String,
|
||
}
|
||
|
||
/// 登录请求
|
||
#[derive(Debug, Deserialize)]
|
||
pub struct LoginRequest {
|
||
pub username: String,
|
||
pub password: String,
|
||
}
|
||
|
||
/// 登录响应
|
||
#[derive(Debug, Serialize)]
|
||
pub struct LoginResponse {
|
||
pub token: String,
|
||
pub user: UserInfo,
|
||
}
|
||
|
||
/// 用户信息
|
||
#[derive(Debug, Serialize)]
|
||
pub struct UserInfo {
|
||
pub id: String,
|
||
pub username: String,
|
||
pub email: String,
|
||
pub full_name: String,
|
||
pub role: String,
|
||
}
|
||
|
||
/// 注册
|
||
pub async fn register(
|
||
pool: web::Data<DbPool>,
|
||
req: web::Json<RegisterRequest>,
|
||
) -> Result<HttpResponse> {
|
||
log::info!("用户注册:username = {}", req.username);
|
||
|
||
// 检查用户名是否已存在
|
||
if User::find_by_username(&pool, &req.username).await.is_ok() {
|
||
return Ok(HttpResponse::BadRequest().json(ApiResponse::<()>::error("用户名已存在")));
|
||
}
|
||
|
||
// 检查邮箱是否已存在
|
||
if User::find_by_email(&pool, &req.email).await.is_ok() {
|
||
return Ok(HttpResponse::BadRequest().json(ApiResponse::<()>::error("邮箱已存在")));
|
||
}
|
||
|
||
// 哈希密码
|
||
let password_hash = hash(&req.password, DEFAULT_COST)
|
||
.map_err(|e| crate::error::OnboardingError::Internal(format!("密码哈希失败: {}", e)))?;
|
||
|
||
// 创建用户
|
||
let user = User::create(
|
||
&pool,
|
||
&req.username,
|
||
&password_hash,
|
||
&req.email,
|
||
&req.full_name,
|
||
).await?;
|
||
|
||
log::info!("用户注册成功:user_id = {}", user.id);
|
||
|
||
Ok(HttpResponse::Ok().json(ApiResponse::success(UserInfo {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email,
|
||
full_name: user.full_name,
|
||
role: user.role,
|
||
})))
|
||
}
|
||
|
||
/// 登录
|
||
pub async fn login(
|
||
pool: web::Data<DbPool>,
|
||
req: web::Json<LoginRequest>,
|
||
) -> Result<HttpResponse> {
|
||
log::info!("用户登录:username = {}", req.username);
|
||
|
||
// 查找用户
|
||
let user = User::find_by_username(&pool, &req.username).await?;
|
||
|
||
// 验证密码
|
||
let valid = verify(&req.password, &user.password_hash)
|
||
.map_err(|e| crate::error::OnboardingError::Internal(format!("密码验证失败: {}", e)))?;
|
||
|
||
if !valid {
|
||
return Ok(HttpResponse::Unauthorized().json(ApiResponse::<()>::error("用户名或密码错误")));
|
||
}
|
||
|
||
// 生成JWT token
|
||
let jwt_secret = std::env::var("JWT_SECRET").unwrap_or_else(|_| "nac-secret-key".to_string());
|
||
|
||
let claims = Claims {
|
||
sub: user.id.clone(),
|
||
username: user.username.clone(),
|
||
role: user.role.clone(),
|
||
exp: (chrono::Utc::now() + chrono::Duration::days(7)).timestamp() as usize,
|
||
};
|
||
|
||
let token = encode(
|
||
&Header::default(),
|
||
&claims,
|
||
&EncodingKey::from_secret(jwt_secret.as_bytes()),
|
||
).map_err(|e| crate::error::OnboardingError::Internal(format!("Token生成失败: {}", e)))?;
|
||
|
||
log::info!("用户登录成功:user_id = {}", user.id);
|
||
|
||
Ok(HttpResponse::Ok().json(ApiResponse::success(LoginResponse {
|
||
token,
|
||
user: UserInfo {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email,
|
||
full_name: user.full_name,
|
||
role: user.role,
|
||
},
|
||
})))
|
||
}
|
||
|
||
/// 获取当前用户信息
|
||
pub async fn me(
|
||
pool: web::Data<DbPool>,
|
||
claims: web::ReqData<Claims>,
|
||
) -> Result<HttpResponse> {
|
||
let user = User::find_by_id(&pool, &claims.sub).await?;
|
||
|
||
Ok(HttpResponse::Ok().json(ApiResponse::success(UserInfo {
|
||
id: user.id,
|
||
username: user.username,
|
||
email: user.email,
|
||
full_name: user.full_name,
|
||
role: user.role,
|
||
})))
|
||
}
|