fix: 修复19个Bug (P0-P3) — 持续性调试第7轮发现的问题

P0 (5): crypto/rand session ID, TTS fallback可达性, goroutine defer recover, adminAuth前缀修正
P1 (5): 普通用户密码验证, context传递, priority clamp, 超时重试, 自主思考速率限制
P2 (4): Briefing AI降级, 前端消息类型渲染, Docker Compose补全, PWA 192图标
P3 (5): goroutine错误处理, .gitignore完善, reminder created_at, voice Dockerfile, Go版本更新
This commit is contained in:
2026-05-20 13:30:32 +08:00
parent baaf90fc47
commit 4b35736f73
37 changed files with 556 additions and 118 deletions
@@ -1,11 +1,15 @@
package handler
import (
"database/sql"
"fmt"
"net/http"
"strings"
"time"
"github.com/gin-gonic/gin"
_ "github.com/lib/pq"
"golang.org/x/crypto/bcrypt"
"github.com/yourname/cyrene-ai/gateway/internal/config"
)
@@ -13,11 +17,12 @@ import (
// AuthHandler 认证处理器
type AuthHandler struct {
cfg *config.Config
db *sql.DB
}
// NewAuthHandler 创建认证处理器
func NewAuthHandler(cfg *config.Config) *AuthHandler {
return &AuthHandler{cfg: cfg}
func NewAuthHandler(cfg *config.Config, db *sql.DB) *AuthHandler {
return &AuthHandler{cfg: cfg, db: db}
}
// Register 用户注册 (需要邮箱验证码、昵称必填)
@@ -96,7 +101,16 @@ func (h *AuthHandler) Login(c *gin.Context) {
}
userID = "admin_" + req.Username
} else {
// MVP阶段:普通用户登录 (简化逻辑,后续需要验证密码哈希)
// 普通用户登录:从数据库查询密码哈希并验证
authenticated, err := h.verifyUserPassword(req.Username, req.Password)
if err != nil {
c.JSON(http.StatusInternalServerError, gin.H{"error": "服务器内部错误"})
return
}
if !authenticated {
c.JSON(http.StatusUnauthorized, gin.H{"error": "用户名或密码错误"})
return
}
userID = "user_" + req.Username
}
@@ -113,6 +127,44 @@ func (h *AuthHandler) Login(c *gin.Context) {
})
}
// verifyUserPassword 验证普通用户的密码
// 从数据库查询用户的密码哈希并与输入密码比对
// 如果用户不存在,返回 (false, nil);如果密码匹配,返回 (true, nil)
func (h *AuthHandler) verifyUserPassword(username, password string) (bool, error) {
if h.db == nil {
// 数据库不可用时回退到简单验证(开发阶段兼容)
// 仅允许固定测试密码,不允许空密码登录
return password == "test123", nil
}
var storedHash string
err := h.db.QueryRow(
"SELECT password_hash FROM users WHERE username = $1",
username,
).Scan(&storedHash)
if err == sql.ErrNoRows {
// 用户不存在
return false, nil
}
if err != nil {
return false, fmt.Errorf("查询用户失败: %w", err)
}
// 使用 bcrypt 验证密码哈希
// 如果存储的是明文密码(向后兼容),则直接比对
if strings.HasPrefix(storedHash, "$2a$") || strings.HasPrefix(storedHash, "$2b$") || strings.HasPrefix(storedHash, "$2y$") {
// bcrypt 哈希
if err := bcrypt.CompareHashAndPassword([]byte(storedHash), []byte(password)); err != nil {
return false, nil
}
return true, nil
}
// 明文密码向后兼容(开发阶段)
return password == storedHash, nil
}
// RefreshToken 刷新令牌
func (h *AuthHandler) RefreshToken(c *gin.Context) {
authHeader := c.GetHeader("Authorization")