可以在使用temp_token的情况下使浏览器和微信小程序前端都能获取到正确的数据

This commit is contained in:
2025-09-29 11:56:08 +08:00
parent 56844a537f
commit ea64c436b6
5 changed files with 150 additions and 23 deletions

View File

@@ -266,12 +266,11 @@ async fn generate_temp_token_handler(
}
// 获取天气数据详情
// 修改获取天气数据详情接口移除路径中的id参数
#[get("/weather/details")]
async fn get_weather_details(
pool: web::Data<PgPool>,
claims: Option<web::ReqData<Claims>>, // 原有JWT的claims变为可选
query: web::Query<serde_json::Value>, // 用于获取URL参数temp_token和id
claims: Option<web::ReqData<Claims>>,
query: web::Query<serde_json::Value>,
) -> impl Responder {
let jwt_secret = match std::env::var("JWT_SECRET") {
Ok(secret) => secret,
@@ -284,9 +283,12 @@ async fn get_weather_details(
}
};
// 标记是否使用临时token
let mut is_temp_token = false;
// 1. 优先检查临时tokenURL参数
let (openid, weather_id) =
if let Some(temp_token) = query.get("temp_token").and_then(|v| v.as_str()) {
is_temp_token = true; // 标记为临时token访问
// 验证临时token
let temp_claims = match auth::verify_temp_token(temp_token, &jwt_secret) {
Ok(c) => c,
@@ -327,20 +329,17 @@ async fn get_weather_details(
});
};
// 后续逻辑校验openid对资源的权限复用原有逻辑
match db::get_weather_details(pool.get_ref(), weather_id).await {
Ok(weather_data) => {
if weather_data.openid != openid {
// 获取天气数据
let weather_data = match db::get_weather_details(pool.get_ref(), weather_id).await {
Ok(data) => {
if data.openid != openid {
return HttpResponse::Forbidden().json(ErrorResponse {
error: "无权限访问该数据".to_string(),
errcode: Some(403),
errmsg: None,
});
}
HttpResponse::Ok().json(serde_json::json!({
"success": true,
"data": weather_data
}))
data
}
Err(error_msg) => {
eprintln!("获取天气数据详情失败: {}", error_msg);
@@ -349,12 +348,59 @@ async fn get_weather_details(
} else {
500
};
HttpResponse::Ok().json(serde_json::json!({
return HttpResponse::Ok().json(serde_json::json!({
"success": false,
"errcode": errcode,
"errmsg": error_msg
}))
}));
}
};
// 根据访问方式返回不同格式
if is_temp_token {
// 临时token访问返回HTML页面数据交由前端afterbody.js渲染
// 读取模板文件
let index_html = match TEMPLATES_DIR.get_file("index.html") {
Some(file) => file.contents_utf8().unwrap_or_default(),
None => {
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "无法找到模板文件".to_string(),
errcode: Some(500),
errmsg: None,
});
}
};
// 将天气数据序列化为JSON字符串供前端JS使用
let weather_data_json = serde_json::to_string(&weather_data).unwrap_or_default();
// 生成数据注入脚本将数据挂载到window对象供afterbody.js访问
let data_script = format!(
r#"
<script>
// 注入后端数据供前端渲染使用
window.weatherData = {};
</script>
"#,
weather_data_json
);
// 将数据脚本插入到模板中,同时显示详细信息容器
let rendered_html = index_html
.replace("<!-- 详细信息将在这里显示 -->", &data_script)
.replace(
"style=\"display: none;\"",
"", // 显示详细信息容器,供前端渲染内容
);
HttpResponse::Ok()
.content_type("text/html; charset=utf-8")
.body(rendered_html)
} else {
// JWT访问返回JSON数据
HttpResponse::Ok().json(serde_json::json!({
"success": true,
"data": weather_data
}))
}
}
@@ -458,6 +504,34 @@ async fn delete_weather(
}
}
// 在 main.rs 中添加以下函数,用于处理静态文件请求
async fn serve_static_files(path: web::Path<String>) -> impl Responder {
// 获取请求的文件路径(例如 "css/style.css"
let file_path = path.into_inner();
// 从嵌入的 STATIC_DIR 中查找文件
match STATIC_DIR.get_file(&file_path) {
Some(file) => {
// 根据文件扩展名设置 Content-Type
let content_type = match file_path.split('.').last() {
Some("css") => "text/css",
Some("js") => "application/javascript",
Some("html") => "text/html",
Some("ttf") | Some("woff") | Some("woff2") => "font/woff2", // 字体文件
_ => "application/octet-stream", // 默认类型
};
HttpResponse::Ok()
.content_type(content_type)
.body(file.contents())
}
None => {
// 文件不存在时返回 404
HttpResponse::NotFound().body("静态文件不存在")
}
}
}
// 创建服务器配置的函数
fn create_server_config(
pool: PgPool,
@@ -475,6 +549,8 @@ fn create_server_config(
.app_data(web::Data::new(pool))
.app_data(web::Data::new(http_client))
// 公开接口(无需验证)
// 注册静态文件服务:处理 /static/* 路径的请求
.service(web::resource("/static/{tail:.*}").route(web::get().to(serve_static_files)))
.service(login)
.service(get_weather_details) // 新增
// 需要验证的接口(使用 from_fn 包装中间件)