使用了jwt作为身份验证和分发

This commit is contained in:
2025-09-26 13:48:18 +08:00
parent 4f0a171366
commit 1c2eb82248
5 changed files with 217 additions and 76 deletions

View File

@@ -1,59 +1,19 @@
use actix_web::middleware::from_fn;
use actix_web::{App, HttpResponse, HttpServer, Responder, Result, post, web};
use db::create_pool;
use reqwest::Client;
use sqlx::postgres::PgPool;
mod auth;
mod db;
mod models;
use db::insert_weather_data;
use models::{
ErrorResponse, OpenIdRequest, OpenIdResponse, UserIdResponse, WeChatApiResponse,
WeChatLoginRequest, WeatherData,
};
use auth::{generate_token, jwt_middleware};
use db::{create_pool, insert_weather_data};
use models::{ErrorResponse, WeChatApiResponse, WeChatLoginRequest, WeatherData};
// 新增根据openid获取用户ID的端点
#[post("/getmyid")]
async fn get_user_id(pool: web::Data<PgPool>, request: web::Json<OpenIdRequest>) -> impl Responder {
let openid = &request.openid;
// 查询用户ID
let query = r#"
SELECT id FROM users WHERE openid = $1
"#;
let result: Result<Option<(i32,)>, sqlx::Error> = sqlx::query_as::<_, (i32,)>(query)
.bind(openid)
.fetch_optional(pool.get_ref())
.await;
match result {
Ok(Some(user_id)) => {
println!("Found user ID {} for openid {}", user_id.0, openid);
HttpResponse::Ok().json(UserIdResponse { user_id: user_id.0 })
}
Ok(None) => {
println!("No user found with openid: {}", openid);
HttpResponse::NotFound().json(ErrorResponse {
error: format!("未找到openid为 {} 的用户", openid),
errcode: Some(404), // 添加错误码
errmsg: Some("用户不存在".to_string()), // 添加错误消息
})
}
Err(e) => {
eprintln!("Database error: {}", e);
HttpResponse::InternalServerError().json(ErrorResponse {
error: format!("数据库查询错误: {}", e),
errcode: Some(500), // 添加错误码
errmsg: Some(e.to_string()), // 添加错误消息
})
}
}
}
// 获取openid的API端点
#[post("/getopenid")]
async fn get_openid(
// 登录的API端点
#[post("/api/login")]
async fn login(
pool: web::Data<PgPool>,
req: web::Json<WeChatLoginRequest>,
http_client: web::Data<Client>,
@@ -121,6 +81,7 @@ async fn get_openid(
errmsg: wechat_data.errmsg,
});
}
// 获取openid
let openid = match wechat_data.openid {
Some(id) => id,
@@ -133,36 +94,75 @@ async fn get_openid(
}
};
// 检查用户是否已存在,不存在则创建
// 3. 检查用户是否已存在,不存在则创建(显式处理数据库错误)
let query = r#"
INSERT INTO users (openid)
VALUES ($1)
ON CONFLICT (openid) DO NOTHING
RETURNING id
"#;
INSERT INTO users (openid, name, type)
VALUES ($1, left($1, 8), 2)
ON CONFLICT (openid) DO NOTHING
RETURNING id
"#;
let result = sqlx::query_as::<_, (i32,)>(query)
let user_id = match sqlx::query_as::<_, (i32,)>(query)
.bind(&openid)
.fetch_optional(pool.get_ref())
.await;
match result {
Ok(Some(user_id)) => {
println!("用户已存在ID: {}", user_id.0);
.await
{
Ok(Some((id,))) => {
// 已存在用户直接获取ID
println!("用户已存在ID: {}", id);
id
}
Ok(None) => {
// 新用户创建成功需再次查询ID因ON CONFLICT DO NOTHING不返回值
println!("新用户已创建openid: {}", openid);
match sqlx::query_as::<_, (i32,)>("SELECT id FROM users WHERE openid = $1")
.bind(&openid)
.fetch_one(pool.get_ref())
.await
{
Ok((id,)) => id,
Err(e) => {
eprintln!("查询新用户ID失败: {}", e);
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "创建用户后查询ID失败".to_string(),
errcode: Some(500),
errmsg: Some(e.to_string()),
});
}
}
}
Err(e) => {
eprintln!("数据库操作失败: {}", e);
// 即使数据库操作失败我们仍然返回openid因为微信登录已经成功
// 数据库操作失败
eprintln!("用户查询/创建失败: {}", e);
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "用户信息处理失败".to_string(),
errcode: Some(500),
errmsg: Some(e.to_string()),
});
}
}
};
// 返回openid给前端
HttpResponse::Ok().json(OpenIdResponse { openid })
// 4. 生成JWT token显式处理所有可能的错误
// 4.1 获取JWT密钥
let jwt_secret = match std::env::var("JWT_SECRET") {
Ok(secret) => secret,
Err(_) => {
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "服务器配置错误缺少JWT_SECRET".to_string(),
errcode: Some(500),
errmsg: None,
});
}
};
// 4.2 编码生成token
let token = generate_token(user_id, &openid, 2, &jwt_secret);
// 5. 返回成功响应包含token
HttpResponse::Ok().json(token)
}
#[post("/weather-test")]
#[post("/api/post-weather-data")]
async fn post_weather_data(
data: web::Json<WeatherData>,
pool: web::Data<PgPool>,
@@ -215,9 +215,14 @@ fn create_server_config(
App::new()
.app_data(web::Data::new(pool))
.app_data(web::Data::new(http_client))
.service(get_user_id)
.service(get_openid)
.service(post_weather_data)
// 公开接口(无需验证)
.service(login)
// 需要验证的接口(使用 from_fn 包装中间件)
.service(
web::scope("")
.wrap(from_fn(jwt_middleware)) // 关键修改:用 from_fn 包装
.service(post_weather_data),
)
}
#[actix_web::main]