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, req: web::Json, http_client: web::Data, app_state: web::Data, ) -> 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) }