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

相关推荐
0思必得04 小时前
[Web自动化] Selenium处理动态网页
前端·爬虫·python·selenium·自动化
东东5164 小时前
智能社区管理系统的设计与实现ssm+vue
前端·javascript·vue.js·毕业设计·毕设
catino4 小时前
图片、文件的预览
前端·javascript
layman05286 小时前
webpack5 css-loader:从基础到原理
前端·css·webpack
半桔6 小时前
【前端小站】CSS 样式美学:从基础语法到界面精筑的实战宝典
前端·css·html
AI老李6 小时前
PostCSS完全指南:功能/配置/插件/SourceMap/AST/插件开发/自定义语法
前端·javascript·postcss
_OP_CHEN6 小时前
【前端开发之CSS】(一)初识 CSS:网页化妆术的终极指南,新手也能轻松拿捏页面美化!
前端·css·html·网页开发·样式表·界面美化
啊哈一半醒6 小时前
CSS 主流布局
前端·css·css布局·标准流 浮动 定位·flex grid 响应式布局
PHP武器库7 小时前
ULUI:不止于按钮和菜单,一个专注于“业务组件”的纯 CSS 框架
前端·css
电商API_180079052477 小时前
第三方淘宝商品详情 API 全维度调用指南:从技术对接到生产落地
java·大数据·前端·数据库·人工智能·网络爬虫