2026-03-18 21:51:17 +08:00
|
|
|
|
package admin
|
|
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"NetworkAuth/database"
|
|
|
|
|
|
"NetworkAuth/models"
|
|
|
|
|
|
"NetworkAuth/services"
|
|
|
|
|
|
"NetworkAuth/utils"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"strings"
|
|
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
"gorm.io/gorm"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// ProfileFragmentHandler 个人资料片段渲染
|
|
|
|
|
|
// - 渲染个人资料与修改密码表单
|
|
|
|
|
|
func ProfileFragmentHandler(c *gin.Context) {
|
|
|
|
|
|
c.HTML(http.StatusOK, "profile.html", map[string]interface{}{})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ProfileInfoHandler 查询当前登录管理员的基本信息
|
|
|
|
|
|
// - 返回 username 字段
|
|
|
|
|
|
func ProfileInfoHandler(c *gin.Context) {
|
|
|
|
|
|
_, _, err := GetCurrentAdminUserWithRefresh(c)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusUnauthorized, gin.H{
|
|
|
|
|
|
"code": 1,
|
|
|
|
|
|
"msg": "未登录或会话已过期",
|
|
|
|
|
|
"data": nil,
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取最新设置
|
|
|
|
|
|
settingsService := services.GetSettingsService()
|
|
|
|
|
|
username := settingsService.GetString("admin_username", "admin")
|
|
|
|
|
|
|
|
|
|
|
|
authBaseController.HandleSuccess(c, "ok", map[string]interface{}{
|
|
|
|
|
|
"username": username,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ProfilePasswordUpdateHandler 修改当前登录管理员的密码
|
|
|
|
|
|
// - 接收 JSON: {old_password, new_password, confirm_password}
|
|
|
|
|
|
// - 校验旧密码正确性、新密码与确认一致性
|
|
|
|
|
|
// - 成功后更新密码哈希
|
|
|
|
|
|
func ProfilePasswordUpdateHandler(c *gin.Context) {
|
|
|
|
|
|
_, _, err := GetCurrentAdminUserWithRefresh(c)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusUnauthorized, gin.H{
|
|
|
|
|
|
"code": 1,
|
|
|
|
|
|
"msg": "未登录或会话已过期",
|
|
|
|
|
|
"data": nil,
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var body struct {
|
|
|
|
|
|
OldPassword string `json:"old_password"`
|
|
|
|
|
|
NewPassword string `json:"new_password"`
|
|
|
|
|
|
ConfirmPassword string `json:"confirm_password"`
|
|
|
|
|
|
}
|
|
|
|
|
|
if !authBaseController.BindJSON(c, &body) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 基础校验
|
|
|
|
|
|
if body.OldPassword == "" || body.NewPassword == "" || body.ConfirmPassword == "" {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "旧密码/新密码/确认密码均不能为空")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(body.NewPassword) < 6 {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "新密码长度不能少于6位")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if body.NewPassword != body.ConfirmPassword {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "两次输入的新密码不一致")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if body.NewPassword == body.OldPassword {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "新密码不能与旧密码相同")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前密码设置
|
|
|
|
|
|
settingsService := services.GetSettingsService()
|
|
|
|
|
|
currentHash := settingsService.GetString("admin_password", "")
|
|
|
|
|
|
currentSalt := settingsService.GetString("admin_password_salt", "")
|
|
|
|
|
|
|
|
|
|
|
|
// 校验旧密码
|
|
|
|
|
|
if !utils.VerifyPasswordWithSalt(body.OldPassword, currentSalt, currentHash) {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "旧密码不正确")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 生成新盐值和哈希
|
|
|
|
|
|
newSalt, err := utils.GenerateRandomSalt()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
authBaseController.HandleInternalError(c, "生成盐值失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
newHash, err := utils.HashPasswordWithSalt(body.NewPassword, newSalt)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
authBaseController.HandleInternalError(c, "生成密码哈希失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据库
|
|
|
|
|
|
db, ok := authBaseController.GetDB(c)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新 admin_password
|
|
|
|
|
|
if err := updateSetting(db, "admin_password", newHash); err != nil {
|
|
|
|
|
|
authBaseController.HandleInternalError(c, "更新密码失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新 admin_password_salt
|
|
|
|
|
|
if err := updateSetting(db, "admin_password_salt", newSalt); err != nil {
|
|
|
|
|
|
authBaseController.HandleInternalError(c, "更新盐值失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 刷新缓存
|
|
|
|
|
|
settingsService.RefreshCache()
|
|
|
|
|
|
|
|
|
|
|
|
// 清除相关缓存键
|
|
|
|
|
|
_ = utils.RedisDel(c.Request.Context(), "setting:admin_password", "setting:admin_password_salt")
|
|
|
|
|
|
|
|
|
|
|
|
// 获取当前用户名
|
|
|
|
|
|
currentUsername := settingsService.GetString("admin_username", "admin")
|
|
|
|
|
|
|
|
|
|
|
|
// 重新签发JWT并写入Cookie
|
|
|
|
|
|
token, err := generateJWTTokenForAdmin(currentUsername, newHash)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
authBaseController.HandleInternalError(c, "生成新令牌失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
secure, sameSite, domain, maxAge := settingsService.GetCookieConfig()
|
|
|
|
|
|
cookie := utils.CreateSecureCookie("admin_session", token, maxAge, domain, secure, sameSite)
|
|
|
|
|
|
c.SetCookie(cookie.Name, cookie.Value, cookie.MaxAge, cookie.Path, cookie.Domain, cookie.Secure, cookie.HttpOnly)
|
|
|
|
|
|
|
2026-03-19 05:11:44 +08:00
|
|
|
|
// 记录操作日志
|
|
|
|
|
|
operator := c.GetString("admin_username")
|
|
|
|
|
|
if operator == "" {
|
|
|
|
|
|
operator = "unknown"
|
|
|
|
|
|
}
|
|
|
|
|
|
operatorUUID := c.GetString("admin_uuid")
|
|
|
|
|
|
|
|
|
|
|
|
services.RecordOperationLog(
|
|
|
|
|
|
"修改密码",
|
|
|
|
|
|
operator,
|
|
|
|
|
|
operatorUUID,
|
|
|
|
|
|
"管理员修改了登录密码",
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-03-18 21:51:17 +08:00
|
|
|
|
authBaseController.HandleSuccess(c, "密码修改成功", nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ProfileUpdateHandler 修改当前登录管理员的用户名
|
|
|
|
|
|
// - 接收 JSON: {username}
|
|
|
|
|
|
// - 校验用户名非空、长度
|
|
|
|
|
|
// - 更新数据库后重新签发JWT并写入 Cookie,保持前端展示的一致性
|
|
|
|
|
|
func ProfileUpdateHandler(c *gin.Context) {
|
|
|
|
|
|
_, _, err := GetCurrentAdminUserWithRefresh(c)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.JSON(http.StatusUnauthorized, gin.H{
|
|
|
|
|
|
"code": 1,
|
|
|
|
|
|
"msg": "未登录或会话已过期",
|
|
|
|
|
|
"data": nil,
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var body struct {
|
|
|
|
|
|
Username string `json:"username"`
|
|
|
|
|
|
OldPassword string `json:"old_password"`
|
|
|
|
|
|
}
|
|
|
|
|
|
if !authBaseController.BindJSON(c, &body) {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
username := strings.TrimSpace(body.Username)
|
|
|
|
|
|
if username == "" {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "用户名不能为空")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if len(username) > 64 {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "用户名长度不能超过64字符")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
settingsService := services.GetSettingsService()
|
|
|
|
|
|
currentUsername := settingsService.GetString("admin_username", "admin")
|
|
|
|
|
|
|
|
|
|
|
|
// 如果未变化则直接返回成功
|
|
|
|
|
|
if strings.EqualFold(username, currentUsername) {
|
|
|
|
|
|
authBaseController.HandleSuccess(c, "保存成功", map[string]interface{}{
|
|
|
|
|
|
"username": username,
|
|
|
|
|
|
})
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 修改用户名需要进行当前密码校验
|
|
|
|
|
|
if strings.TrimSpace(body.OldPassword) == "" {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "修改用户名需要提供当前密码")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
currentHash := settingsService.GetString("admin_password", "")
|
|
|
|
|
|
currentSalt := settingsService.GetString("admin_password_salt", "")
|
|
|
|
|
|
|
|
|
|
|
|
// 校验旧密码
|
|
|
|
|
|
if !utils.VerifyPasswordWithSalt(body.OldPassword, currentSalt, currentHash) {
|
|
|
|
|
|
authBaseController.HandleValidationError(c, "当前密码不正确")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 更新数据库
|
|
|
|
|
|
db, ok := authBaseController.GetDB(c)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if err := updateSetting(db, "admin_username", username); err != nil {
|
|
|
|
|
|
authBaseController.HandleInternalError(c, "更新用户名失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2026-03-19 05:11:44 +08:00
|
|
|
|
// 刷新缓存
|
|
|
|
|
|
settingsService.RefreshCache()
|
|
|
|
|
|
_ = utils.RedisDel(c.Request.Context(), "setting:admin_username")
|
|
|
|
|
|
|
|
|
|
|
|
// 记录操作日志
|
|
|
|
|
|
operator := c.GetString("admin_username")
|
|
|
|
|
|
if operator == "" {
|
|
|
|
|
|
operator = "unknown"
|
|
|
|
|
|
}
|
|
|
|
|
|
operatorUUID := c.GetString("admin_uuid")
|
|
|
|
|
|
|
|
|
|
|
|
services.RecordOperationLog(
|
|
|
|
|
|
"修改账号",
|
|
|
|
|
|
operator,
|
|
|
|
|
|
operatorUUID,
|
|
|
|
|
|
"管理员修改了用户名为: "+username,
|
|
|
|
|
|
)
|
|
|
|
|
|
|
2026-03-18 21:51:17 +08:00
|
|
|
|
// 重新签发JWT并写入Cookie
|
|
|
|
|
|
token, err := generateJWTTokenForAdmin(username, currentHash)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
authBaseController.HandleInternalError(c, "生成新令牌失败", err)
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
secure, sameSite, domain, maxAge := settingsService.GetCookieConfig()
|
|
|
|
|
|
cookie := utils.CreateSecureCookie("admin_session", token, maxAge, domain, secure, sameSite)
|
|
|
|
|
|
c.SetCookie(cookie.Name, cookie.Value, cookie.MaxAge, cookie.Path, cookie.Domain, cookie.Secure, cookie.HttpOnly)
|
|
|
|
|
|
|
|
|
|
|
|
authBaseController.HandleSuccess(c, "用户名修改成功", map[string]interface{}{
|
|
|
|
|
|
"username": username,
|
|
|
|
|
|
})
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 辅助函数:更新设置项
|
|
|
|
|
|
func updateSetting(db interface{}, name, value string) error {
|
|
|
|
|
|
// 类型断言
|
|
|
|
|
|
gormDB, ok := db.(*gorm.DB)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
// 如果断言失败,尝试重新获取连接
|
|
|
|
|
|
var err error
|
|
|
|
|
|
gormDB, err = database.GetDB()
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
return err
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var setting models.Settings
|
|
|
|
|
|
if err := gormDB.Where("name = ?", name).First(&setting).Error; err != nil {
|
|
|
|
|
|
// 如果不存在则创建
|
|
|
|
|
|
setting = models.Settings{Name: name, Value: value}
|
|
|
|
|
|
return gormDB.Create(&setting).Error
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 存在则更新
|
|
|
|
|
|
return gormDB.Model(&setting).Update("value", value).Error
|
|
|
|
|
|
}
|