Rust登录注册模块

Rust04-登录注册模块

用户模块的介绍

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

👉 用户模块

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

javascript 复制代码
src/
├── main.rs
├── database/
│   └── mod.rs
└── modules/
    ├── mod.rs
    └── user/
        ├── mod.rs
        ├── routes.rs
        ├── models.rs      # 用户数据模型
        ├── services.rs    # 业务逻辑
        └── handlers.rs    # 处理函数(可选)
🍎配置插件bcrypt

Cargo.toml之中添加依赖插件

javascript 复制代码
bcrypt = "0.15"
🍎main.rs 注册模块

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

javascript 复制代码
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 模块入口

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

javascript 复制代码
pub mod handlers;
pub mod models;
pub mod routes; // 必须有这一行,否则无法使用路由
🍎models.rs

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

javascript 复制代码
// # 用户数据模型
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

先添加我们的路由接口

javascript 复制代码
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

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

javascript 复制代码
use serde::Serialize;

#[derive(Serialize)]
pub struct ApiResponse {
    pub code: i32,
    pub msg: &'static str,
}
🍎 在main.rs之中声明
javascript 复制代码
mod common {
    pub mod response;
}
🍎 在handlers.rs之中定义并使用

引入

javascript 复制代码
use crate::common::response::ApiResponse;// 导入 ApiResponse 模型

使用

javascript 复制代码
// 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: "注册失败",
            })
        }
    }
}
🍎测试接口
javascript 复制代码
//成功的时候返回
{
    "code": 200,
    "msg": "注册成功"
}

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

👉用户登录/login

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

🍎src\modules\user\routes.rs

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

javascript 复制代码
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之中引入
javascript 复制代码
use bcrypt::{hash, DEFAULT_COST};// 导入 bcrypt 库

编写登录接口

javascript 复制代码
// 登录接口
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: "用户名或密码错误",
        })
    }
}
🍎测试接口
javascript 复制代码
// 失败的时候返回格式
{
    "code": 400,
    "msg": "用户名或密码错误"
}


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

登录接口ok

相关推荐
S***q3773 分钟前
Spring Boot管理用户数据
java·spring boot·后端
BD_Marathon7 分钟前
SpringBoot——辅助功能之切换web服务器
服务器·前端·spring boot
Kagol7 分钟前
JavaScript 中的 sort 排序问题
前端·javascript
毕设源码-郭学长26 分钟前
【开题答辩全过程】以 基于SpringBoot框架的民俗文化交流与交易平台的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
eason_fan33 分钟前
Service Worker 缓存请求:前端性能优化的进阶利器
前端·性能优化
l***217840 分钟前
SpringBoot Maven快速上手
spring boot·后端·maven
光影少年42 分钟前
rn如何和原生进行通信,是单线程还是多线程,通信方式都有哪些
前端·react native·react.js·taro
好大哥呀1 小时前
Java Web的学习路径
java·前端·学习
f***14771 小时前
SpringBoot实战:高效实现API限流策略
java·spring boot·后端
计算机毕设VX:Fegn08951 小时前
计算机毕业设计|基于springboot + vue动物园管理系统(源码+数据库+文档)
数据库·vue.js·spring boot·后端·课程设计