feat(auth): implement yggdrasil authenticate endpoint

This commit is contained in:
2025-06-14 21:51:36 +03:00
parent 54ce479a6e
commit 4d42cfff2d
5 changed files with 209 additions and 8 deletions

View File

@@ -0,0 +1,67 @@
package core
import (
"context"
"errors"
"strings"
"gitea.mrixs.me/minecraft-platform/backend/internal/database"
"gitea.mrixs.me/minecraft-platform/backend/internal/models"
"github.com/google/uuid"
"golang.org/x/crypto/bcrypt"
)
var (
ErrInvalidCredentials = errors.New("invalid credentials")
)
type AuthService struct {
UserRepo *database.UserRepository
}
// Authenticate проверяет учетные данные и возвращает данные для ответа Yggdrasil.
func (s *AuthService) Authenticate(ctx context.Context, req models.AuthenticateRequest) (*models.AuthenticateResponse, error) {
// 1. Найти пользователя по имени
user, err := s.UserRepo.GetUserByUsername(ctx, req.Username)
if err != nil {
if errors.Is(err, database.ErrUserNotFound) {
return nil, ErrInvalidCredentials
}
return nil, err // Другая ошибка БД
}
// 2. Сравнить хеш пароля из БД с паролем из запроса
err = bcrypt.CompareHashAndPassword([]byte(user.PasswordHash), []byte(req.Password))
if err != nil {
// Если хеши не совпадают, bcrypt возвращает ошибку
return nil, ErrInvalidCredentials
}
// 3. Сгенерировать новый accessToken
accessToken := uuid.New().String()
// 4. Сохранить токен в БД
err = s.UserRepo.CreateAccessToken(ctx, user.ID, accessToken, req.ClientToken)
if err != nil {
return nil, err
}
// 5. Сформировать ответ согласно спецификации Yggdrasil
profile := models.ProfileInfo{
ID: strings.ReplaceAll(user.UUID.String(), "-", ""), // UUID без дефисов
Name: user.Username,
}
response := &models.AuthenticateResponse{
AccessToken: accessToken,
ClientToken: req.ClientToken,
AvailableProfiles: []models.ProfileInfo{profile},
SelectedProfile: profile,
User: &models.UserProperty{
ID: user.UUID.String(),
Properties: []any{},
},
}
return response, nil
}