refactor(account): 统一账号管理API、完善权限检查和操作审计
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m17s
All checks were successful
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Successful in 6m17s
- 合并 customer_account 和 shop_account 路由到统一的 account 接口 - 新增统一认证接口 (auth handler) - 实现越权防护中间件和权限检查工具函数 - 新增操作审计日志模型和服务 - 更新数据库迁移 (版本 39: account_operation_log 表) - 补充集成测试覆盖权限检查和审计日志场景
This commit is contained in:
167
internal/handler/auth/handler.go
Normal file
167
internal/handler/auth/handler.go
Normal file
@@ -0,0 +1,167 @@
|
||||
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)
|
||||
}
|
||||
Reference in New Issue
Block a user