114 lines
3.0 KiB
Go
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)
|
|
}
|