You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Rust全栈登录功能:JWT生成及字段缺失问题求助

解决方案:Rust Web应用登录流程的两个核心问题处理

问题1:登录时无法获取用户ID生成JWT

登录阶段获取用户ID的核心逻辑是通过用户名/密码从数据库查询完整的用户实例,你的verify_user_credentials函数需要确保返回包含ID的用户结构体,而不是仅验证密码不返回用户数据。

修复步骤:

  1. 确保verify_user_credentials函数查询数据库时返回完整用户(包含ID):
use diesel::prelude::*;
use crate::models::User; // 这个User结构体必须包含id字段
use crate::schema::users::dsl::*;
use bcrypt;

pub fn verify_user_credentials(
    username_input: &str,
    password_input: &str,
    db_conn: &PgConnection
) -> Result<User, Box<dyn std::error::Error>> {
    // 从数据库查询匹配用户名的用户(包含id)
    let user = users
        .filter(username.eq(username_input))
        .first::<User>(db_conn)?;
    
    // 验证密码
    if bcrypt::verify(password_input, &user.password_hash)? {
        Ok(user)
    } else {
        Err("Invalid password".into())
    }
}
  1. 在登录接口中调用该函数,直接从返回的User实例中取id生成JWT:
use rocket::serde::json::Json;
use rocket::http::Status;
use jsonwebtoken::{encode, Header, Algorithm, EncodingKey};
use crate::models::{LoginUser, ResponseUser, User};
use crate::db::DbConn;

#[post("/login", data = "<login_data>")]
pub async fn login(
    login_data: Json<LoginUser>,
    db_conn: DbConn
) -> Result<Json<ResponseUser>, Status> {
    let user = db_conn.run(|c| {
        verify_user_credentials(&login_data.username, &login_data.password, c)
    }).await.map_err(|_| Status::Unauthorized)?;

    // 使用user.id生成JWT
    let token = encode(
        &Header::new(Algorithm::HS256),
        &serde_json::json!({"user_id": user.id}),
        &EncodingKey::from_secret("your_secret_key".as_ref())
    ).map_err(|_| Status::InternalServerError)?;

    Ok(Json(ResponseUser {
        id: user.id,
        username: user.username,
        token
    }))
}

问题2:Rocket解析LoginUser失败 & 前端无法解析ResponseUser

后端解析失败原因:

你的LoginUser结构体定义了id字段,但前端登录请求体里只需要传用户名和密码,不需要id,导致Rocket反序列化时找不到该字段报错。

修复LoginUser结构体:

use serde::Deserialize;

// 登录请求只需要用户名和密码,去掉id字段或者标记为反序列化时跳过
#[derive(Debug, Deserialize)]
pub struct LoginUser {
    pub username: String,
    pub password: String,
    // 如果必须保留id字段,添加以下属性让Rocket忽略反序列化时的缺失
    // #[serde(skip_deserializing)]
    // pub id: Option<i32>,
}

前端无法解析ResponseUser原因:

前端Yew中的ResponseUser结构体与后端返回的JSON字段不匹配,或者后端返回格式错误。

修复前端结构体定义:

确保字段名、类型完全匹配后端的ResponseUser:

use serde::Deserialize;

#[derive(Debug, Clone, PartialEq, Deserialize)]
pub struct ResponseUser {
    pub id: i32,
    pub username: String,
    pub token: String,
}

同时检查前端请求代码,确保提交的是正确的JSON格式(仅含username和password):

// Yew中提交登录请求的示例代码
let login_request = serde_json::json!({
    "username": username,
    "password": password
});

let response = reqwest::Client::new()
    .post("/api/login")
    .json(&login_request)
    .send()
    .await?
    .json::<ResponseUser>()
    .await?;

内容的提问来源于stack exchange,提问作者apoorv569

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.10 22:33:16