refactor: Implement dependency injection for handlers and services

- Refactored AuthHandler, UserHandler, TextureHandler, ProfileHandler, CaptchaHandler, and YggdrasilHandler to use dependency injection.
- Removed direct instantiation of services and repositories within handlers, replacing them with constructor injection.
- Updated the container to initialize service instances and provide them to handlers.
- Enhanced code structure for better testability and adherence to Go best practices.
This commit is contained in:
lafay
2025-12-02 19:43:39 +08:00
parent 188a05caa7
commit 801f1b1397
33 changed files with 3628 additions and 4129 deletions

View File

@@ -2,11 +2,9 @@ package handler
import (
"bytes"
"carrotskin/internal/container"
"carrotskin/internal/model"
"carrotskin/internal/service"
"carrotskin/pkg/database"
"carrotskin/pkg/logger"
"carrotskin/pkg/redis"
"carrotskin/pkg/utils"
"io"
"net/http"
@@ -111,6 +109,7 @@ type (
Password string `json:"password" binding:"required"`
}
// JoinServerRequest 加入服务器请求
JoinServerRequest struct {
ServerID string `json:"serverId" binding:"required"`
AccessToken string `json:"accessToken" binding:"required"`
@@ -138,6 +137,7 @@ type (
}
)
// APIResponse API响应
type APIResponse struct {
Status int `json:"status"`
Data interface{} `json:"data"`
@@ -153,38 +153,47 @@ func standardResponse(c *gin.Context, status int, data interface{}, err interfac
})
}
// Authenticate 用户认证
func Authenticate(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
// YggdrasilHandler Yggdrasil API处理器
type YggdrasilHandler struct {
container *container.Container
logger *zap.Logger
}
// 读取并保存原始请求体,以便多次读取
// NewYggdrasilHandler 创建YggdrasilHandler实例
func NewYggdrasilHandler(c *container.Container) *YggdrasilHandler {
return &YggdrasilHandler{
container: c,
logger: c.Logger,
}
}
// Authenticate 用户认证
func (h *YggdrasilHandler) Authenticate(c *gin.Context) {
rawData, err := io.ReadAll(c.Request.Body)
if err != nil {
loggerInstance.Error("[ERROR] 读取请求体失败: ", zap.Error(err))
h.logger.Error("读取请求体失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "读取请求体失败"})
return
}
c.Request.Body = io.NopCloser(bytes.NewBuffer(rawData))
// 绑定JSON数据到请求结构体
var request AuthenticateRequest
if err = c.ShouldBindJSON(&request); err != nil {
loggerInstance.Error("[ERROR] 解析认证请求失败: ", zap.Error(err))
h.logger.Error("解析认证请求失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 根据标识符类型(邮箱或用户名)获取用户
var userId int64
var profile *model.Profile
var UUID string
if emailRegex.MatchString(request.Identifier) {
userId, err = service.GetUserIDByEmail(db, request.Identifier)
userId, err = service.GetUserIDByEmail(h.container.DB, request.Identifier)
} else {
profile, err = service.GetProfileByProfileName(db, request.Identifier)
profile, err = service.GetProfileByProfileName(h.container.DB, request.Identifier)
if err != nil {
loggerInstance.Error("[ERROR] 用户名不存在: ", zap.String("标识符", request.Identifier), zap.Error(err))
h.logger.Error("用户名不存在", zap.String("identifier", request.Identifier), zap.Error(err))
c.JSON(http.StatusForbidden, gin.H{"error": err.Error()})
return
}
@@ -193,163 +202,146 @@ func Authenticate(c *gin.Context) {
}
if err != nil {
loggerInstance.Warn("[WARN] 认证失败: 用户不存在",
zap.String("标识符:", request.Identifier),
zap.Error(err))
h.logger.Warn("认证失败: 用户不存在", zap.String("identifier", request.Identifier), zap.Error(err))
c.JSON(http.StatusForbidden, gin.H{"error": "用户不存在"})
return
}
// 验证密码
err = service.VerifyPassword(db, request.Password, userId)
if err != nil {
loggerInstance.Warn("[WARN] 认证失败:", zap.Error(err))
if err := service.VerifyPassword(h.container.DB, request.Password, userId); err != nil {
h.logger.Warn("认证失败: 密码错误", zap.Error(err))
c.JSON(http.StatusForbidden, gin.H{"error": ErrWrongPassword})
return
}
// 生成新令牌
selectedProfile, availableProfiles, accessToken, clientToken, err := service.NewToken(db, loggerInstance, userId, UUID, request.ClientToken)
selectedProfile, availableProfiles, accessToken, clientToken, err := h.container.TokenService.Create(userId, UUID, request.ClientToken)
if err != nil {
loggerInstance.Error("[ERROR] 生成令牌失败:", zap.Error(err), zap.Any("用户ID:", userId))
h.logger.Error("生成令牌失败", zap.Error(err), zap.Int64("userId", userId))
c.JSON(http.StatusInternalServerError, gin.H{"error": err.Error()})
return
}
user, err := service.GetUserByID(userId)
user, err := h.container.UserService.GetByID(userId)
if err != nil {
loggerInstance.Error("[ERROR] id查找错误:", zap.Error(err), zap.Any("ID:", userId))
h.logger.Error("获取用户信息失败", zap.Error(err), zap.Int64("userId", userId))
}
// 处理可用的配置文件
redisClient := redis.MustGetClient()
availableProfilesData := make([]map[string]interface{}, 0, len(availableProfiles))
for _, profile := range availableProfiles {
availableProfilesData = append(availableProfilesData, service.SerializeProfile(db, loggerInstance, redisClient, *profile))
for _, p := range availableProfiles {
availableProfilesData = append(availableProfilesData, service.SerializeProfile(h.container.DB, h.logger, h.container.Redis, *p))
}
response := AuthenticateResponse{
AccessToken: accessToken,
ClientToken: clientToken,
AvailableProfiles: availableProfilesData,
}
if selectedProfile != nil {
response.SelectedProfile = service.SerializeProfile(db, loggerInstance, redisClient, *selectedProfile)
}
if request.RequestUser {
// 使用 SerializeUser 来正确处理 Properties 字段
response.User = service.SerializeUser(loggerInstance, user, UUID)
response.SelectedProfile = service.SerializeProfile(h.container.DB, h.logger, h.container.Redis, *selectedProfile)
}
// 返回认证响应
loggerInstance.Info("[INFO] 用户认证成功", zap.Any("用户ID:", userId))
if request.RequestUser && user != nil {
response.User = service.SerializeUser(h.logger, user, UUID)
}
h.logger.Info("用户认证成功", zap.Int64("userId", userId))
c.JSON(http.StatusOK, response)
}
// ValidToken 验证令牌
func ValidToken(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
func (h *YggdrasilHandler) ValidToken(c *gin.Context) {
var request ValidTokenRequest
if err := c.ShouldBindJSON(&request); err != nil {
loggerInstance.Error("[ERROR] 解析验证令牌请求失败: ", zap.Error(err))
h.logger.Error("解析验证令牌请求失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 验证令牌
if service.ValidToken(db, request.AccessToken, request.ClientToken) {
loggerInstance.Info("[INFO] 令牌验证成功", zap.Any("访问令牌:", request.AccessToken))
if h.container.TokenService.Validate(request.AccessToken, request.ClientToken) {
h.logger.Info("令牌验证成功", zap.String("accessToken", request.AccessToken))
c.JSON(http.StatusNoContent, gin.H{"valid": true})
} else {
loggerInstance.Warn("[WARN] 令牌验证失败", zap.Any("访问令牌:", request.AccessToken))
h.logger.Warn("令牌验证失败", zap.String("accessToken", request.AccessToken))
c.JSON(http.StatusForbidden, gin.H{"valid": false})
}
}
// RefreshToken 刷新令牌
func RefreshToken(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
func (h *YggdrasilHandler) RefreshToken(c *gin.Context) {
var request RefreshRequest
if err := c.ShouldBindJSON(&request); err != nil {
loggerInstance.Error("[ERROR] 解析刷新令牌请求失败: ", zap.Error(err))
h.logger.Error("解析刷新令牌请求失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 获取用户ID和用户信息
UUID, err := service.GetUUIDByAccessToken(db, request.AccessToken)
UUID, err := h.container.TokenService.GetUUIDByAccessToken(request.AccessToken)
if err != nil {
loggerInstance.Warn("[WARN] 刷新令牌失败: 无效的访问令牌", zap.Any("令牌:", request.AccessToken), zap.Error(err))
h.logger.Warn("刷新令牌失败: 无效的访问令牌", zap.String("token", request.AccessToken), zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
userID, _ := service.GetUserIDByAccessToken(db, request.AccessToken)
// 格式化UUID 这里是因为HMCL的传入参数是HEX格式为了兼容HMCL在此做处理
userID, _ := h.container.TokenService.GetUserIDByAccessToken(request.AccessToken)
UUID = utils.FormatUUID(UUID)
profile, err := service.GetProfileByUUID(db, UUID)
profile, err := h.container.ProfileService.GetByUUID(UUID)
if err != nil {
loggerInstance.Error("[ERROR] 刷新令牌失败: 无法获取用户信息 错误: ", zap.Error(err))
h.logger.Error("刷新令牌失败: 无法获取用户信息", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 准备响应数据
var profileData map[string]interface{}
var userData map[string]interface{}
var profileID string
// 处理选定的配置文件
if request.SelectedProfile != nil {
// 验证profileID是否存在
profileIDValue, ok := request.SelectedProfile["id"]
if !ok {
loggerInstance.Error("[ERROR] 刷新令牌失败: 缺少配置文件ID", zap.Any("ID:", userID))
h.logger.Error("刷新令牌失败: 缺少配置文件ID", zap.Int64("userId", userID))
c.JSON(http.StatusBadRequest, gin.H{"error": "缺少配置文件ID"})
return
}
// 类型断言
profileID, ok = profileIDValue.(string)
if !ok {
loggerInstance.Error("[ERROR] 刷新令牌失败: 配置文件ID类型错误 ", zap.Any("用户ID:", userID))
h.logger.Error("刷新令牌失败: 配置文件ID类型错误", zap.Int64("userId", userID))
c.JSON(http.StatusBadRequest, gin.H{"error": "配置文件ID必须是字符串"})
return
}
// 格式化profileID
profileID = utils.FormatUUID(profileID)
// 验证配置文件所属用户
if profile.UserID != userID {
loggerInstance.Warn("[WARN] 刷新令牌失败: 用户不匹配 ", zap.Any("用户ID:", userID), zap.Any("配置文件用户ID:", profile.UserID))
h.logger.Warn("刷新令牌失败: 用户不匹配",
zap.Int64("userId", userID),
zap.Int64("profileUserId", profile.UserID),
)
c.JSON(http.StatusBadRequest, gin.H{"error": ErrUserNotMatch})
return
}
profileData = service.SerializeProfile(db, loggerInstance, redis.MustGetClient(), *profile)
}
user, _ := service.GetUserByID(userID)
// 添加用户信息(如果请求了)
if request.RequestUser {
userData = service.SerializeUser(loggerInstance, user, UUID)
profileData = service.SerializeProfile(h.container.DB, h.logger, h.container.Redis, *profile)
}
// 刷新令牌
newAccessToken, newClientToken, err := service.RefreshToken(db, loggerInstance,
user, _ := h.container.UserService.GetByID(userID)
if request.RequestUser && user != nil {
userData = service.SerializeUser(h.logger, user, UUID)
}
newAccessToken, newClientToken, err := h.container.TokenService.Refresh(
request.AccessToken,
request.ClientToken,
profileID,
)
if err != nil {
loggerInstance := logger.MustGetLogger()
loggerInstance.Error("[ERROR] 刷新令牌失败: ", zap.Error(err), zap.Any("用户ID: ", userID))
h.logger.Error("刷新令牌失败", zap.Error(err), zap.Int64("userId", userID))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 返回响应
loggerInstance.Info("[INFO] 刷新令牌成功", zap.Any("用户ID:", userID))
h.logger.Info("刷新令牌成功", zap.Int64("userId", userID))
c.JSON(http.StatusOK, RefreshResponse{
AccessToken: newAccessToken,
ClientToken: newClientToken,
@@ -359,231 +351,177 @@ func RefreshToken(c *gin.Context) {
}
// InvalidToken 使令牌失效
func InvalidToken(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
func (h *YggdrasilHandler) InvalidToken(c *gin.Context) {
var request ValidTokenRequest
if err := c.ShouldBindJSON(&request); err != nil {
loggerInstance.Error("[ERROR] 解析使令牌失效请求失败: ", zap.Error(err))
h.logger.Error("解析使令牌失效请求失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 使令牌失效
service.InvalidToken(db, loggerInstance, request.AccessToken)
loggerInstance.Info("[INFO] 令牌已使失效", zap.Any("访问令牌:", request.AccessToken))
h.container.TokenService.Invalidate(request.AccessToken)
h.logger.Info("令牌已失效", zap.String("token", request.AccessToken))
c.JSON(http.StatusNoContent, gin.H{})
}
// SignOut 用户登出
func SignOut(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
func (h *YggdrasilHandler) SignOut(c *gin.Context) {
var request SignOutRequest
if err := c.ShouldBindJSON(&request); err != nil {
loggerInstance.Error("[ERROR] 解析登出请求失败: %v", zap.Error(err))
h.logger.Error("解析登出请求失败", zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
return
}
// 验证邮箱格式
if !emailRegex.MatchString(request.Email) {
loggerInstance.Warn("[WARN] 登出失败: 邮箱格式不正确 ", zap.Any(" ", request.Email))
h.logger.Warn("登出失败: 邮箱格式不正确", zap.String("email", request.Email))
c.JSON(http.StatusBadRequest, gin.H{"error": ErrInvalidEmailFormat})
return
}
// 通过邮箱获取用户
user, err := service.GetUserByEmail(request.Email)
if err != nil {
loggerInstance.Warn(
"登出失败: 用户不存在",
zap.String("邮箱", request.Email),
zap.Error(err),
)
c.JSON(http.StatusBadRequest, gin.H{"error": err.Error()})
user, err := h.container.UserService.GetByEmail(request.Email)
if err != nil || user == nil {
h.logger.Warn("登出失败: 用户不存在", zap.String("email", request.Email), zap.Error(err))
c.JSON(http.StatusBadRequest, gin.H{"error": "用户不存在"})
return
}
// 验证密码
if err := service.VerifyPassword(db, request.Password, user.ID); err != nil {
loggerInstance.Warn("[WARN] 登出失败: 密码错误", zap.Any("用户ID:", user.ID))
if err := service.VerifyPassword(h.container.DB, request.Password, user.ID); err != nil {
h.logger.Warn("登出失败: 密码错误", zap.Int64("userId", user.ID))
c.JSON(http.StatusBadRequest, gin.H{"error": ErrWrongPassword})
return
}
// 使该用户的所有令牌失效
service.InvalidUserTokens(db, loggerInstance, user.ID)
loggerInstance.Info("[INFO] 用户登出成功", zap.Any("用户ID:", user.ID))
h.container.TokenService.InvalidateUserTokens(user.ID)
h.logger.Info("用户登出成功", zap.Int64("userId", user.ID))
c.JSON(http.StatusNoContent, gin.H{"valid": true})
}
func GetProfileByUUID(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
redisClient := redis.MustGetClient()
// 获取并格式化UUID
// GetProfileByUUID 根据UUID获取档案
func (h *YggdrasilHandler) GetProfileByUUID(c *gin.Context) {
uuid := utils.FormatUUID(c.Param("uuid"))
loggerInstance.Info("[INFO] 接收到获取配置文件请求", zap.Any("UUID:", uuid))
h.logger.Info("获取配置文件请求", zap.String("uuid", uuid))
// 获取配置文件
profile, err := service.GetProfileByUUID(db, uuid)
profile, err := h.container.ProfileService.GetByUUID(uuid)
if err != nil {
loggerInstance.Error("[ERROR] 获取配置文件失败:", zap.Error(err), zap.String("UUID:", uuid))
h.logger.Error("获取配置文件失败", zap.Error(err), zap.String("uuid", uuid))
standardResponse(c, http.StatusInternalServerError, nil, err.Error())
return
}
// 返回配置文件信息
loggerInstance.Info("[INFO] 成功获取配置文件", zap.String("UUID:", uuid), zap.String("名称:", profile.Name))
c.JSON(http.StatusOK, service.SerializeProfile(db, loggerInstance, redisClient, *profile))
h.logger.Info("成功获取配置文件", zap.String("uuid", uuid), zap.String("name", profile.Name))
c.JSON(http.StatusOK, service.SerializeProfile(h.container.DB, h.logger, h.container.Redis, *profile))
}
func JoinServer(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
redisClient := redis.MustGetClient()
// JoinServer 加入服务器
func (h *YggdrasilHandler) JoinServer(c *gin.Context) {
var request JoinServerRequest
clientIP := c.ClientIP()
// 解析请求参数
if err := c.ShouldBindJSON(&request); err != nil {
loggerInstance.Error(
"解析加入服务器请求失败",
zap.Error(err),
zap.String("IP", clientIP),
)
h.logger.Error("解析加入服务器请求失败", zap.Error(err), zap.String("ip", clientIP))
standardResponse(c, http.StatusBadRequest, nil, ErrInvalidRequest)
return
}
loggerInstance.Info(
"收到加入服务器请求",
zap.String("服务器ID", request.ServerID),
zap.String("用户UUID", request.SelectedProfile),
zap.String("IP", clientIP),
h.logger.Info("收到加入服务器请求",
zap.String("serverId", request.ServerID),
zap.String("userUUID", request.SelectedProfile),
zap.String("ip", clientIP),
)
// 处理加入服务器请求
if err := service.JoinServer(db, loggerInstance, redisClient, request.ServerID, request.AccessToken, request.SelectedProfile, clientIP); err != nil {
loggerInstance.Error(
"加入服务器失败",
if err := service.JoinServer(h.container.DB, h.logger, h.container.Redis, request.ServerID, request.AccessToken, request.SelectedProfile, clientIP); err != nil {
h.logger.Error("加入服务器失败",
zap.Error(err),
zap.String("服务器ID", request.ServerID),
zap.String("用户UUID", request.SelectedProfile),
zap.String("IP", clientIP),
zap.String("serverId", request.ServerID),
zap.String("userUUID", request.SelectedProfile),
zap.String("ip", clientIP),
)
standardResponse(c, http.StatusInternalServerError, nil, ErrJoinServerFailed)
return
}
// 加入成功返回204状态码
loggerInstance.Info(
"加入服务器成功",
zap.String("服务器ID", request.ServerID),
zap.String("用户UUID", request.SelectedProfile),
zap.String("IP", clientIP),
h.logger.Info("加入服务器成功",
zap.String("serverId", request.ServerID),
zap.String("userUUID", request.SelectedProfile),
zap.String("ip", clientIP),
)
c.Status(http.StatusNoContent)
}
func HasJoinedServer(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
redisClient := redis.MustGetClient()
// HasJoinedServer 验证玩家是否已加入服务器
func (h *YggdrasilHandler) HasJoinedServer(c *gin.Context) {
clientIP, _ := c.GetQuery("ip")
// 获取并验证服务器ID参数
serverID, exists := c.GetQuery("serverId")
if !exists || serverID == "" {
loggerInstance.Warn("[WARN] 缺少服务器ID参数", zap.Any("IP:", clientIP))
h.logger.Warn("缺少服务器ID参数", zap.String("ip", clientIP))
standardResponse(c, http.StatusNoContent, nil, ErrServerIDRequired)
return
}
// 获取并验证用户名参数
username, exists := c.GetQuery("username")
if !exists || username == "" {
loggerInstance.Warn("[WARN] 缺少用户名参数", zap.Any("服务器ID:", serverID), zap.Any("IP:", clientIP))
h.logger.Warn("缺少用户名参数", zap.String("serverId", serverID), zap.String("ip", clientIP))
standardResponse(c, http.StatusNoContent, nil, ErrUsernameRequired)
return
}
loggerInstance.Info("[INFO] 收到会话验证请求", zap.Any("服务器ID:", serverID), zap.Any("用户名: ", username), zap.Any("IP: ", clientIP))
h.logger.Info("收到会话验证请求",
zap.String("serverId", serverID),
zap.String("username", username),
zap.String("ip", clientIP),
)
// 验证玩家是否已加入服务器
if err := service.HasJoinedServer(loggerInstance, redisClient, serverID, username, clientIP); err != nil {
loggerInstance.Warn("[WARN] 会话验证失败",
if err := service.HasJoinedServer(h.logger, h.container.Redis, serverID, username, clientIP); err != nil {
h.logger.Warn("会话验证失败",
zap.Error(err),
zap.String("serverID", serverID),
zap.String("serverId", serverID),
zap.String("username", username),
zap.String("clientIP", clientIP),
zap.String("ip", clientIP),
)
standardResponse(c, http.StatusNoContent, nil, ErrSessionVerifyFailed)
return
}
profile, err := service.GetProfileByUUID(db, username)
profile, err := h.container.ProfileService.GetByUUID(username)
if err != nil {
loggerInstance.Error("[ERROR] 获取用户配置文件失败: %v - 用户名: %s",
zap.Error(err), // 错误详情zap 原生支持,保留错误链)
zap.String("username", username), // 结构化存储用户名(便于检索)
)
h.logger.Error("获取用户配置文件失败", zap.Error(err), zap.String("username", username))
standardResponse(c, http.StatusNoContent, nil, ErrProfileNotFound)
return
}
// 返回玩家配置文件
loggerInstance.Info("[INFO] 会话验证成功 - 服务器ID: %s, 用户名: %s, UUID: %s",
zap.String("serverID", serverID), // 结构化存储服务器ID
zap.String("username", username), // 结构化存储用户名
zap.String("UUID", profile.UUID), // 结构化存储UUID
h.logger.Info("会话验证成功",
zap.String("serverId", serverID),
zap.String("username", username),
zap.String("uuid", profile.UUID),
)
c.JSON(200, service.SerializeProfile(db, loggerInstance, redisClient, *profile))
c.JSON(200, service.SerializeProfile(h.container.DB, h.logger, h.container.Redis, *profile))
}
func GetProfilesByName(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
// GetProfilesByName 批量获取配置文件
func (h *YggdrasilHandler) GetProfilesByName(c *gin.Context) {
var names []string
// 解析请求参数
if err := c.ShouldBindJSON(&names); err != nil {
loggerInstance.Error("[ERROR] 解析名称数组请求失败: ",
zap.Error(err),
)
h.logger.Error("解析名称数组请求失败", zap.Error(err))
standardResponse(c, http.StatusBadRequest, nil, ErrInvalidParams)
return
}
loggerInstance.Info("[INFO] 接收到批量获取配置文件请求",
zap.Int("名称数量:", len(names)), // 结构化存储名称数量
)
// 批量获取配置文件
profiles, err := service.GetProfilesDataByNames(db, names)
h.logger.Info("接收到批量获取配置文件请求", zap.Int("count", len(names)))
profiles, err := h.container.ProfileService.GetByNames(names)
if err != nil {
loggerInstance.Error("[ERROR] 获取配置文件失败: ",
zap.Error(err),
)
h.logger.Error("获取配置文件失败", zap.Error(err))
}
// 改造zap 兼容原有 INFO 日志格式
loggerInstance.Info("[INFO] 成功获取配置文件",
zap.Int("请求名称数:", len(names)),
zap.Int("返回结果数: ", len(profiles)),
)
h.logger.Info("成功获取配置文件", zap.Int("requested", len(names)), zap.Int("returned", len(profiles)))
c.JSON(http.StatusOK, profiles)
}
func GetMetaData(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
redisClient := redis.MustGetClient()
// GetMetaData 获取Yggdrasil元数据
func (h *YggdrasilHandler) GetMetaData(c *gin.Context) {
meta := gin.H{
"implementationName": "CellAuth",
"implementationVersion": "0.0.1",
@@ -595,26 +533,25 @@ func GetMetaData(c *gin.Context) {
"feature.non_email_login": true,
"feature.enable_profile_key": true,
}
skinDomains := []string{".hitwh.games", ".littlelan.cn"}
signature, err := service.GetPublicKeyFromRedisFunc(loggerInstance, redisClient)
signature, err := service.GetPublicKeyFromRedisFunc(h.logger, h.container.Redis)
if err != nil {
loggerInstance.Error("[ERROR] 获取公钥失败: ", zap.Error(err))
h.logger.Error("获取公钥失败", zap.Error(err))
standardResponse(c, http.StatusInternalServerError, nil, ErrInternalServer)
return
}
loggerInstance.Info("[INFO] 提供元数据")
c.JSON(http.StatusOK, gin.H{"meta": meta,
h.logger.Info("提供元数据")
c.JSON(http.StatusOK, gin.H{
"meta": meta,
"skinDomains": skinDomains,
"signaturePublickey": signature})
"signaturePublickey": signature,
})
}
func GetPlayerCertificates(c *gin.Context) {
loggerInstance := logger.MustGetLogger()
db := database.MustGetDB()
redisClient := redis.MustGetClient()
var uuid string
// GetPlayerCertificates 获取玩家证书
func (h *YggdrasilHandler) GetPlayerCertificates(c *gin.Context) {
authHeader := c.GetHeader("Authorization")
if authHeader == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Authorization header not provided"})
@@ -622,39 +559,36 @@ func GetPlayerCertificates(c *gin.Context) {
return
}
// 检查是否以 Bearer 开头并提取 sessionID
bearerPrefix := "Bearer "
if len(authHeader) < len(bearerPrefix) || authHeader[:len(bearerPrefix)] != bearerPrefix {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid Authorization format"})
c.Abort()
return
}
tokenID := authHeader[len(bearerPrefix):]
if tokenID == "" {
c.JSON(http.StatusUnauthorized, gin.H{"error": "Invalid Authorization format"})
c.Abort()
return
}
var err error
uuid, err = service.GetUUIDByAccessToken(db, tokenID)
uuid, err := h.container.TokenService.GetUUIDByAccessToken(tokenID)
if uuid == "" {
loggerInstance.Error("[ERROR] 获取玩家UUID失败: ", zap.Error(err))
h.logger.Error("获取玩家UUID失败", zap.Error(err))
standardResponse(c, http.StatusInternalServerError, nil, ErrInternalServer)
return
}
// 格式化UUID
uuid = utils.FormatUUID(uuid)
// 生成玩家证书
certificate, err := service.GeneratePlayerCertificate(db, loggerInstance, redisClient, uuid)
certificate, err := service.GeneratePlayerCertificate(h.container.DB, h.logger, h.container.Redis, uuid)
if err != nil {
loggerInstance.Error("[ERROR] 生成玩家证书失败: ", zap.Error(err))
h.logger.Error("生成玩家证书失败", zap.Error(err))
standardResponse(c, http.StatusInternalServerError, nil, ErrInternalServer)
return
}
loggerInstance.Info("[INFO] 成功生成玩家证书")
h.logger.Info("成功生成玩家证书")
c.JSON(http.StatusOK, certificate)
}