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:
233
internal/handler/user_handler_di.go
Normal file
233
internal/handler/user_handler_di.go
Normal file
@@ -0,0 +1,233 @@
|
||||
package handler
|
||||
|
||||
import (
|
||||
"carrotskin/internal/container"
|
||||
"carrotskin/internal/service"
|
||||
"carrotskin/internal/types"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
||||
// UserHandler 用户处理器(依赖注入版本)
|
||||
type UserHandler struct {
|
||||
container *container.Container
|
||||
logger *zap.Logger
|
||||
}
|
||||
|
||||
// NewUserHandler 创建UserHandler实例
|
||||
func NewUserHandler(c *container.Container) *UserHandler {
|
||||
return &UserHandler{
|
||||
container: c,
|
||||
logger: c.Logger,
|
||||
}
|
||||
}
|
||||
|
||||
// GetProfile 获取用户信息
|
||||
func (h *UserHandler) GetProfile(c *gin.Context) {
|
||||
userID, ok := GetUserIDFromContext(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
user, err := service.GetUserByID(userID)
|
||||
if err != nil || user == nil {
|
||||
h.logger.Error("获取用户信息失败",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.Error(err),
|
||||
)
|
||||
RespondNotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, UserToUserInfo(user))
|
||||
}
|
||||
|
||||
// UpdateProfile 更新用户信息
|
||||
func (h *UserHandler) UpdateProfile(c *gin.Context) {
|
||||
userID, ok := GetUserIDFromContext(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req types.UpdateUserRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondBadRequest(c, "请求参数错误", err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := service.GetUserByID(userID)
|
||||
if err != nil || user == nil {
|
||||
RespondNotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
// 处理密码修改
|
||||
if req.NewPassword != "" {
|
||||
if req.OldPassword == "" {
|
||||
RespondBadRequest(c, "修改密码需要提供原密码", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.ChangeUserPassword(userID, req.OldPassword, req.NewPassword); err != nil {
|
||||
h.logger.Error("修改密码失败", zap.Int64("user_id", userID), zap.Error(err))
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("用户修改密码成功", zap.Int64("user_id", userID))
|
||||
}
|
||||
|
||||
// 更新头像
|
||||
if req.Avatar != "" {
|
||||
if err := service.ValidateAvatarURL(req.Avatar); err != nil {
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
user.Avatar = req.Avatar
|
||||
if err := service.UpdateUserInfo(user); err != nil {
|
||||
h.logger.Error("更新用户信息失败", zap.Int64("user_id", user.ID), zap.Error(err))
|
||||
RespondServerError(c, "更新失败", err)
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
// 重新获取更新后的用户信息
|
||||
updatedUser, err := service.GetUserByID(userID)
|
||||
if err != nil || updatedUser == nil {
|
||||
RespondNotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, UserToUserInfo(updatedUser))
|
||||
}
|
||||
|
||||
// GenerateAvatarUploadURL 生成头像上传URL
|
||||
func (h *UserHandler) GenerateAvatarUploadURL(c *gin.Context) {
|
||||
userID, ok := GetUserIDFromContext(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req types.GenerateAvatarUploadURLRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondBadRequest(c, "请求参数错误", err)
|
||||
return
|
||||
}
|
||||
|
||||
if h.container.Storage == nil {
|
||||
RespondServerError(c, "存储服务不可用", nil)
|
||||
return
|
||||
}
|
||||
|
||||
result, err := service.GenerateAvatarUploadURL(c.Request.Context(), h.container.Storage, userID, req.FileName)
|
||||
if err != nil {
|
||||
h.logger.Error("生成头像上传URL失败",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.String("file_name", req.FileName),
|
||||
zap.Error(err),
|
||||
)
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, &types.GenerateAvatarUploadURLResponse{
|
||||
PostURL: result.PostURL,
|
||||
FormData: result.FormData,
|
||||
AvatarURL: result.FileURL,
|
||||
ExpiresIn: 900,
|
||||
})
|
||||
}
|
||||
|
||||
// UpdateAvatar 更新头像URL
|
||||
func (h *UserHandler) UpdateAvatar(c *gin.Context) {
|
||||
userID, ok := GetUserIDFromContext(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
avatarURL := c.Query("avatar_url")
|
||||
if avatarURL == "" {
|
||||
RespondBadRequest(c, "头像URL不能为空", nil)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.ValidateAvatarURL(avatarURL); err != nil {
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.UpdateUserAvatar(userID, avatarURL); err != nil {
|
||||
h.logger.Error("更新头像失败",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.String("avatar_url", avatarURL),
|
||||
zap.Error(err),
|
||||
)
|
||||
RespondServerError(c, "更新头像失败", err)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := service.GetUserByID(userID)
|
||||
if err != nil || user == nil {
|
||||
RespondNotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, UserToUserInfo(user))
|
||||
}
|
||||
|
||||
// ChangeEmail 更换邮箱
|
||||
func (h *UserHandler) ChangeEmail(c *gin.Context) {
|
||||
userID, ok := GetUserIDFromContext(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
var req types.ChangeEmailRequest
|
||||
if err := c.ShouldBindJSON(&req); err != nil {
|
||||
RespondBadRequest(c, "请求参数错误", err)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.VerifyCode(c.Request.Context(), h.container.Redis, req.NewEmail, req.VerificationCode, service.VerificationTypeChangeEmail); err != nil {
|
||||
h.logger.Warn("验证码验证失败", zap.String("new_email", req.NewEmail), zap.Error(err))
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
if err := service.ChangeUserEmail(userID, req.NewEmail); err != nil {
|
||||
h.logger.Error("更换邮箱失败",
|
||||
zap.Int64("user_id", userID),
|
||||
zap.String("new_email", req.NewEmail),
|
||||
zap.Error(err),
|
||||
)
|
||||
RespondBadRequest(c, err.Error(), nil)
|
||||
return
|
||||
}
|
||||
|
||||
user, err := service.GetUserByID(userID)
|
||||
if err != nil || user == nil {
|
||||
RespondNotFound(c, "用户不存在")
|
||||
return
|
||||
}
|
||||
|
||||
RespondSuccess(c, UserToUserInfo(user))
|
||||
}
|
||||
|
||||
// ResetYggdrasilPassword 重置Yggdrasil密码
|
||||
func (h *UserHandler) ResetYggdrasilPassword(c *gin.Context) {
|
||||
userID, ok := GetUserIDFromContext(c)
|
||||
if !ok {
|
||||
return
|
||||
}
|
||||
|
||||
newPassword, err := service.ResetYggdrasilPassword(h.container.DB, userID)
|
||||
if err != nil {
|
||||
h.logger.Error("重置Yggdrasil密码失败", zap.Error(err), zap.Int64("userId", userID))
|
||||
RespondServerError(c, "重置Yggdrasil密码失败", nil)
|
||||
return
|
||||
}
|
||||
|
||||
h.logger.Info("Yggdrasil密码重置成功", zap.Int64("userId", userID))
|
||||
RespondSuccess(c, gin.H{"password": newPassword})
|
||||
}
|
||||
Reference in New Issue
Block a user