2024-01-10 16:05:15 +08:00
|
|
|
|
/*
|
|
|
|
|
|
@Time : 2020/6/28 21:40
|
|
|
|
|
|
@Author : xuyiqing
|
|
|
|
|
|
@File : users.py
|
|
|
|
|
|
*/
|
|
|
|
|
|
|
2024-07-04 19:15:44 +08:00
|
|
|
|
package controllers
|
2024-01-10 16:05:15 +08:00
|
|
|
|
|
|
|
|
|
|
import (
|
|
|
|
|
|
"fmt"
|
|
|
|
|
|
"go_blog/models"
|
|
|
|
|
|
"go_blog/pkg/jwt"
|
|
|
|
|
|
"go_blog/pkg/util"
|
|
|
|
|
|
"go_blog/serializers"
|
2025-06-09 17:59:19 +08:00
|
|
|
|
"go_blog/themes"
|
|
|
|
|
|
"html/template"
|
|
|
|
|
|
"net/http"
|
|
|
|
|
|
"time"
|
2024-01-10 16:05:15 +08:00
|
|
|
|
|
|
|
|
|
|
"github.com/gin-gonic/gin"
|
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
// 登录
|
|
|
|
|
|
func UsersLoginHandler(ctx *gin.Context) {
|
|
|
|
|
|
response := Response{Ctx: ctx}
|
|
|
|
|
|
var loginUser serializers.Login
|
|
|
|
|
|
if err := ctx.ShouldBind(&loginUser); err != nil {
|
2025-05-27 19:24:07 +08:00
|
|
|
|
response.BadRequest("请求参数错误: " + err.Error())
|
2025-05-27 19:01:05 +08:00
|
|
|
|
return
|
2024-01-10 16:05:15 +08:00
|
|
|
|
}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
2025-05-27 19:24:07 +08:00
|
|
|
|
// 修正:通过数据库查询获取用户记录(原逻辑直接使用 loginUser.GetUser() 未查询数据库)
|
|
|
|
|
|
user := &models.Account{Username: loginUser.Username}
|
|
|
|
|
|
if err := models.DB.Where("username = ?", user.Username).First(user).Error; err != nil {
|
|
|
|
|
|
response.BadRequest("用户不存在")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
2025-05-27 19:24:07 +08:00
|
|
|
|
// 修正:使用 IsPasswordEqual 验证密码
|
|
|
|
|
|
if !user.IsPasswordEqual(loginUser.Password) {
|
2024-01-10 16:05:15 +08:00
|
|
|
|
response.BadRequest("密码错误")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
2025-05-27 19:01:05 +08:00
|
|
|
|
token, err := jwt.GenerateToken(user)
|
2024-01-10 16:05:15 +08:00
|
|
|
|
if err != nil {
|
2025-05-27 19:24:07 +08:00
|
|
|
|
response.ServerError("生成令牌失败: " + err.Error())
|
|
|
|
|
|
return
|
2024-01-10 16:05:15 +08:00
|
|
|
|
}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加 Authorization 响应头(格式与 auth.go 的 AuthRequired 方法一致)
|
|
|
|
|
|
ctx.Header("Authorization", "Bearer " + token)
|
|
|
|
|
|
|
|
|
|
|
|
// 表单提交场景:设置Cookie并跳转(需配合前端使用Cookie存储JWT)
|
|
|
|
|
|
if ctx.ContentType() == "application/x-www-form-urlencoded" {
|
|
|
|
|
|
http.SetCookie(ctx.Writer, &http.Cookie{
|
|
|
|
|
|
Name: "token",
|
|
|
|
|
|
Value: token,
|
|
|
|
|
|
Path: "/",
|
|
|
|
|
|
Expires: time.Now().Add(24 * time.Hour),
|
|
|
|
|
|
HttpOnly: true, // 防止XSS
|
|
|
|
|
|
})
|
|
|
|
|
|
ctx.Redirect(http.StatusFound, "/admin/index")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// API请求场景:返回JSON
|
2024-01-10 16:05:15 +08:00
|
|
|
|
data, _ := util.PrecisionLost(user)
|
|
|
|
|
|
data["token"] = token
|
|
|
|
|
|
response.Response(data, nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 注册
|
|
|
|
|
|
func UsersRegisterHandler(ctx *gin.Context) {
|
|
|
|
|
|
response := Response{Ctx: ctx}
|
|
|
|
|
|
var registerUser serializers.Login
|
|
|
|
|
|
if err := ctx.ShouldBind(®isterUser); err != nil {
|
2025-05-27 19:01:05 +08:00
|
|
|
|
response.BadRequest("请求参数错误: " + err.Error()) // 替换 panic 为错误响应
|
|
|
|
|
|
return
|
2024-01-10 16:05:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
user := registerUser.GetUser()
|
|
|
|
|
|
status := user.CheckDuplicateUsername()
|
|
|
|
|
|
if status == false {
|
|
|
|
|
|
response.BadRequest("用户名已存在")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := user.SetPassword(user.Password); err != nil {
|
|
|
|
|
|
panic(err)
|
|
|
|
|
|
}
|
|
|
|
|
|
user.IsActive = true
|
|
|
|
|
|
models.DB.Create(&user)
|
|
|
|
|
|
response.Response(nil, nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 修改用户信息
|
|
|
|
|
|
func UsersSetInfoHandler(ctx *gin.Context) {
|
|
|
|
|
|
response := Response{Ctx: ctx}
|
|
|
|
|
|
jsonData, err := util.GetBodyData(ctx)
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
response.BadRequest("参数解析失败")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
fmt.Println(jsonData)
|
|
|
|
|
|
if jsonData == nil {
|
|
|
|
|
|
response.BadRequest("获取不到参数")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-05-27 19:01:05 +08:00
|
|
|
|
// 从上下文中获取用户(假设 JWT 中间件已将用户存入 "user" 键)
|
|
|
|
|
|
user, exists := ctx.Get("user")
|
|
|
|
|
|
if !exists {
|
|
|
|
|
|
response.Unauthenticated("未登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
currentUser, ok := user.(*models.Account) // 明确类型为 models.Account
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
response.ServerError("用户类型错误")
|
2024-01-10 16:05:15 +08:00
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
2025-05-27 19:01:05 +08:00
|
|
|
|
models.DB.Model(currentUser).Updates(jsonData)
|
|
|
|
|
|
response.Response(currentUser, nil)
|
2024-01-10 16:05:15 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 修改密码
|
|
|
|
|
|
func UsersSetPwdHandler(ctx *gin.Context) {
|
|
|
|
|
|
response := Response{Ctx: ctx}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
2025-05-27 19:24:07 +08:00
|
|
|
|
// 从上下文中获取用户(替换原 jwt.AssertUser 调用)
|
2025-06-09 17:59:19 +08:00
|
|
|
|
ctxuser, exists := ctx.Get("user")
|
2025-05-27 19:24:07 +08:00
|
|
|
|
if !exists {
|
|
|
|
|
|
response.Unauthenticated("未验证登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
currentUser, ok := ctxuser.(*models.Account)
|
2025-05-27 19:24:07 +08:00
|
|
|
|
if !ok {
|
|
|
|
|
|
response.ServerError("用户类型错误")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
2024-01-10 16:05:15 +08:00
|
|
|
|
if currentUser == nil {
|
|
|
|
|
|
response.Unauthenticated("未验证登录")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
var user serializers.Account
|
|
|
|
|
|
if err := ctx.ShouldBindJSON(&user); err != nil {
|
|
|
|
|
|
response.BadRequest(err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if user.Username != currentUser.Username {
|
|
|
|
|
|
response.BadRequest("当前登录用户用户名与输入用户名不符")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if user.OldPwd == user.NewPwd {
|
|
|
|
|
|
response.BadRequest("两次输入的密码相同")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if isPwd := currentUser.IsPasswordEqual(user.OldPwd); !isPwd {
|
|
|
|
|
|
response.BadRequest("原密码错误")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
if err := currentUser.SetPassword(user.NewPwd); err != nil {
|
|
|
|
|
|
response.BadRequest(err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
models.DB.Save(¤tUser)
|
|
|
|
|
|
response.Response(nil, nil)
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func UsersListHandler(ctx *gin.Context) {
|
|
|
|
|
|
response := Response{Ctx: ctx}
|
|
|
|
|
|
var pager serializers.Pager
|
|
|
|
|
|
pager.InitPager(ctx)
|
|
|
|
|
|
var users []models.Account
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
2025-05-27 19:01:05 +08:00
|
|
|
|
// 先查询总记录数
|
|
|
|
|
|
var totalCount int64
|
|
|
|
|
|
models.DB.Model(&models.Account{}).Count(&totalCount)
|
|
|
|
|
|
pager.Total = int(totalCount) // 正确设置总数
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
2025-05-27 19:01:05 +08:00
|
|
|
|
// 分页查询
|
2025-06-09 17:59:19 +08:00
|
|
|
|
// 由于 pager.OffSet 是 int 类型,直接使用该变量,无需调用函数
|
|
|
|
|
|
models.DB.Offset(pager.OffSet).Limit(pager.PageSize).Find(&users)
|
2024-01-10 16:05:15 +08:00
|
|
|
|
pager.GetPager()
|
|
|
|
|
|
response.Response(users, pager)
|
|
|
|
|
|
}
|
2025-06-09 17:59:19 +08:00
|
|
|
|
|
|
|
|
|
|
// ShowLoginPage 渲染登录页面
|
|
|
|
|
|
func ShowLoginPage(c *gin.Context) {
|
|
|
|
|
|
// 直接加载 web/admin 目录下的 login.tmpl 模板(需确保文件存在)
|
|
|
|
|
|
tpl, err := template.ParseFiles("web/admin/login.tmpl")
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.String(http.StatusInternalServerError, "加载模板失败: "+err.Error())
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.Status(http.StatusOK)
|
|
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
|
|
|
|
err = tpl.Execute(c.Writer, gin.H{
|
|
|
|
|
|
"Title": "用户登录",
|
|
|
|
|
|
})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.String(http.StatusInternalServerError, "渲染模板错误: "+err.Error())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// ShowRegisterPage 渲染注册页面
|
|
|
|
|
|
func ShowRegisterPage(c *gin.Context) {
|
|
|
|
|
|
tm, exists := c.Get("ThemeManager")
|
|
|
|
|
|
if !exists {
|
|
|
|
|
|
c.String(http.StatusInternalServerError, "Theme manager not found")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
themeManager, ok := tm.(*themes.ThemeManager)
|
|
|
|
|
|
if !ok {
|
|
|
|
|
|
c.String(http.StatusInternalServerError, "Invalid theme manager type")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 假设主题中存在 register.tmpl 模板(或使用后台固定模板)
|
|
|
|
|
|
tpl := themeManager.GetTemplate("register")
|
|
|
|
|
|
if tpl == nil {
|
|
|
|
|
|
c.String(http.StatusInternalServerError, "Template 'register' not found in current theme. Make sure 'register.html' or 'register.tmpl' exists.")
|
|
|
|
|
|
return
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
c.Status(http.StatusOK)
|
|
|
|
|
|
c.Header("Content-Type", "text/html; charset=utf-8")
|
|
|
|
|
|
err := tpl.Execute(c.Writer, gin.H{
|
|
|
|
|
|
"Title": "用户注册",
|
|
|
|
|
|
})
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
c.String(http.StatusInternalServerError, "Error rendering template: "+err.Error())
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|