Files
note-manager/handler/auth_handler.go
T
Your Name 13c53fea0a feat: 管理员跨租户管理 + 注册开关
- 管理员可管理任意用户笔记(读取/修改/删除/回收站/标签/图谱/FTS 全平台)
- 普通用户仍数据隔离, 越权返回404
- 新增注册开关: 管理员后台⚙设置可开/关, 支持REGISTRATION_ENABLED环境变量
- 注册关闭时前台/登录页隐藏注册入口, 注册接口返回400
- 冒烟测试扩展到91用例全过
2026-08-11 13:07:56 +08:00

132 lines
3.7 KiB
Go

package handler
import (
"net/http"
"github.com/gin-gonic/gin"
"note-manager/middleware"
"note-manager/service"
)
// AuthHandler 认证处理器(多租户账号:注册/登录/登出/当前用户)
type AuthHandler struct {
userSvc *service.UserService
}
// NewAuthHandler 创建认证处理器
func NewAuthHandler(userSvc *service.UserService) *AuthHandler {
return &AuthHandler{userSvc: userSvc}
}
// REGISTER 注册请求
type registerReq struct {
Username string `json:"username"`
Password string `json:"password"`
DisplayName string `json:"display_name"`
}
// Register 注册新用户
// 首个注册用户自动成为 admin,并接管历史遗留笔记。
func (h *AuthHandler) Register(c *gin.Context) {
var req registerReq
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, "请求参数错误")
return
}
u, err := h.userSvc.Register(req.Username, req.Password, req.DisplayName)
if err != nil {
fail(c, http.StatusBadRequest, err.Error())
return
}
// 注册成功即自动登录
token, _ := middleware.NewSession(u.ID)
secure := c.Request.TLS != nil
middleware.SetAuthCookie(c, token, secure)
success(c, gin.H{"id": u.ID, "username": u.Username, "display_name": u.DisplayName, "role": u.Role})
}
// Login 登录(用户名 + 密码)
func (h *AuthHandler) Login(c *gin.Context) {
var req struct {
Username string `json:"username"`
Password string `json:"password"`
}
// 兼容 form 提交(后台登录页)
if err := c.ShouldBindJSON(&req); err != nil {
req.Username = c.PostForm("username")
req.Password = c.PostForm("password")
}
if req.Password == "" || req.Username == "" {
fail(c, http.StatusBadRequest, "请输入用户名和密码")
return
}
u, err := h.userSvc.Login(req.Username, req.Password)
if err != nil {
fail(c, http.StatusUnauthorized, err.Error())
return
}
token, _ := middleware.NewSession(u.ID)
secure := c.Request.TLS != nil
middleware.SetAuthCookie(c, token, secure)
success(c, gin.H{"id": u.ID, "username": u.Username, "display_name": u.DisplayName, "role": u.Role})
}
// Logout 登出
func (h *AuthHandler) Logout(c *gin.Context) {
middleware.RevokeSession(middleware.GetAuthToken(c))
middleware.ClearAuthCookie(c)
success(c, nil)
}
// Me 返回当前登录用户信息(未登录返回 null)
func (h *AuthHandler) Me(c *gin.Context) {
uid := middleware.GetUserID(c)
if uid == 0 {
success(c, gin.H{
"registration_enabled": h.userSvc.RegistrationEnabled(),
})
return
}
u, err := h.userSvc.GetByID(uid)
if err != nil {
success(c, nil)
return
}
success(c, gin.H{
"id": u.ID,
"username": u.Username,
"display_name": u.DisplayName,
"role": u.Role,
"registration_enabled": h.userSvc.RegistrationEnabled(),
})
}
// GetRegistrationStatus 获取注册开关状态(管理员)
func (h *AuthHandler) GetRegistrationStatus(c *gin.Context) {
if !h.userSvc.IsAdmin(middleware.GetUserID(c)) {
fail(c, http.StatusForbidden, "仅管理员可操作")
return
}
success(c, gin.H{"registration_enabled": h.userSvc.RegistrationEnabled()})
}
// SetRegistration 切换注册开关(管理员)
func (h *AuthHandler) SetRegistration(c *gin.Context) {
if !h.userSvc.IsAdmin(middleware.GetUserID(c)) {
fail(c, http.StatusForbidden, "仅管理员可操作")
return
}
var req struct {
Enabled bool `json:"enabled"`
}
if err := c.ShouldBindJSON(&req); err != nil {
fail(c, http.StatusBadRequest, "请求参数错误")
return
}
if err := h.userSvc.SetRegistrationEnabled(req.Enabled); err != nil {
fail(c, http.StatusInternalServerError, err.Error())
return
}
success(c, gin.H{"registration_enabled": req.Enabled})
}