From 3293fc452a54bf704cdc9c56f9f780e18afa5aed Mon Sep 17 00:00:00 2001 From: skyle1995 Date: Tue, 31 Mar 2026 02:14:08 +0800 Subject: [PATCH] =?UTF-8?q?=E4=BF=AE=E4=BF=AE=E5=A4=8D=20=E5=9B=A0?= =?UTF-8?q?=E4=B8=BAsecure=E5=AF=BC=E8=87=B4=E7=9A=84=E7=99=BB=E5=BD=95?= =?UTF-8?q?=E5=A4=B1=E8=B4=A5=E9=97=AE=E9=A2=98=20=E4=BF=AE=E5=A4=8D=20?= =?UTF-8?q?=E5=AE=89=E8=A3=85=E6=8B=A6=E6=88=AA=E5=99=A8=E9=83=A8=E5=88=86?= =?UTF-8?q?=E6=83=85=E5=86=B5=E4=B8=8B=E5=A4=B1=E6=95=88=E7=9A=84=E9=97=AE?= =?UTF-8?q?=E9=A2=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- cmd/server.go | 38 ++++++++++++++++------------ controllers/admin/auth.go | 45 +++++++++++++++++++++++++++++----- controllers/install/install.go | 11 +++++++++ database/settings.go | 4 +-- middleware/install.go | 26 -------------------- 5 files changed, 74 insertions(+), 50 deletions(-) diff --git a/cmd/server.go b/cmd/server.go index 6ce9922..8b16c8d 100644 --- a/cmd/server.go +++ b/cmd/server.go @@ -71,24 +71,30 @@ func runServer(cmd *cobra.Command, args []string) { } if db != nil { - // 执行自动迁移(确保表结构存在) - if err := database.AutoMigrate(); err != nil { - logrus.WithError(err).Fatal("数据库自动迁移失败") - } - // 初始化默认系统设置 - if err := database.SeedDefaultSettings(); err != nil { - logrus.WithError(err).Fatal("默认系统设置初始化失败") - } + // 检查系统是否已安装 + isInstalled := services.GetSettingsService().GetString("is_installed", "0") + if isInstalled == "1" { + // 执行自动迁移(确保表结构存在) + if err := database.AutoMigrate(); err != nil { + logrus.WithError(err).Fatal("数据库自动迁移失败") + } + // 初始化默认系统设置 + if err := database.SeedDefaultSettings(); err != nil { + logrus.WithError(err).Fatal("默认系统设置初始化失败") + } - // 初始化加密管理器 - // 从数据库设置中获取加密密钥 - encryptionKey := services.GetSettingsService().GetEncryptionKey() - if err := utils.InitEncryption(encryptionKey); err != nil { - logrus.WithError(err).Fatal("加密管理器初始化失败") - } + // 初始化加密管理器 + // 从数据库设置中获取加密密钥 + encryptionKey := services.GetSettingsService().GetEncryptionKey() + if err := utils.InitEncryption(encryptionKey); err != nil { + logrus.WithError(err).Fatal("加密管理器初始化失败") + } - // 启动日志清理定时任务 - services.StartLogCleanupTask() + // 启动日志清理定时任务 + services.StartLogCleanupTask() + } else { + logrus.Info("系统尚未安装 (is_installed=0),跳过核心组件初始化") + } } else { logrus.Info("系统处于未初始化状态,跳过数据库自动迁移和设置加载") } diff --git a/controllers/admin/auth.go b/controllers/admin/auth.go index a5e76f2..1d0df5c 100644 --- a/controllers/admin/auth.go +++ b/controllers/admin/auth.go @@ -131,6 +131,7 @@ func LoginHandler(c *gin.Context) { "avatar": user.Avatar, "nickname": user.Nickname, "username": user.Username, + "token": token, }) } @@ -308,9 +309,21 @@ func parseJWTToken(tokenString string) (*JWTClaims, error) { return nil, fmt.Errorf("invalid token") } -// getJWTCookie 获取JWT cookie的通用函数 +// getJWTCookie 获取JWT cookie的通用函数,支持从Cookie或Authorization Header中获取 func getJWTCookie(c *gin.Context) (string, error) { - return c.Cookie("admin_session") + cookie, err := c.Cookie("admin_session") + if err == nil && cookie != "" { + return cookie, nil + } + + // 如果Cookie中没有,尝试从Authorization Header中获取 (兼容前端在非HTTPS环境下无法设置Secure Cookie的情况) + authHeader := c.GetHeader("Authorization") + if authHeader != "" && strings.HasPrefix(authHeader, "Bearer ") { + token := strings.TrimPrefix(authHeader, "Bearer ") + return token, nil + } + + return "", fmt.Errorf("未找到会话信息") } // validateAdminPasswordHash 验证管理员密码哈希的通用函数 @@ -367,13 +380,23 @@ func IsAdminAuthenticated(c *gin.Context) bool { // IsAdminAuthenticatedHttp 判断管理员是否已认证(HTTP兼容版本) // 保留此方法以兼容未迁移的 Handler func IsAdminAuthenticatedHttp(r *http.Request) bool { + token := "" cookie, err := r.Cookie("admin_session") - if err != nil || cookie.Value == "" { + if err == nil && cookie.Value != "" { + token = cookie.Value + } else { + authHeader := r.Header.Get("Authorization") + if authHeader != "" && strings.HasPrefix(authHeader, "Bearer ") { + token = strings.TrimPrefix(authHeader, "Bearer ") + } + } + + if token == "" { return false } // 解析并验证JWT令牌 - claims, err := parseJWTToken(cookie.Value) + claims, err := parseJWTToken(token) if err != nil { return false } @@ -431,12 +454,22 @@ func IsAdminAuthenticatedWithCleanup(c *gin.Context) bool { // GetCurrentAdminUser 获取当前登录的管理员用户信息 (HTTP 兼容版) func GetCurrentAdminUser(r *http.Request) (*JWTClaims, error) { + token := "" cookie, err := r.Cookie("admin_session") - if err != nil { + if err == nil && cookie.Value != "" { + token = cookie.Value + } else { + authHeader := r.Header.Get("Authorization") + if authHeader != "" && strings.HasPrefix(authHeader, "Bearer ") { + token = strings.TrimPrefix(authHeader, "Bearer ") + } + } + + if token == "" { return nil, fmt.Errorf("未找到会话信息") } - claims, err := parseJWTToken(cookie.Value) + claims, err := parseJWTToken(token) if err != nil { return nil, fmt.Errorf("无效的会话信息") } diff --git a/controllers/install/install.go b/controllers/install/install.go index 34a0035..9edb812 100644 --- a/controllers/install/install.go +++ b/controllers/install/install.go @@ -11,6 +11,7 @@ import ( "strings" "github.com/gin-gonic/gin" + "github.com/sirupsen/logrus" "gorm.io/driver/mysql" "gorm.io/gorm" ) @@ -165,5 +166,15 @@ func InstallSubmitHandler(c *gin.Context) { // 5. 更新内存缓存 services.ResetSettingsService() + // 6. 动态初始化核心组件 + // 在系统安装完成后,执行本来在 server.go 中需要已安装才能执行的初始化逻辑 + encryptionKey := services.GetSettingsService().GetEncryptionKey() + if err := utils.InitEncryption(encryptionKey); err != nil { + logrus.WithError(err).Error("安装完成后加密管理器初始化失败") + } + + // 启动日志清理定时任务 + services.StartLogCleanupTask() + c.JSON(http.StatusOK, gin.H{"code": 0, "msg": "安装成功"}) } diff --git a/database/settings.go b/database/settings.go index 07823d3..60c045f 100644 --- a/database/settings.go +++ b/database/settings.go @@ -116,8 +116,8 @@ func SeedDefaultSettings() error { defaultSettings = append(defaultSettings, []models.Settings{ { Name: "cookie_secure", - Value: "true", - Description: "Cookie Secure属性(是否只在HTTPS下发送)", + Value: "false", + Description: "是否启用安全Cookie(仅HTTPS),开启后HTTP访问可能导致登录失败", }, { Name: "cookie_same_site", diff --git a/middleware/install.go b/middleware/install.go index 6cb4cff..ab8ccb1 100644 --- a/middleware/install.go +++ b/middleware/install.go @@ -3,10 +3,8 @@ package middleware import ( "NetworkAuth/services" "net/http" - "os" "github.com/gin-gonic/gin" - "github.com/spf13/viper" ) // InstallCheckMiddleware 检查系统是否已安装 @@ -20,30 +18,6 @@ func InstallCheckMiddleware() gin.HandlerFunc { isInstalledStr := services.GetSettingsService().GetString("is_installed", "0") isInstalled := isInstalledStr == "1" - // 如果设置服务没获取到(因为未连接数据库),再结合文件判断 - if !isInstalled { - // 检查数据库文件是否存在(如果是 sqlite) - dbType := viper.GetString("database.type") - switch dbType { - case "sqlite": - dbPath := viper.GetString("database.sqlite.path") - if dbPath == "" { - dbPath = "./database.db" - } - if _, err := os.Stat(dbPath); os.IsNotExist(err) { - isInstalled = false - } else { - isInstalled = true - } - case "mysql": - // 如果是 mysql 且配置了 database,我们认为是已安装 - dbName := viper.GetString("database.mysql.database") - if dbName != "" { - isInstalled = true - } - } - } - // 如果未安装且是 API 请求但不是安装接口,则返回 403 JSON // 如果是前端页面请求,不在此处拦截,交由前端 Vue Router 拦截并跳转至安装页 if !isInstalled && !isInstallRoute && len(path) >= 4 && path[:4] == "/api" {