fix: 移除订单自动确认,仅依赖支付宝回调验签;rsa2_verify 支持裸 base64 DER 公钥;.env 取消 git 跟踪

This commit is contained in:
2026-08-10 15:34:44 +08:00
parent 2ce97243ab
commit 49d740e27c
4 changed files with 10 additions and 71 deletions

19
.env
View File

@@ -1,19 +0,0 @@
# .env
DATABASE_URL=postgres://milkydata:44n6FdB8CdDAk5rk@154.37.213.24:5432/milkydata
WECHAT_APPID="wx5b00eb90621802f7"
WECHAT_SECRET="494efc513faa310bfba588bda2849bfd"
JWT_SECRET="your_super_secret_key"
SSL_KEY_PATH=/etc/ssl/private/private.key
SSL_CERT_PATH=/etc/ssl/certs/full_chain.pem
RUST_LOG=info
APP_VERSION="0.2.0"
FREE_USER_DATA_LIMIT=20
SSH_SERVER=root@1panel-server
# 支付宝生产环境配置
# 支付宝生产环境配置
ALIPAY_APP_ID=2021006148681106
ALIPAY_PRIVATE_KEY="MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCImX4Zj18whXYi6l29caq+ShjqT7JwWDbOoz/hEqZqPxQNu6KF59OswcUIv3It4CxJ0/kXsiC/pc6mrN9GedOAPIaz6YydgII/nwHl4OdPPxW8jeomBuiSmcbPcZ4AJTi1YTxrj//8YDIQInVc5/I4HPg+osN4qkqy+xrJ4vGrmyy+ClwHh3OxglGDLhbprH4WCgxKjwTDfR1A84w+pbrST1YaWI7sqqPhVxuYQQPjaLOpXMgrJu5ctnlFVTC27mY2wSIrxajB/6w1SQ+Z+Z149frk47PBOwL+xfKT4gwy3yj/t7WZStzH0gEhG7mXjc6qIjZ8uH5OxUZ+f6gMDpKBAgMBAAECggEAYnI87y7k65NEEOXXqTDCXWIJktTdRRpOZZ5B63QFe4z6ZutTti3d4CPGXQecwnNNd+fNHcbC01wsEvOD9sbWJxV3/zHSpbB4LmHqfEIacoKEp9+fYMiZ1Q3+uoKn3HL268GoSdz+IGUzr20mKE8Bwm8eegXT2qLgMx3FsLpecc3WXmwgMDI/alknO81+xZenLH1Y6+XdsoPVWsS3OY3gnzfYz40n1LaLCQiklBu6AUjSQupSUJ53rGtYpZnp+ImYwBVcYeFL0mZZVId/lzDI2K8eaM/RGVZYsU1vkP6CeSJzWhpr6ftSRRl3VJQou0ytLLX/YeUoXIhsfZ+x3cPKAQKBgQC9ub1z+T/+0lHZwm360otNHQNeEq3FYjnx1x7WOWTXCsAqVZizfmpUYSHoNZeNlyLpbXVsYp22xJmLBArB9LBMvjY1z2iOQJW7F46O6cY38AcgWC41YalLcrk2y4jny6rJZRMjvmDOM67SH01pzZQ6eGJpzSZpTj2Jm/tBsH7gGwKBgQC4UPK5a32ov9YuyzfQXcW341JFlTK2k2D1ewilYSZifpTDqdVpH1gSzGpfoXI7K6Z26xkx1n5rOIe+SxOKaNBj/5PJuEzmMVvUWkFU0IutoqVc2R6h4Rb+9q7llzAavFZ5Ssj1u9Q5Pjhc5Jr8zM6xXk55/4CuqYuBMCcte4fZkwKBgF/kVSEcxX+iBcSuRLAVYlrjYyRVBIdTEj5toCRedd1Kjb3X7YorRsrHHUAkdikWTor0y/iwD06lJ4Xf0SAe8EyZhwTDg/ECK6uYSHFrLshvBOsQJqrMZajAn2RWkye1BOktsPLL8lnGPYHuWE41ncm/tt4K1nM7HFdFA0U8U6QpAoGAe0gRgboG+6cMoJHmjCUciUmwDsCjggEDuk4H024umXSnFlRzXPPNGg3GHJ7E5BTnK+VGHdKlDhxqlvpqYIqI0EnzVNpD/TgIfvm7dvpiYspGJttGpOoEUpc3FnPQhiFxCYHe9pYidgNK+b8id3KZ0YMNpIYkUS8wE0HdAov8qqcCgYEAtRjXzj4JZ5we6aOqv4bcr7xLw4a7wzS99K5EcrbYRxvibUhelooQdgdY40FmdtfuY/4rpHC3R9/13aqcD/WSTFOdOsZAcfTi738y13h3dCy3FZisLYM7rgjUSnQnEGlyR0TYE4Yda490rpYJBjyQIE3EcIlWPerm8vh1wx1Rh90="
ALIPAY_ALIPAY_PUBLIC_KEY="MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAkhLqABUN1E2PCmOznQp+53T3x4j27I96hdatl6lWbCBPwyXnZVW4uYZ4kV+34+i2wCzEtMpUiNQaIsQXx2qD8x0d8szsj7pEZuY+xUUJTzm95fYO2nq4aaQ38T/kxdYrW12is8vwY83rlghdlkvVP2XZCuYoFq9UVieTu6LTDk6v91Mt2xr1Zw1Oj+yg8VpBFXkcS7ORJjiufWzCEoxzlb2KK2AGOLhdc8BJsBfrQ0JAqFB6b0uteUF21DDdPN/sblD8GoRAGuSpDhyQLG+0fDNdcIMyHpsq7bIDNjgYGS8RbKAtb6WyV6vriIemZ0fMvzN5Mpqv2jwCe/31ar//PwIDAQAB"
ALIPAY_GATEWAY="https://openapi.alipay.com/gateway.do"
APP_BASE_URL="https://dev.xmclassmate.top"

View File

@@ -371,45 +371,6 @@ pub async fn get_user_orders(
} }
/// 扫描超过 10 分钟的待支付订单,尝试自动确认(用于回调重试) /// 扫描超过 10 分钟的待支付订单,尝试自动确认(用于回调重试)
/// 返回成功确认的订单数量
pub async fn check_and_retry_pending_orders(pool: &PgPool) -> Result<u64, AppError> {
// 查找超过 10 分钟仍为 pending 的订单
let stuck_orders: Vec<(String,)> = sqlx::query_as(
r#"
SELECT order_no FROM payment_orders
WHERE status = 'pending'
AND created_at < NOW() - INTERVAL '10 minutes'
AND created_at > NOW() - INTERVAL '24 hours'
ORDER BY created_at ASC
"#,
)
.fetch_all(pool)
.await
.map_err(|e| AppError::Database(format!("查询待处理订单失败: {}", e)))?;
if stuck_orders.is_empty() {
return Ok(0);
}
tracing::info!(
"发现 {} 个待处理订单,尝试自动确认...",
stuck_orders.len()
);
let mut confirmed: u64 = 0;
for (order_no,) in &stuck_orders {
match confirm_payment_order_by_orderno(pool, order_no).await {
Ok(_) => {
confirmed += 1;
tracing::info!("定时任务自动确认订单: {}", order_no);
}
Err(e) => {
tracing::warn!("定时任务无法确认订单 {}: {}", order_no, e);
}
}
}
Ok(confirmed)
}
/// 检查会员到期前 7 天的用户,发送即将到期通知 /// 检查会员到期前 7 天的用户,发送即将到期通知
pub async fn check_member_expiry_soon(pool: &PgPool) -> Result<u64, AppError> { pub async fn check_member_expiry_soon(pool: &PgPool) -> Result<u64, AppError> {

View File

@@ -153,9 +153,15 @@ fn rsa2_verify(content: &str, sign: &str, public_key_pem: &str) -> Result<bool,
use rsa::pkcs8::DecodePublicKey; use rsa::pkcs8::DecodePublicKey;
use rsa::RsaPublicKey; use rsa::RsaPublicKey;
use sha2::Digest; use sha2::Digest;
let public_key = let public_key = RsaPublicKey::from_public_key_pem(public_key_pem).or_else(|_| {
RsaPublicKey::from_public_key_pem(public_key_pem) base64::Engine::decode(&base64::engine::general_purpose::STANDARD, public_key_pem)
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?; .map_err(|e| format!("支付宝公钥 base64 解码失败: {}", e))
.and_then(|der| {
RsaPublicKey::from_public_key_der(&der)
.map_err(|e| format!("支付宝公钥 DER 解析失败: {}", e))
})
})
.map_err(|e| format!("支付宝公钥解析失败: {}", e))?;
let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign) let sig_bytes = base64::Engine::decode(&base64::engine::general_purpose::STANDARD, sign)
.map_err(|e| format!("签名 Base64 解码失败: {}", e))?; .map_err(|e| format!("签名 Base64 解码失败: {}", e))?;
let hashed = Sha256::digest(content.as_bytes()); let hashed = Sha256::digest(content.as_bytes());

View File

@@ -244,22 +244,13 @@ async fn main() -> std::io::Result<()> {
Err(e) => warn!("启动时清理 web 登录码失败: {}", e), Err(e) => warn!("启动时清理 web 登录码失败: {}", e),
} }
// 后台定时扫描待支付订单(每 5 分钟)
let pool_clone = pool.clone(); let pool_clone = pool.clone();
actix_web::rt::spawn(async move { actix_web::rt::spawn(async move {
let mut interval = actix_web::rt::time::interval(std::time::Duration::from_secs(300)); let mut interval = actix_web::rt::time::interval(std::time::Duration::from_secs(300));
interval.tick().await; // 跳过立即执行 interval.tick().await; // 跳过立即执行
loop { loop {
interval.tick().await; interval.tick().await;
tracing::info!("[定时任务] 开始扫描待支付订单..."); tracing::info!("[定时任务] 开始...");
match db::check_and_retry_pending_orders(&pool_clone).await {
Ok(confirmed) => {
if confirmed > 0 {
tracing::info!("[定时任务] 自动确认了 {} 个待支付订单", confirmed);
}
}
Err(e) => tracing::warn!("[定时任务] 扫描待支付订单失败: {}", e),
}
// 会员到期前 7 天提醒 // 会员到期前 7 天提醒
if let Err(e) = db::check_member_expiry_soon(&pool_clone).await { if let Err(e) = db::check_member_expiry_soon(&pool_clone).await {