feat: 引入依赖注入模式
- 创建Repository接口定义(UserRepository、ProfileRepository、TextureRepository等) - 创建Repository接口实现 - 创建依赖注入容器(container.Container) - 改造Handler层使用依赖注入(AuthHandler、UserHandler、TextureHandler) - 创建新的路由注册方式(RegisterRoutesWithDI) - 提供main.go示例文件展示如何使用依赖注入 同时包含之前的安全修复: - CORS配置安全加固 - 头像URL验证安全修复 - JWT algorithm confusion漏洞修复 - Recovery中间件增强 - 敏感错误信息泄露修复 - 类型断言安全修复
This commit is contained in:
177
internal/handler/auth_handler_di.go
Normal file
177
internal/handler/auth_handler_di.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"carrotskin/internal/container"
|
||||
"carrotskin/internal/service"
|
||||
"carrotskin/internal/types"
|
||||
"carrotskin/pkg/email"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// AuthHandler 认证处理器(依赖注入版本)
|
||||
type AuthHandler struct {
|
||||
container *container.Container
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewAuthHandler 创建AuthHandler实例
|
||||
func NewAuthHandler(c *container.Container) *AuthHandler {
|
||||
return &AuthHandler{
|
||||
container: c,
|
||||
logger: c.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
// Register 用户注册
|
||||
// @Summary 用户注册
|
||||
// @Description 注册新用户账号
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body types.RegisterRequest true "注册信息"
|
||||
// @Success 200 {object} model.Response "注册成功"
|
||||
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
|
||||
// @Router /api/v1/auth/register [post]
|
||||
func (h *AuthHandler) Register(c *gin.Context) {
|
||||
var req types.RegisterRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondBadRequest(c, "请求参数错误", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证邮箱验证码
|
||||
if err := service.VerifyCode(c.Request.Context(), h.container.Redis, req.Email, req.VerificationCode, service.VerificationTypeRegister); err != nil {
|
||||
h.logger.Warn("验证码验证失败", zap.String("email", req.Email), zap.Error(err))
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 注册用户
|
||||
user, token, err := service.RegisterUser(h.container.JWT, req.Username, req.Password, req.Email, req.Avatar)
|
||||
if err != nil {
|
||||
h.logger.Error("用户注册失败", zap.Error(err))
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, &types.LoginResponse{
|
||||
Token: token,
|
||||
UserInfo: UserToUserInfo(user),
|
||||
})
|
||||
}
|
||||
|
||||
// Login 用户登录
|
||||
// @Summary 用户登录
|
||||
// @Description 用户登录获取JWT Token,支持用户名或邮箱登录
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body types.LoginRequest true "登录信息(username字段支持用户名或邮箱)"
|
||||
// @Success 200 {object} model.Response{data=types.LoginResponse} "登录成功"
|
||||
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
|
||||
// @Failure 401 {object} model.ErrorResponse "登录失败"
|
||||
// @Router /api/v1/auth/login [post]
|
||||
func (h *AuthHandler) Login(c *gin.Context) {
|
||||
var req types.LoginRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondBadRequest(c, "请求参数错误", err)
|
||||
return
|
||||
}
|
||||
|
||||
ipAddress := c.ClientIP()
|
||||
userAgent := c.GetHeader("User-Agent")
|
||||
|
||||
user, token, err := service.LoginUserWithRateLimit(h.container.Redis, h.container.JWT, req.Username, req.Password, ipAddress, userAgent)
|
||||
if err != nil {
|
||||
h.logger.Warn("用户登录失败",
|
||||
zap.String("username_or_email", req.Username),
|
||||
zap.String("ip", ipAddress),
|
||||
zap.Error(err),
|
||||
)
|
||||
RespondUnauthorized(c, err.Error())
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, &types.LoginResponse{
|
||||
Token: token,
|
||||
UserInfo: UserToUserInfo(user),
|
||||
})
|
||||
}
|
||||
|
||||
// SendVerificationCode 发送验证码
|
||||
// @Summary 发送验证码
|
||||
// @Description 发送邮箱验证码(注册/重置密码/更换邮箱)
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body types.SendVerificationCodeRequest true "发送验证码请求"
|
||||
// @Success 200 {object} model.Response "发送成功"
|
||||
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
|
||||
// @Router /api/v1/auth/send-code [post]
|
||||
func (h *AuthHandler) SendVerificationCode(c *gin.Context) {
|
||||
var req types.SendVerificationCodeRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondBadRequest(c, "请求参数错误", err)
|
||||
return
|
||||
}
|
||||
|
||||
emailService, err := h.getEmailService()
|
||||
if err != nil {
|
||||
RespondServerError(c, "邮件服务不可用", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.SendVerificationCode(c.Request.Context(), h.container.Redis, emailService, req.Email, req.Type); err != nil {
|
||||
h.logger.Error("发送验证码失败",
|
||||
zap.String("email", req.Email),
|
||||
zap.String("type", req.Type),
|
||||
zap.Error(err),
|
||||
)
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, gin.H{"message": "验证码已发送,请查收邮件"})
|
||||
}
|
||||
|
||||
// ResetPassword 重置密码
|
||||
// @Summary 重置密码
|
||||
// @Description 通过邮箱验证码重置密码
|
||||
// @Tags auth
|
||||
// @Accept json
|
||||
// @Produce json
|
||||
// @Param request body types.ResetPasswordRequest true "重置密码请求"
|
||||
// @Success 200 {object} model.Response "重置成功"
|
||||
// @Failure 400 {object} model.ErrorResponse "请求参数错误"
|
||||
// @Router /api/v1/auth/reset-password [post]
|
||||
func (h *AuthHandler) ResetPassword(c *gin.Context) {
|
||||
var req types.ResetPasswordRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondBadRequest(c, "请求参数错误", err)
|
||||
return
|
||||
}
|
||||
|
||||
// 验证验证码
|
||||
if err := service.VerifyCode(c.Request.Context(), h.container.Redis, req.Email, req.VerificationCode, service.VerificationTypeResetPassword); err != nil {
|
||||
h.logger.Warn("验证码验证失败", zap.String("email", req.Email), zap.Error(err))
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
// 重置密码
|
||||
if err := service.ResetUserPassword(req.Email, req.NewPassword); err != nil {
|
||||
h.logger.Error("重置密码失败", zap.String("email", req.Email), zap.Error(err))
|
||||
RespondServerError(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, gin.H{"message": "密码重置成功"})
|
||||
}
|
||||
|
||||
// getEmailService 获取邮件服务(暂时使用全局方式,后续可改为依赖注入)
|
||||
func (h *AuthHandler) getEmailService() (*email.Service, error) {
|
||||
return email.GetService()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user