feat(yggdrasil): implement standard error responses and UUID format improvements
- Add YggdrasilErrorResponse struct and standard error codes for protocol compliance - Change UUID storage from varchar(36) to varchar(32) for unsigned format - Add utility functions: GenerateUUID, FormatUUIDToNoDash, RandomHex - Support unsigned query parameter in GetProfileByUUID endpoint - Improve refresh token response with available profiles list - Fix key pair retrieval to use correct database column (rsa_private_key) - Update UUID validator to accept both 32-char and 36-char formats - Add SignStringWithProfileRSA method for profile-specific signing - Fix profile assignment validation in refresh token flow
This commit is contained in:
@@ -4,12 +4,12 @@ import (
|
||||
"carrotskin/internal/model"
|
||||
"carrotskin/internal/repository"
|
||||
"carrotskin/pkg/auth"
|
||||
"carrotskin/pkg/utils"
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/jackc/pgx/v5"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
@@ -63,9 +63,13 @@ func (s *tokenServiceRedis) Create(ctx context.Context, userID int64, UUID strin
|
||||
}
|
||||
}
|
||||
|
||||
// 生成ClientToken
|
||||
// 生成ClientToken(使用32字符十六进制字符串)
|
||||
if clientToken == "" {
|
||||
clientToken = uuid.New().String()
|
||||
var err error
|
||||
clientToken, err = utils.RandomHex(16) // 16字节 = 32字符十六进制
|
||||
if err != nil {
|
||||
return selectedProfileID, availableProfiles, "", "", fmt.Errorf("生成ClientToken失败: %w", err)
|
||||
}
|
||||
}
|
||||
|
||||
// 获取或创建Client
|
||||
@@ -73,7 +77,10 @@ func (s *tokenServiceRedis) Create(ctx context.Context, userID int64, UUID strin
|
||||
existingClient, err := s.clientRepo.FindByClientToken(ctx, clientToken)
|
||||
if err != nil {
|
||||
// Client不存在,创建新的
|
||||
clientUUID := uuid.New().String()
|
||||
clientUUID, err := utils.RandomHex(16) // 16字节 = 32字符十六进制
|
||||
if err != nil {
|
||||
return selectedProfileID, availableProfiles, "", "", fmt.Errorf("生成ClientUUID失败: %w", err)
|
||||
}
|
||||
client = &model.Client{
|
||||
UUID: clientUUID,
|
||||
ClientToken: clientToken,
|
||||
@@ -173,6 +180,11 @@ func (s *tokenServiceRedis) Create(ctx context.Context, userID int64, UUID strin
|
||||
return selectedProfileID, availableProfiles, accessToken, clientToken, nil
|
||||
}
|
||||
|
||||
// CreateWithProfile 创建Token并绑定指定Profile(使用JWT + Redis存储)
|
||||
func (s *tokenServiceRedis) CreateWithProfile(ctx context.Context, userID int64, profileUUID string, clientToken string) (*model.Profile, []*model.Profile, string, string, error) {
|
||||
return s.Create(ctx, userID, profileUUID, clientToken)
|
||||
}
|
||||
|
||||
// Validate 验证Token(使用JWT验证 + Redis存储验证)
|
||||
func (s *tokenServiceRedis) Validate(ctx context.Context, accessToken, clientToken string) bool {
|
||||
// 设置超时上下文
|
||||
|
||||
Reference in New Issue
Block a user