用户认证系统 #
项目结构 #
text
auth-project/
├── Cargo.toml
├── src/
│ ├── main.rs
│ ├── auth.rs
│ ├── handlers.rs
│ ├── models.rs
│ └── repository.rs
└── tests/
完整实现 #
rust
use actix_web::{web, App, HttpResponse, HttpServer, Responder, Error};
use bcrypt::{hash, verify, DEFAULT_COST};
use jsonwebtoken::{decode, encode, Algorithm, DecodingKey, EncodingKey, Header, Validation};
use serde::{Deserialize, Serialize};
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
#[derive(Debug, Clone, Serialize, Deserialize)]
struct User {
id: u32,
username: String,
password_hash: String,
}
#[derive(Deserialize)]
struct RegisterRequest {
username: String,
password: String,
}
#[derive(Deserialize)]
struct LoginRequest {
username: String,
password: String,
}
#[derive(Serialize)]
struct LoginResponse {
token: String,
}
#[derive(Debug, Serialize, Deserialize)]
struct Claims {
sub: String,
exp: usize,
}
struct AppState {
users: Mutex<HashMap<String, User>>,
jwt_secret: String,
}
impl AppState {
fn new(jwt_secret: String) -> Self {
Self {
users: Mutex::new(HashMap::new()),
jwt_secret,
}
}
fn generate_token(&self, user_id: &str) -> Result<String, Error> {
let exp = chrono::Utc::now() + chrono::Duration::hours(24);
let claims = Claims {
sub: user_id.to_string(),
exp: exp.timestamp() as usize,
};
encode(
&Header::default(),
&claims,
&EncodingKey::from_secret(self.jwt_secret.as_bytes()),
)
.map_err(|e| actix_web::error::ErrorInternalServerError(e))
}
}
#[actix_web::post("/register")]
async fn register(
body: web::Json<RegisterRequest>,
state: web::Data<Arc<AppState>>,
) -> impl Responder {
let password_hash = hash(&body.password, DEFAULT_COST).unwrap();
let user = User {
id: 1,
username: body.username.clone(),
password_hash,
};
state.users.lock().unwrap().insert(body.username.clone(), user);
HttpResponse::Created().json(serde_json::json!({ "message": "User created" }))
}
#[actix_web::post("/login")]
async fn login(
body: web::Json<LoginRequest>,
state: web::Data<Arc<AppState>>,
) -> impl Responder {
let users = state.users.lock().unwrap();
match users.get(&body.username) {
Some(user) => {
if verify(&body.password, &user.password_hash).unwrap_or(false) {
match state.generate_token(&user.id.to_string()) {
Ok(token) => HttpResponse::Ok().json(LoginResponse { token }),
Err(e) => HttpResponse::InternalServerError().json(serde_json::json!({ "error": e.to_string() })),
}
} else {
HttpResponse::Unauthorized().json(serde_json::json!({ "error": "Invalid credentials" }))
}
}
None => HttpResponse::Unauthorized().json(serde_json::json!({ "error": "User not found" })),
}
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let state = Arc::new(AppState::new("secret_key".to_string()));
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(state.clone()))
.service(register)
.service(login)
})
.bind("127.0.0.1:8080")?
.run()
.await
}
下一步 #
继续学习 博客系统,了解完整项目开发!
最后更新:2026-03-29