All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m17s
- 合并 customer_account 和 shop_account 路由到统一的 account 接口 - 新增统一认证接口 (auth handler) - 实现越权防护中间件和权限检查工具函数 - 新增操作审计日志模型和服务 - 更新数据库迁移 (版本 39: account_operation_log 表) - 补充集成测试覆盖权限检查和审计日志场景
168 lines
4.2 KiB
Go
168 lines
4.2 KiB
Go
package auth
|
||
|
||
import (
|
||
"github.com/break/junhong_cmp_fiber/internal/model/dto"
|
||
"github.com/break/junhong_cmp_fiber/internal/service/auth"
|
||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||
"github.com/break/junhong_cmp_fiber/pkg/logger"
|
||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||
"github.com/break/junhong_cmp_fiber/pkg/response"
|
||
"github.com/go-playground/validator/v10"
|
||
"github.com/gofiber/fiber/v2"
|
||
"go.uber.org/zap"
|
||
)
|
||
|
||
// Handler 统一认证处理器
|
||
// 合并后台和 H5 认证接口
|
||
type Handler struct {
|
||
authService *auth.Service
|
||
validator *validator.Validate
|
||
}
|
||
|
||
// NewHandler 创建统一认证处理器
|
||
func NewHandler(authService *auth.Service, validator *validator.Validate) *Handler {
|
||
return &Handler{
|
||
authService: authService,
|
||
validator: validator,
|
||
}
|
||
}
|
||
|
||
// Login 统一登录(后台+H5)
|
||
// POST /api/auth/login - 统一登录(后台+H5)
|
||
func (h *Handler) Login(c *fiber.Ctx) error {
|
||
var req dto.LoginRequest
|
||
if err := c.BodyParser(&req); err != nil {
|
||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||
}
|
||
|
||
if err := h.validator.Struct(&req); err != nil {
|
||
logger.GetAppLogger().Warn("参数验证失败",
|
||
zap.String("path", c.Path()),
|
||
zap.String("method", c.Method()),
|
||
zap.Error(err),
|
||
)
|
||
return errors.New(errors.CodeInvalidParam)
|
||
}
|
||
|
||
clientIP := c.IP()
|
||
ctx := c.UserContext()
|
||
|
||
resp, err := h.authService.Login(ctx, &req, clientIP)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
return response.Success(c, resp)
|
||
}
|
||
|
||
// Logout 统一登出
|
||
// POST /api/auth/logout - 统一登出
|
||
func (h *Handler) Logout(c *fiber.Ctx) error {
|
||
authorization := c.Get("Authorization")
|
||
accessToken := ""
|
||
if len(authorization) > 7 && authorization[:7] == "Bearer " {
|
||
accessToken = authorization[7:]
|
||
}
|
||
|
||
// 尝试从请求体获取 refresh_token(可选)
|
||
refreshToken := ""
|
||
var req dto.RefreshTokenRequest
|
||
if err := c.BodyParser(&req); err == nil {
|
||
refreshToken = req.RefreshToken
|
||
}
|
||
|
||
ctx := c.UserContext()
|
||
|
||
if err := h.authService.Logout(ctx, accessToken, refreshToken); err != nil {
|
||
return err
|
||
}
|
||
|
||
return response.Success(c, nil)
|
||
}
|
||
|
||
// RefreshToken 刷新 Token
|
||
// POST /api/auth/refresh-token - 刷新 Token
|
||
func (h *Handler) RefreshToken(c *fiber.Ctx) error {
|
||
var req dto.RefreshTokenRequest
|
||
if err := c.BodyParser(&req); err != nil {
|
||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||
}
|
||
|
||
if err := h.validator.Struct(&req); err != nil {
|
||
logger.GetAppLogger().Warn("参数验证失败",
|
||
zap.String("path", c.Path()),
|
||
zap.String("method", c.Method()),
|
||
zap.Error(err),
|
||
)
|
||
return errors.New(errors.CodeInvalidParam)
|
||
}
|
||
|
||
ctx := c.UserContext()
|
||
|
||
newAccessToken, err := h.authService.RefreshToken(ctx, req.RefreshToken)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
resp := &dto.RefreshTokenResponse{
|
||
AccessToken: newAccessToken,
|
||
ExpiresIn: 86400,
|
||
}
|
||
|
||
return response.Success(c, resp)
|
||
}
|
||
|
||
// GetMe 获取用户信息
|
||
// GET /api/auth/me - 获取用户信息
|
||
func (h *Handler) GetMe(c *fiber.Ctx) error {
|
||
userID := middleware.GetUserIDFromContext(c.UserContext())
|
||
if userID == 0 {
|
||
return errors.New(errors.CodeUnauthorized, "未授权访问")
|
||
}
|
||
|
||
ctx := c.UserContext()
|
||
|
||
userInfo, permissions, err := h.authService.GetCurrentUser(ctx, userID)
|
||
if err != nil {
|
||
return err
|
||
}
|
||
|
||
data := map[string]interface{}{
|
||
"user": userInfo,
|
||
"permissions": permissions,
|
||
}
|
||
|
||
return response.Success(c, data)
|
||
}
|
||
|
||
// ChangePassword 修改密码
|
||
// PUT /api/auth/password - 修改密码
|
||
func (h *Handler) ChangePassword(c *fiber.Ctx) error {
|
||
userID := middleware.GetUserIDFromContext(c.UserContext())
|
||
if userID == 0 {
|
||
return errors.New(errors.CodeUnauthorized, "未授权访问")
|
||
}
|
||
|
||
var req dto.ChangePasswordRequest
|
||
if err := c.BodyParser(&req); err != nil {
|
||
return errors.New(errors.CodeInvalidParam, "请求参数解析失败")
|
||
}
|
||
|
||
if err := h.validator.Struct(&req); err != nil {
|
||
logger.GetAppLogger().Warn("参数验证失败",
|
||
zap.String("path", c.Path()),
|
||
zap.String("method", c.Method()),
|
||
zap.Error(err),
|
||
)
|
||
return errors.New(errors.CodeInvalidParam)
|
||
}
|
||
|
||
ctx := c.UserContext()
|
||
|
||
if err := h.authService.ChangePassword(ctx, userID, req.OldPassword, req.NewPassword); err != nil {
|
||
return err
|
||
}
|
||
|
||
return response.Success(c, nil)
|
||
}
|