fix: 调整路由顺序,修复静态文件被JWT拦截的问题
- 将 /static/{tail:.*} 路由移到受保护 scope 之前
- 确保静态文件无需认证即可访问
This commit is contained in:
125
src/handlers/auth.rs
Normal file
125
src/handlers/auth.rs
Normal file
@@ -0,0 +1,125 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user