Files
asd-backend/src/handlers/auth.rs
Milky0217 a819a0db91 fix: 调整路由顺序,修复静态文件被JWT拦截的问题
- 将 /static/{tail:.*} 路由移到受保护 scope 之前
- 确保静态文件无需认证即可访问
2026-04-15 11:51:59 +08:00

126 lines
4.0 KiB
Rust
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
use actix_web::{web, HttpResponse, Responder, post};
use reqwest::Client;
use sqlx::postgres::PgPool;
use tracing::{debug, error, info, warn};
use crate::auth::generate_token;
use crate::models::{
AppState, ErrorResponse, TokenResponse, WeChatApiResponse, WeChatLoginRequest,
};
#[post("/api/login")]
pub async fn login(
pool: web::Data<PgPool>,
req: web::Json<WeChatLoginRequest>,
http_client: web::Data<Client>,
app_state: web::Data<AppState>,
) -> impl Responder {
let url = format!(
"https://api.weixin.qq.com/sns/jscode2session?appid={}&secret={}&js_code={}&grant_type=authorization_code",
app_state.wechat_appid, app_state.wechat_secret, req.code
);
debug!("准备调用微信API: {}", url.replace(&app_state.wechat_secret, "***"));
let wechat_response = match http_client.get(&url).send().await {
Ok(response) => {
debug!("微信API请求成功状态码: {}", response.status());
response
}
Err(e) => {
error!("微信API请求失败: {}", e);
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "请求微信服务失败".to_string(),
errcode: None,
errmsg: None,
});
}
};
let wechat_data: WeChatApiResponse = match wechat_response.json().await {
Ok(data) => {
debug!("微信API响应解析成功");
data
}
Err(e) => {
error!("微信API响应解析失败: {}", e);
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "解析微信响应失败".to_string(),
errcode: None,
errmsg: None,
});
}
};
if let Some(errcode) = wechat_data.errcode {
warn!(
"微信登录验证失败 - 错误码: {}, 错误信息: {:?}",
errcode, wechat_data.errmsg
);
return HttpResponse::BadRequest().json(ErrorResponse {
error: "微信登录失败".to_string(),
errcode: Some(errcode),
errmsg: wechat_data.errmsg,
});
}
let openid = match wechat_data.openid {
Some(id) => {
let masked_openid = format!("{}***{}", &id[0..4], &id[id.len() - 4..]);
debug!("获取到用户openid: {}", masked_openid);
id
}
None => {
error!("微信API响应中未包含openid");
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "微信API未返回openid".to_string(),
errcode: None,
errmsg: None,
});
}
};
let upsert_query = r#"
INSERT INTO users (openid, name, type)
VALUES ($1, left($1, 8), 2)
ON CONFLICT (openid) DO UPDATE SET id = users.id
RETURNING id
"#;
let user_id = match sqlx::query_as::<_, (i32,)>(upsert_query)
.bind(&openid)
.fetch_one(pool.get_ref())
.await
{
Ok((id,)) => {
info!("用户登录/注册成功用户ID: {}", id);
id
}
Err(e) => {
error!("用户信息处理失败: {}", e);
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "用户信息处理失败".to_string(),
errcode: Some(500),
errmsg: None,
});
}
};
let token = match generate_token(user_id, &openid, 2, &app_state.jwt_secret) {
Ok(t) => {
debug!("JWT生成成功: {}", &t[0..8]);
t
}
Err(e) => {
error!("JWT生成失败: {}", e);
return HttpResponse::InternalServerError().json(ErrorResponse {
error: "生成身份令牌失败".to_string(),
errcode: Some(500),
errmsg: None,
});
}
};
let token_response = TokenResponse::new(token);
HttpResponse::Ok().json(token_response)
}