mirror of
https://github.com/skyle1995/NetworkAuth.git
synced 2026-05-25 02:24:05 +08:00
New administrator authentication method
New configuration generation scheme
This commit is contained in:
@@ -48,7 +48,7 @@ func LoginPageHandler(w http.ResponseWriter, r *http.Request) {
|
||||
}
|
||||
data := utils.GetDefaultTemplateData()
|
||||
data["CSRFToken"] = token
|
||||
|
||||
|
||||
// 合并额外数据
|
||||
for key, value := range extraData {
|
||||
data[key] = value
|
||||
@@ -98,25 +98,56 @@ func LoginHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
var user models.User
|
||||
dbErr := db.Where("username = ?", body.Username).First(&user).Error
|
||||
if dbErr != nil {
|
||||
// 通过前缀匹配一次性获取所有管理员相关设置
|
||||
var adminSettings []models.Settings
|
||||
if err = db.Where("name LIKE ?", "admin_%").Find(&adminSettings).Error; err != nil {
|
||||
utils.JsonResponse(w, http.StatusUnauthorized, false, "用户不存在或密码错误", nil)
|
||||
return
|
||||
}
|
||||
if user.Role != 0 {
|
||||
utils.JsonResponse(w, http.StatusForbidden, false, "非管理员账号不可登录后台", nil)
|
||||
|
||||
// 将设置转换为map便于查找
|
||||
settingsMap := make(map[string]string)
|
||||
for _, setting := range adminSettings {
|
||||
settingsMap[setting.Name] = setting.Value
|
||||
}
|
||||
|
||||
// 检查必要的设置是否存在
|
||||
adminUsername, hasUsername := settingsMap["admin_username"]
|
||||
adminPassword, hasPassword := settingsMap["admin_password"]
|
||||
adminPasswordSalt, hasSalt := settingsMap["admin_password_salt"]
|
||||
|
||||
if !hasUsername || !hasPassword || !hasSalt {
|
||||
utils.JsonResponse(w, http.StatusUnauthorized, false, "用户不存在或密码错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证用户名
|
||||
if body.Username != adminUsername {
|
||||
utils.JsonResponse(w, http.StatusUnauthorized, false, "用户不存在或密码错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证密码为空的情况(首次登录需要初始化)
|
||||
if adminPassword == "" || adminPasswordSalt == "" {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "管理员账号未初始化,请联系系统管理员", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 使用盐值验证密码
|
||||
if !utils.VerifyPasswordWithSalt(body.Password, user.PasswordSalt, user.Password) {
|
||||
if !utils.VerifyPasswordWithSalt(body.Password, adminPasswordSalt, adminPassword) {
|
||||
utils.JsonResponse(w, http.StatusUnauthorized, false, "用户不存在或密码错误", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 创建虚拟用户对象用于生成JWT令牌
|
||||
adminUser := models.User{
|
||||
Username: adminUsername,
|
||||
Password: adminPassword,
|
||||
PasswordSalt: adminPasswordSalt,
|
||||
}
|
||||
|
||||
// 生成JWT令牌
|
||||
token, err := generateJWTToken(user)
|
||||
token, err := generateJWTTokenForAdmin(adminUser)
|
||||
if err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "生成令牌失败", nil)
|
||||
return
|
||||
@@ -159,32 +190,30 @@ var jwtSecret = []byte(viper.GetString("security.jwt_secret"))
|
||||
|
||||
// JWTClaims JWT载荷结构
|
||||
type JWTClaims struct {
|
||||
UserUUID string `json:"user_uuid"`
|
||||
Username string `json:"username"`
|
||||
Role int `json:"role"`
|
||||
IsAdmin bool `json:"is_admin"` // 是否为管理员
|
||||
PasswordHash string `json:"password_hash"` // 密码哈希摘要,用于验证密码是否被修改
|
||||
jwt.RegisteredClaims
|
||||
}
|
||||
|
||||
// generateJWTToken 生成JWT令牌
|
||||
// - 包含用户ID、用户名、角色信息
|
||||
// generateJWTTokenForAdmin 生成管理员JWT令牌
|
||||
// - 包含管理员UUID、用户名信息
|
||||
// - 设置24小时过期时间
|
||||
// - 使用HMAC-SHA256签名
|
||||
func generateJWTToken(user models.User) (string, error) {
|
||||
func generateJWTTokenForAdmin(adminUser models.User) (string, error) {
|
||||
// 生成密码哈希摘要(使用SHA256)
|
||||
passwordHashDigest := utils.GenerateSHA256Hash(user.Password)
|
||||
|
||||
passwordHashDigest := utils.GenerateSHA256Hash(adminUser.Password)
|
||||
|
||||
claims := JWTClaims{
|
||||
UserUUID: user.UUID,
|
||||
Username: user.Username,
|
||||
Role: user.Role,
|
||||
Username: adminUser.Username,
|
||||
IsAdmin: true, // 管理员
|
||||
PasswordHash: passwordHashDigest, // 包含密码哈希摘要
|
||||
RegisteredClaims: jwt.RegisteredClaims{
|
||||
ExpiresAt: jwt.NewNumericDate(time.Now().Add(24 * time.Hour)),
|
||||
IssuedAt: jwt.NewNumericDate(time.Now()),
|
||||
NotBefore: jwt.NewNumericDate(time.Now()),
|
||||
Issuer: "凌动技术",
|
||||
Subject: user.UUID,
|
||||
Subject: adminUser.Username,
|
||||
},
|
||||
}
|
||||
|
||||
@@ -230,39 +259,16 @@ func IsAdminAuthenticated(r *http.Request) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证用户角色(只允许管理员角色=0)
|
||||
if claims.Role != 0 {
|
||||
// 验证用户角色(只允许管理员)
|
||||
if !claims.IsAdmin {
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证用户是否仍然存在于数据库中
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if dbErr := db.Where("uuid = ? AND role = 0", claims.UserUUID).First(&user).Error; dbErr != nil {
|
||||
// 记录安全事件:用户不存在但持有有效JWT令牌
|
||||
fmt.Printf("[SECURITY WARNING] Invalid JWT token detected - User not found: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证用户名是否匹配(防止用户名被修改后仍使用旧令牌)
|
||||
if user.Username != claims.Username {
|
||||
// 记录安全事件:用户名不匹配
|
||||
fmt.Printf("[SECURITY WARNING] Username mismatch detected - Token username=%s, DB username=%s, UUID=%s, IP=%s\n",
|
||||
claims.Username, user.Username, claims.UserUUID, r.RemoteAddr)
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证密码哈希是否匹配(防止密码被修改后仍使用旧令牌)
|
||||
currentPasswordHash := utils.GenerateSHA256Hash(user.Password)
|
||||
if claims.PasswordHash != currentPasswordHash {
|
||||
// 记录安全事件:密码哈希不匹配,可能密码已被修改
|
||||
fmt.Printf("[SECURITY WARNING] Password hash mismatch detected - Token may be invalid due to password change: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
// 对于管理员,不需要验证数据库中的用户记录,因为管理员信息存储在settings中
|
||||
// 只需要验证JWT中的信息即可
|
||||
if !claims.IsAdmin {
|
||||
fmt.Printf("[SECURITY WARNING] Invalid admin token detected - Username=%s, IP=%s\n",
|
||||
claims.Username, r.RemoteAddr)
|
||||
return false
|
||||
}
|
||||
|
||||
@@ -286,42 +292,17 @@ func IsAdminAuthenticatedWithCleanup(w http.ResponseWriter, r *http.Request) boo
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证用户角色(只允许管理员角色=0)
|
||||
if claims.Role != 0 {
|
||||
// 验证用户角色(只允许管理员)
|
||||
if !claims.IsAdmin {
|
||||
clearInvalidJWTCookie(w)
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证用户是否仍然存在于数据库中
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if dbErr := db.Where("uuid = ? AND role = 0", claims.UserUUID).First(&user).Error; dbErr != nil {
|
||||
// 记录安全事件并清理失效Cookie
|
||||
fmt.Printf("[SECURITY WARNING] Invalid JWT token detected - User not found: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
clearInvalidJWTCookie(w)
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证用户名是否匹配(防止用户名被修改后仍使用旧令牌)
|
||||
if user.Username != claims.Username {
|
||||
// 记录安全事件并清理失效Cookie
|
||||
fmt.Printf("[SECURITY WARNING] Username mismatch detected - Token username=%s, DB username=%s, UUID=%s, IP=%s\n",
|
||||
claims.Username, user.Username, claims.UserUUID, r.RemoteAddr)
|
||||
clearInvalidJWTCookie(w)
|
||||
return false
|
||||
}
|
||||
|
||||
// 验证密码哈希是否匹配(防止密码被修改后仍使用旧令牌)
|
||||
currentPasswordHash := utils.GenerateSHA256Hash(user.Password)
|
||||
if claims.PasswordHash != currentPasswordHash {
|
||||
// 记录安全事件并清理失效Cookie
|
||||
fmt.Printf("[SECURITY WARNING] Password hash mismatch detected - Token may be invalid due to password change: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
// 对于管理员,不需要验证数据库中的用户记录,因为管理员信息存储在settings中
|
||||
// 只需要验证JWT中的信息即可
|
||||
if !claims.IsAdmin {
|
||||
fmt.Printf("[SECURITY WARNING] Invalid admin token detected - Username=%s, IP=%s\n",
|
||||
claims.Username, r.RemoteAddr)
|
||||
clearInvalidJWTCookie(w)
|
||||
return false
|
||||
}
|
||||
@@ -344,39 +325,14 @@ func GetCurrentAdminUser(r *http.Request) (*JWTClaims, error) {
|
||||
return nil, fmt.Errorf("无效的会话信息")
|
||||
}
|
||||
|
||||
if claims.Role != 0 {
|
||||
if !claims.IsAdmin {
|
||||
return nil, fmt.Errorf("权限不足")
|
||||
}
|
||||
|
||||
// 验证用户是否仍然存在于数据库中
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("数据库连接失败")
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if dbErr := db.Where("uuid = ? AND role = 0", claims.UserUUID).First(&user).Error; dbErr != nil {
|
||||
// 记录安全事件:用户不存在但持有有效JWT令牌
|
||||
fmt.Printf("[SECURITY WARNING] Invalid JWT token detected in GetCurrentAdminUser - User not found: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
return nil, fmt.Errorf("用户不存在或权限已变更")
|
||||
}
|
||||
|
||||
// 验证用户名是否匹配(防止用户名被修改后仍使用旧令牌)
|
||||
if user.Username != claims.Username {
|
||||
// 记录安全事件:用户名不匹配
|
||||
fmt.Printf("[SECURITY WARNING] Username mismatch detected in GetCurrentAdminUser - Token username=%s, DB username=%s, UUID=%s, IP=%s\n",
|
||||
claims.Username, user.Username, claims.UserUUID, r.RemoteAddr)
|
||||
return nil, fmt.Errorf("用户信息已变更,请重新登录")
|
||||
}
|
||||
|
||||
// 验证密码哈希是否匹配(防止密码被修改后仍使用旧令牌)
|
||||
currentPasswordHash := utils.GenerateSHA256Hash(user.Password)
|
||||
if claims.PasswordHash != currentPasswordHash {
|
||||
// 记录安全事件:密码哈希不匹配,可能密码已被修改
|
||||
fmt.Printf("[SECURITY WARNING] Password hash mismatch detected in GetCurrentAdminUser - Token may be invalid due to password change: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
return nil, fmt.Errorf("密码已变更,请重新登录")
|
||||
// 对于管理员,不需要验证数据库中的用户记录,因为管理员信息存储在settings中
|
||||
// 只需要验证JWT中的信息即可
|
||||
if !claims.IsAdmin {
|
||||
return nil, fmt.Errorf("无效的管理员令牌")
|
||||
}
|
||||
|
||||
return claims, nil
|
||||
@@ -397,52 +353,25 @@ func GetCurrentAdminUserWithRefresh(w http.ResponseWriter, r *http.Request) (*JW
|
||||
return nil, false, fmt.Errorf("无效的会话信息")
|
||||
}
|
||||
|
||||
if claims.Role != 0 {
|
||||
if !claims.IsAdmin {
|
||||
return nil, false, fmt.Errorf("权限不足")
|
||||
}
|
||||
|
||||
// 验证用户是否仍然存在于数据库中
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
return nil, false, fmt.Errorf("数据库连接失败")
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if dbErr := db.Where("uuid = ? AND role = 0", claims.UserUUID).First(&user).Error; dbErr != nil {
|
||||
// 记录安全事件:用户不存在但持有有效JWT令牌
|
||||
fmt.Printf("[SECURITY WARNING] Invalid JWT token detected in GetCurrentAdminUserWithRefresh - User not found: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
return nil, false, fmt.Errorf("用户不存在或权限已变更")
|
||||
}
|
||||
|
||||
// 验证用户名是否匹配(防止用户名被修改后仍使用旧令牌)
|
||||
if user.Username != claims.Username {
|
||||
// 记录安全事件:用户名不匹配
|
||||
fmt.Printf("[SECURITY WARNING] Username mismatch detected in GetCurrentAdminUserWithRefresh - Token username=%s, DB username=%s, UUID=%s, IP=%s\n",
|
||||
claims.Username, user.Username, claims.UserUUID, r.RemoteAddr)
|
||||
return nil, false, fmt.Errorf("用户信息已变更,请重新登录")
|
||||
}
|
||||
|
||||
// 验证密码哈希是否匹配(防止密码被修改后仍使用旧令牌)
|
||||
currentPasswordHash := utils.GenerateSHA256Hash(user.Password)
|
||||
if claims.PasswordHash != currentPasswordHash {
|
||||
// 记录安全事件:密码哈希不匹配,可能密码已被修改
|
||||
fmt.Printf("[SECURITY WARNING] Password hash mismatch detected in GetCurrentAdminUserWithRefresh - Token may be invalid due to password change: UUID=%s, Username=%s, IP=%s\n",
|
||||
claims.UserUUID, claims.Username, r.RemoteAddr)
|
||||
return nil, false, fmt.Errorf("密码已变更,请重新登录")
|
||||
// 对于管理员,不需要验证数据库中的用户记录,因为管理员信息存储在settings中
|
||||
// 只需要验证JWT中的信息即可
|
||||
if !claims.IsAdmin {
|
||||
return nil, false, fmt.Errorf("无效的管理员令牌")
|
||||
}
|
||||
|
||||
// 检查是否需要刷新令牌(根据配置的阈值)
|
||||
refreshed := false
|
||||
refreshThreshold := time.Duration(viper.GetInt("security.jwt_refresh_threshold_hours")) * time.Hour
|
||||
if time.Until(claims.ExpiresAt.Time) < refreshThreshold {
|
||||
// 生成新的JWT令牌
|
||||
user := models.User{
|
||||
UUID: claims.UserUUID,
|
||||
// 为管理员生成新的JWT令牌
|
||||
adminUser := models.User{
|
||||
Username: claims.Username,
|
||||
Role: claims.Role,
|
||||
}
|
||||
newToken, err := generateJWTToken(user)
|
||||
newToken, err := generateJWTTokenForAdmin(adminUser)
|
||||
if err == nil {
|
||||
// 更新Cookie(使用安全配置)
|
||||
newCookie := utils.CreateSecureCookie("admin_session", newToken, utils.GetDefaultCookieMaxAge())
|
||||
@@ -468,7 +397,7 @@ func AdminAuthRequired(next http.HandlerFunc) http.HandlerFunc {
|
||||
if err != nil {
|
||||
// 自动清理失效的JWT Cookie,提升安全性和用户体验
|
||||
clearInvalidJWTCookie(w)
|
||||
|
||||
|
||||
// 中文注释:区分普通页面请求与AJAX/JSON请求
|
||||
// - 对 AJAX/JSON:直接返回 401 JSON,便于前端处理(如提示重新登录)
|
||||
// - 对普通页面:保持原有重定向到登录页
|
||||
|
||||
@@ -2,7 +2,6 @@ package admin
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"networkDev/database"
|
||||
"networkDev/models"
|
||||
@@ -16,9 +15,9 @@ func UserFragmentHandler(w http.ResponseWriter, r *http.Request) {
|
||||
utils.RenderTemplate(w, "user.html", map[string]interface{}{})
|
||||
}
|
||||
|
||||
// UserProfileQueryHandler 查询当前登录管理员的基本信息
|
||||
// - 返回 uuid/username/role/created_at 四个字段
|
||||
// - 自动刷新接近过期的JWT令牌
|
||||
// UserProfileQueryHandler 获取当前登录管理员的用户名
|
||||
// - 返回 JSON: {username}
|
||||
// - 直接从JWT获取用户名信息
|
||||
func UserProfileQueryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
if r.Method != http.MethodGet {
|
||||
http.Error(w, "Method Not Allowed", http.StatusMethodNotAllowed)
|
||||
@@ -31,24 +30,8 @@ func UserProfileQueryHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 查询用户完整信息以获取创建时间
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "数据库连接失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
var user models.User
|
||||
if dbErr := db.Where("uuid = ?", claims.UserUUID).First(&user).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusNotFound, false, "用户不存在", nil)
|
||||
return
|
||||
}
|
||||
|
||||
utils.JsonResponse(w, http.StatusOK, true, "ok", map[string]interface{}{
|
||||
"uuid": user.UUID,
|
||||
"username": user.Username,
|
||||
"role": user.Role,
|
||||
"created_at": user.CreatedAt,
|
||||
"username": claims.Username,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -98,21 +81,42 @@ func UserPasswordUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 确认是管理员
|
||||
if !claims.IsAdmin {
|
||||
utils.JsonResponse(w, http.StatusForbidden, false, "权限不足", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 获取数据库连接
|
||||
db, err := database.GetDB()
|
||||
if err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "数据库连接失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 查询当前用户
|
||||
var user models.User
|
||||
if dbErr := db.Where("uuid = ?", claims.UserUUID).First(&user).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusNotFound, false, "用户不存在", nil)
|
||||
// 通过前缀匹配一次性获取所有管理员相关设置
|
||||
var adminSettings []models.Settings
|
||||
if err = db.Where("name LIKE ?", "admin_%").Find(&adminSettings).Error; err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "获取管理员设置失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 校验旧密码(使用盐值验证)
|
||||
if !utils.VerifyPasswordWithSalt(body.OldPassword, user.PasswordSalt, user.Password) {
|
||||
// 将设置转换为map便于查找
|
||||
settingsMap := make(map[string]string)
|
||||
for _, setting := range adminSettings {
|
||||
settingsMap[setting.Name] = setting.Value
|
||||
}
|
||||
|
||||
// 检查必要的设置是否存在
|
||||
adminPassword, hasPassword := settingsMap["admin_password"]
|
||||
adminPasswordSalt, hasSalt := settingsMap["admin_password_salt"]
|
||||
if !hasPassword || !hasSalt {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "管理员密码设置不完整", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 校验旧密码
|
||||
if !utils.VerifyPasswordWithSalt(body.OldPassword, adminPasswordSalt, adminPassword) {
|
||||
utils.JsonResponse(w, http.StatusUnauthorized, false, "旧密码不正确", nil)
|
||||
return
|
||||
}
|
||||
@@ -120,41 +124,34 @@ func UserPasswordUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
// 生成新的密码盐值
|
||||
newSalt, err := utils.GenerateRandomSalt()
|
||||
if err != nil {
|
||||
// 添加详细错误日志
|
||||
fmt.Printf("生成密码盐失败: %v\n", err)
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "生成密码盐失败", nil)
|
||||
return
|
||||
}
|
||||
fmt.Printf("成功生成新盐值,长度: %d\n", len(newSalt))
|
||||
|
||||
// 使用新盐值生成密码哈希
|
||||
hash, err := utils.HashPasswordWithSalt(body.NewPassword, newSalt)
|
||||
// 生成新密码哈希
|
||||
newPasswordHash, err := utils.HashPasswordWithSalt(body.NewPassword, newSalt)
|
||||
if err != nil {
|
||||
// 添加详细错误日志
|
||||
fmt.Printf("生成密码哈希失败: %v, 密码长度: %d, 盐值长度: %d\n", err, len(body.NewPassword), len(newSalt))
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "生成密码哈希失败", nil)
|
||||
return
|
||||
}
|
||||
fmt.Printf("成功生成密码哈希,长度: %d\n", len(hash))
|
||||
|
||||
// 更新密码和盐值
|
||||
if dbErr := db.Model(&models.User{}).Where("uuid = ?", claims.UserUUID).Updates(map[string]interface{}{
|
||||
"password": hash,
|
||||
"password_salt": newSalt,
|
||||
}).Error; dbErr != nil {
|
||||
// 更新settings中的管理员密码和盐值
|
||||
if err = db.Model(&models.Settings{}).Where("name = ?", "admin_password").Update("value", newPasswordHash).Error; err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "更新密码失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 重新查询用户信息(包含新密码)
|
||||
var updatedUser models.User
|
||||
if dbErr := db.Where("uuid = ?", claims.UserUUID).First(&updatedUser).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "查询用户信息失败", nil)
|
||||
if err = db.Model(&models.Settings{}).Where("name = ?", "admin_password_salt").Update("value", newSalt).Error; err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "更新密码盐值失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 重新生成JWT令牌(包含新的密码哈希摘要)
|
||||
newToken, err := generateJWTToken(updatedUser)
|
||||
adminUser := models.User{
|
||||
Username: claims.Username,
|
||||
Password: newPasswordHash,
|
||||
PasswordSalt: newSalt,
|
||||
}
|
||||
newToken, err := generateJWTTokenForAdmin(adminUser)
|
||||
if err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "生成新令牌失败", nil)
|
||||
return
|
||||
@@ -210,19 +207,45 @@ func UserProfileUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
// 检查唯一性:排除当前用户UUID
|
||||
var cnt int64
|
||||
if dbErr := db.Model(&models.User{}).Where("username = ? AND uuid <> ?", username, claims.UserUUID).Count(&cnt).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "检查用户名唯一性失败", nil)
|
||||
return
|
||||
}
|
||||
if cnt > 0 {
|
||||
utils.JsonResponse(w, http.StatusBadRequest, false, "用户名已存在,请更换", nil)
|
||||
// 确认当前用户是管理员
|
||||
if !claims.IsAdmin {
|
||||
utils.JsonResponse(w, http.StatusForbidden, false, "权限不足", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 如果未变化则直接返回成功(无需校验旧密码)
|
||||
if strings.EqualFold(username, claims.Username) {
|
||||
// 获取所有管理员相关设置
|
||||
var adminSettings []models.Settings
|
||||
if dbErr := db.Where("name LIKE ?", "admin_%").Find(&adminSettings).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "获取管理员设置失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 转换为map便于查找
|
||||
settingsMap := make(map[string]string)
|
||||
for _, setting := range adminSettings {
|
||||
settingsMap[setting.Name] = setting.Value
|
||||
}
|
||||
|
||||
adminUsername, exists := settingsMap["admin_username"]
|
||||
if !exists {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "管理员用户名设置不存在", nil)
|
||||
return
|
||||
}
|
||||
|
||||
adminPassword, exists := settingsMap["admin_password"]
|
||||
if !exists {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "管理员密码设置不存在", nil)
|
||||
return
|
||||
}
|
||||
|
||||
adminPasswordSalt, exists := settingsMap["admin_password_salt"]
|
||||
if !exists {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "管理员密码盐值设置不存在", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 如果用户名未变化则直接返回成功(无需校验旧密码)
|
||||
if strings.EqualFold(username, adminUsername) {
|
||||
utils.JsonResponse(w, http.StatusOK, true, "保存成功", map[string]interface{}{
|
||||
"username": username,
|
||||
})
|
||||
@@ -234,28 +257,27 @@ func UserProfileUpdateHandler(w http.ResponseWriter, r *http.Request) {
|
||||
utils.JsonResponse(w, http.StatusBadRequest, false, "修改用户名需要提供当前密码", nil)
|
||||
return
|
||||
}
|
||||
// 查询当前用户并校验旧密码
|
||||
var user models.User
|
||||
if dbErr := db.Where("uuid = ?", claims.UserUUID).First(&user).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusNotFound, false, "用户不存在", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 使用盐值验证当前密码
|
||||
if !utils.VerifyPasswordWithSalt(body.OldPassword, user.PasswordSalt, user.Password) {
|
||||
if !utils.VerifyPasswordWithSalt(body.OldPassword, adminPasswordSalt, adminPassword) {
|
||||
utils.JsonResponse(w, http.StatusUnauthorized, false, "当前密码不正确", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 执行更新
|
||||
if dbErr := db.Model(&models.User{}).Where("uuid = ?", claims.UserUUID).Update("username", username).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "更新用户名失败", nil)
|
||||
// 更新管理员用户名设置
|
||||
if dbErr := db.Model(&models.Settings{}).Where("name = ?", "admin_username").Update("value", username).Error; dbErr != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "更新管理员用户名失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 重新签发JWT并写入Cookie
|
||||
// 使用完整的用户信息(包含密码)来生成JWT令牌
|
||||
user.Username = username // 更新用户名
|
||||
token, err := generateJWTToken(user)
|
||||
// 创建虚拟用户对象用于生成JWT令牌
|
||||
adminUser := models.User{
|
||||
Username: username, // 使用新的用户名
|
||||
Password: adminPassword,
|
||||
PasswordSalt: adminPasswordSalt,
|
||||
}
|
||||
token, err := generateJWTTokenForAdmin(adminUser)
|
||||
if err != nil {
|
||||
utils.JsonResponse(w, http.StatusInternalServerError, false, "生成新令牌失败", nil)
|
||||
return
|
||||
|
||||
Reference in New Issue
Block a user