2026-05-11 01:40:29 +08:00

114 lines
3.0 KiB
Go

package auth
import (
"net/http"
"github.com/gin-gonic/gin"
"hyapp-admin-server/internal/config"
"hyapp-admin-server/internal/modules/shared"
"hyapp-admin-server/internal/repository"
"hyapp-admin-server/internal/response"
authcore "hyapp-admin-server/internal/service"
)
const refreshCookieName = "hyapp_admin_refresh"
type Handler struct {
service *AuthFlowService
audit shared.OperationLogger
cfg config.Config
}
func New(store *repository.Store, auth *authcore.AuthService, audit shared.OperationLogger, cfg config.Config) *Handler {
return &Handler{service: NewService(store, auth, cfg), audit: audit, cfg: cfg}
}
func (h *Handler) Login(c *gin.Context) {
var req loginRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "用户名和密码不能为空")
return
}
result, err := h.service.Login(LoginInput{
Username: req.Username,
Password: req.Password,
IP: c.ClientIP(),
UserAgent: c.Request.UserAgent(),
})
if err != nil {
response.Unauthorized(c, "用户名或密码错误")
return
}
h.setRefreshCookie(c, result.RefreshToken, int(h.cfg.RefreshTokenTTL.Seconds()))
response.OK(c, gin.H{
"accessToken": result.AccessToken,
"expiresAtMs": result.ExpiresAtMS,
"user": shared.UserDTO(result.User),
"permissions": result.Permissions,
})
}
func (h *Handler) Logout(c *gin.Context) {
if token, err := c.Cookie(refreshCookieName); err == nil && token != "" {
_ = h.service.Logout(token)
}
h.setRefreshCookie(c, "", -1)
response.OK(c, gin.H{"loggedOut": true})
}
func (h *Handler) Refresh(c *gin.Context) {
token, err := c.Cookie(refreshCookieName)
if err != nil || token == "" {
response.Unauthorized(c, "刷新会话不存在")
return
}
result, err := h.service.Refresh(token)
if err != nil {
response.Unauthorized(c, "刷新会话已失效")
return
}
response.OK(c, gin.H{
"accessToken": result.AccessToken,
"expiresAtMs": result.ExpiresAtMS,
"user": shared.UserDTO(result.User),
"permissions": result.Permissions,
})
}
func (h *Handler) Me(c *gin.Context) {
user, permissions, err := h.service.Me(shared.ActorFromContext(c))
if err != nil {
response.Unauthorized(c, "用户不存在")
return
}
response.OK(c, gin.H{
"user": shared.UserDTO(*user),
"permissions": permissions,
})
}
func (h *Handler) ChangePassword(c *gin.Context) {
var req changePasswordRequest
if err := c.ShouldBindJSON(&req); err != nil {
response.BadRequest(c, "旧密码和新密码不能为空")
return
}
if err := h.service.ChangePassword(shared.ActorFromContext(c), req.OldPassword, req.NewPassword); err != nil {
response.BadRequest(c, err.Error())
return
}
shared.OperationLog(c, h.audit, "change-password", "admin_users", "success", "用户修改自己的密码")
response.OK(c, gin.H{"changed": true})
}
func (h *Handler) setRefreshCookie(c *gin.Context, token string, maxAge int) {
c.SetSameSite(http.SameSiteLaxMode)
c.SetCookie(refreshCookieName, token, maxAge, "/api/v1/auth", "", h.cfg.RefreshCookieSecure, true)
}