Rust登录注册模块

举报
林太白 发表于 2025/07/23 13:12:42 2025/07/23
【摘要】 Rust登录注册模块

Rust04-登录注册模块

用户模块的介绍

接下来我们用 actix-web + sqlx + MySQL写一个完整的用户注册登录模块

👉 用户模块

先来看看我们的模块结构是什么样子的

src/
├── main.rs
├── database/
│   └── mod.rs
└── modules/
    ├── mod.rs
    └── user/
        ├── mod.rs
        ├── routes.rs
        ├── models.rs      # 用户数据模型
        ├── services.rs    # 业务逻辑
        └── handlers.rs    # 处理函数(可选)

🍎配置插件bcrypt

Cargo.toml之中添加依赖插件

bcrypt = "0.15"

🍎main.rs注册模块

main.rs入口文件之中引入模块

mod common {
    pub mod response;
}
mod modules {
    pub mod user;
}

use actix_cors::Cors;
use actix_web::{App, HttpServer, Responder,HttpResponse,web};
use dotenv::dotenv;
use sqlx::MySqlPool;
use std::env;

async fn welcome() -> impl Responder {
    let addr = "127.0.0.1:8080/api";
    println!("服务已经启动,数据库已连接,地址为:{}", addr);
    HttpResponse::Ok().body(format!("欢迎访问NexusRust API,服务地址:{}", addr))
}

#[actix_web::main]
async fn main() -> std::io::Result<()> {
    dotenv().ok(); // 一定要在读取环境变量之前调用

    let database_url = env::var("DATABASE_URL").unwrap(); // 获取数据库连接字符串
    let pool = MySqlPool::connect(&database_url).await.unwrap();
    
    HttpServer::new(move || {
        let cors = Cors::default()
            .allow_any_origin()
            .allow_any_method()
            .allow_any_header(); // 允许所有来源
        App::new()
            // 添加 CORS 中间件
            .wrap(cors)
            // 2. 注入数据库连接池
            .app_data(web::Data::new(pool.clone()))
            // 3. 注册模块路由加前缀
            .service(
                web::scope("/api") // 这里加上 /api 前缀
                    .configure(modules::user::routes::config),
            )
            // 3. 注册路由
            .route("/", web::get().to(welcome))
    })
    .bind("127.0.0.1:8888")?
    .run()
    .await
}

🍎user=>mod.rs 模块入口

组织声明子模块,在模块入口文件之中进行声明组织子模块

pub mod handlers;
pub mod models;
pub mod routes; // 必须有这一行,否则无法使用路由

🍎models.rs

声明该模块对应的数据库字段的类型,当然了,这个并不是必须的,更像是我们数据的类型

// # 用户数据模型
use serde::{Serialize, Deserialize};

#[derive(Debug, Serialize, Deserialize, sqlx::FromRow)]
pub struct User {
    pub id: i64,
    pub name: String,
    pub email: String,
}

👉用户注册/register

接下来我们开始从用户注册接口写我们的整个服务部分,一开始可能会略微简单一些,到后面我们不断的进行优化和升级

🍎src\modules\user\routes.rs

先添加我们的路由接口

pub fn config(cfg: &mut web::ServiceConfig) {
  cfg.route("/register", web::post().to(crate::modules::user::handlers::register_users));
  cfg.route("/users", web::get().to(crate::modules::user::handlers::get_all_users));
}

🍎src\common\response.rs

添加一个公共模块存放我们返回的数据类型

use serde::Serialize;

#[derive(Serialize)]
pub struct ApiResponse {
    pub code: i32,
    pub msg: &'static str,
}

🍎 在main.rs之中声明

mod common {
    pub mod response;
}

🍎 在handlers.rs之中定义并使用

引入

use crate::common::response::ApiResponse;// 导入 ApiResponse 模型

使用



// use crate::modules::user::models::ApiResponse; 
use bcrypt::{hash, DEFAULT_COST};
// use serde::Serialize;
use crate::common::response::ApiResponse;// 导入 ApiResponse 模型

// 注册请求体
#[derive(serde::Deserialize)]
pub struct RegisterRequest {
    pub username: String,
    pub password: String,
    // 其他字段可选
}

// use actix_web::web;
pub async fn register_users(
    pool: web::Data<MySqlPool>,
    form: web::Json<RegisterRequest>,
) -> HttpResponse {
    // 检查用户名是否已存在
    let exists: (i64,) = match sqlx::query_as("SELECT COUNT(*) FROM sys_user WHERE username = ?")
        .bind(&form.username)
        .fetch_one(pool.get_ref())
        .await
    {
        Ok(count) => count,
        Err(_) => {
            return HttpResponse::InternalServerError().json(ApiResponse {
                code: 500,
                msg: "数据库错误",
            })
        }
    };
    if exists.0 > 0 {
        return HttpResponse::Ok().json(ApiResponse {
            code: 400,
            msg: "用户名已存在",
        });
    }

    // 密码加密
    let hashed_pwd = match hash(&form.password, DEFAULT_COST) {
        Ok(pwd) => pwd,
        Err(_) => {
            return HttpResponse::InternalServerError().json(ApiResponse {
                code: 500,
                msg: "密码加密失败",
            })
        }
    };

    // 插入新用户
    let result = sqlx::query("INSERT INTO sys_user (username, password) VALUES (?, ?)")
        .bind(&form.username)
        .bind(&hashed_pwd)
        .execute(pool.get_ref())
        .await;

    match result {
        Ok(_) => HttpResponse::Ok().json(ApiResponse {
            code: 200,
            msg: "注册成功",
        }),
        Err(e) => {
            eprintln!("注册失败: {:?}", e);
            HttpResponse::InternalServerError().json(ApiResponse {
                code: 500,
                msg: "注册失败",
            })
        }
    }
}

🍎测试接口

//成功的时候返回
{
    "code": 200,
    "msg": "注册成功"
}

//失败的时候返回的数据
{
    "code": 400,
    "msg": "用户名已存在"
}

👉用户登录/login

接下来我们开始写我们登录的接口模块

🍎src\modules\user\routes.rs

先添加我们的路由接口,还是在我们之前的文件之中

pub fn config(cfg: &mut web::ServiceConfig) {
  cfg.route("/register", web::post().to(crate::modules::user::handlers::register_users));
  cfg.route("/login", web::post().to(crate::modules::user::handlers::login_users));
}

🍎 在handlers.rs之中引入

use bcrypt::{hash, DEFAULT_COST};// 导入 bcrypt 库

编写登录接口

// 登录接口
pub async fn login_users(
    pool: web::Data<MySqlPool>,
    form: web::Json<LoginRequest>,
) -> HttpResponse {
    // 查询用户
    let user = sqlx::query_as::<_, User>("SELECT * FROM sys_user WHERE username = ?")
        .bind(&form.username)
        .fetch_one(pool.get_ref())
        .await;

    let user = match user {
        Ok(u) => u,
        Err(_) => {
            return HttpResponse::Ok().json(ApiResponse {
                code: 400,
                msg: "用户名或密码错误",
            });
        }
    };

    // 校验密码
    let is_valid = verify(&form.password, &user.password).unwrap_or(false);

    if is_valid {
        HttpResponse::Ok().json(ApiResponse {
            code: 200,
            msg: "登录成功",
        })
    } else {
        HttpResponse::Ok().json(ApiResponse {
            code: 400,
            msg: "用户名或密码错误",
        })
    }
}

🍎测试接口

// 失败的时候返回格式
{
    "code": 400,
    "msg": "用户名或密码错误"
}


//成功的时候返回格式
{
    "code": 200,
    "msg": "登录成功"
}

登录接口ok

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。