Skip to content

Commit d7985bb

Browse files
refactor(aegis): 重构密钥管理 SDK,解耦 Provider/Fetcher/Loader 架构 (#30)
1 parent 7bb1406 commit d7985bb

File tree

22 files changed

+486
-488
lines changed

22 files changed

+486
-488
lines changed

aegis/handler.go

Lines changed: 13 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ func (h *Handler) GetContext(c *gin.Context) {
169169

170170
// 获取 AuthFlow(内部会续期内存中的 ExpiresAt)
171171
flow := h.authenticateSvc.GetAndValidateFlow(c.Request.Context(), flowID)
172-
if flow.HasError() {
172+
if flow.Failed() {
173173
h.flowErrorResponse(c, flow)
174174
return
175175
}
@@ -216,7 +216,7 @@ func (h *Handler) GetConnections(c *gin.Context) {
216216

217217
// 获取 AuthFlow(内部会续期内存中的 ExpiresAt)
218218
flow := h.authenticateSvc.GetAndValidateFlow(c.Request.Context(), flowID)
219-
if flow.HasError() {
219+
if flow.Failed() {
220220
h.flowErrorResponse(c, flow)
221221
return
222222
}
@@ -254,7 +254,7 @@ func (h *Handler) Login(c *gin.Context) {
254254

255255
// 1. 获取 AuthFlow
256256
flow := h.authenticateSvc.GetAndValidateFlow(ctx, flowID)
257-
if flow.HasError() {
257+
if flow.Failed() {
258258
h.flowErrorResponse(c, flow)
259259
return
260260
}
@@ -406,12 +406,12 @@ func (h *Handler) GetIdentifyContext(c *gin.Context) {
406406
ctx := c.Request.Context()
407407

408408
flow := h.authenticateSvc.GetAndValidateFlow(ctx, flowID)
409-
if flow.HasError() {
409+
if flow.Failed() {
410410
h.flowErrorResponse(c, flow)
411411
return
412412
}
413413

414-
if !flow.HasIdentifiedUser() {
414+
if !flow.IdentifiedUser() {
415415
h.errorResponse(c, autherrors.NewInvalidRequest("no identified user"))
416416
return
417417
}
@@ -445,7 +445,7 @@ func (h *Handler) ConfirmIdentify(c *gin.Context) {
445445
ctx := c.Request.Context()
446446

447447
flow := h.authenticateSvc.GetAndValidateFlow(ctx, flowID)
448-
if flow.HasError() {
448+
if flow.Failed() {
449449
h.flowErrorResponse(c, flow)
450450
return
451451
}
@@ -457,7 +457,7 @@ func (h *Handler) ConfirmIdentify(c *gin.Context) {
457457
}
458458
}()
459459

460-
if !flow.HasIdentifiedUser() {
460+
if !flow.IdentifiedUser() {
461461
h.errorResponse(c, autherrors.NewInvalidRequest("no identified user"))
462462
return
463463
}
@@ -645,21 +645,21 @@ func (h *Handler) UserInfo(c *gin.Context) {
645645
}
646646

647647
uat := tc.UserAccessToken()
648-
if uat == nil || !uat.HasUser() {
648+
if uat == nil || !uat.Identified() {
649649
c.JSON(http.StatusUnauthorized, gin.H{
650650
"error": "invalid_token",
651651
"error_description": "token does not contain user info",
652652
})
653653
return
654654
}
655655

656-
email := uat.GetEmail()
657-
phone := uat.GetPhone()
656+
email := uat.Email()
657+
phone := uat.Phone()
658658

659659
resp := &UserInfoResponse{
660-
Sub: uat.GetOpenID(),
661-
Nickname: uat.GetNickname(),
662-
Picture: uat.GetPicture(),
660+
Sub: uat.OpenID(),
661+
Nickname: uat.Nickname(),
662+
Picture: uat.Picture(),
663663
Email: helpers.MaskEmail(email),
664664
EmailVerified: email != "",
665665
Phone: helpers.MaskPhone(phone),

aegis/init.go

Lines changed: 7 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,6 @@ func Initialize(hermesSvc *hermes.Service, userSvc *hermes.UserService, credenti
5151
cacheManager := cache.NewManager(hermesSvc, userSvc, redis)
5252

5353
// 3. 初始化 KeyStore
54-
watcher := key.NewSimpleWatcher()
55-
5654
ssoMasterKeyFetcher := func() ([][]byte, error) {
5755
masterKey, err := config.GetSSOMasterKey()
5856
if err != nil {
@@ -65,7 +63,7 @@ func Initialize(hermesSvc *hermes.Service, userSvc *hermes.UserService, credenti
6563
}
6664

6765
// 域密钥:clientID → domain.Main(id="aegis" 时返回 SSO master key)
68-
domainKeyStore := key.NewNamedStore("domain", key.FetcherFunc(func(ctx context.Context, clientID string) ([][]byte, error) {
66+
domainKeyProvider := key.LoadKeysFunc(func(ctx context.Context, clientID string) ([][]byte, error) {
6967
if clientID == token.SSOIssuer {
7068
return ssoMasterKeyFetcher()
7169
}
@@ -78,10 +76,10 @@ func Initialize(hermesSvc *hermes.Service, userSvc *hermes.UserService, credenti
7876
return nil, fmt.Errorf("get domain: %w", err)
7977
}
8078
return [][]byte{domain.Main}, nil
81-
}), watcher)
79+
})
8280

8381
// 服务密钥:audience → service.Key(id="aegis" 时返回 SSO master key)
84-
serviceKeyStore := key.NewNamedStore("service", key.FetcherFunc(func(ctx context.Context, audience string) ([][]byte, error) {
82+
serviceKeyProvider := key.LoadKeysFunc(func(ctx context.Context, audience string) ([][]byte, error) {
8583
if audience == token.SSOAudience {
8684
return ssoMasterKeyFetcher()
8785
}
@@ -90,19 +88,19 @@ func Initialize(hermesSvc *hermes.Service, userSvc *hermes.UserService, credenti
9088
return nil, fmt.Errorf("get service: %w", err)
9189
}
9290
return [][]byte{svc.Key}, nil
93-
}), watcher)
91+
})
9492

9593
// 应用密钥:clientID → app.Key
96-
appKeyStore := key.NewNamedStore("app", key.FetcherFunc(func(ctx context.Context, clientID string) ([][]byte, error) {
94+
appKeyProvider := key.LoadKeysFunc(func(ctx context.Context, clientID string) ([][]byte, error) {
9795
app, err := cacheManager.GetApplication(ctx, clientID)
9896
if err != nil {
9997
return nil, fmt.Errorf("get application: %w", err)
10098
}
10199
return [][]byte{app.Key}, nil
102-
}), watcher)
100+
})
103101

104102
// 4. 初始化 Token Service
105-
tokenSvc := token.NewService(cacheManager, domainKeyStore, serviceKeyStore, appKeyStore)
103+
tokenSvc := token.NewService(cacheManager, domainKeyProvider, serviceKeyProvider, appKeyProvider)
106104
logger.Info("[Auth] Token Service 初始化完成")
107105

108106
// 4. 初始化邮件发送器

aegis/internal/token/service.go

Lines changed: 31 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,8 @@ import (
66
"fmt"
77
"sync"
88

9+
"aidanwoods.dev/go-paseto"
10+
911
"github.com/heliannuuthus/helios/aegis/config"
1012
"github.com/heliannuuthus/helios/aegis/internal/cache"
1113
"github.com/heliannuuthus/helios/pkg/aegis/key"
@@ -19,9 +21,9 @@ type Service struct {
1921
issuer string
2022
cache *cache.Manager
2123

22-
domainKeyStore *key.Store // clientID → domain.Main (includes SSO with id="aegis")
23-
serviceKeyStore *key.Store // audience → service.Key (includes SSO with id="aegis")
24-
appKeyStore *key.Store // clientID → app.Key
24+
domainKeyProvider key.Provider // clientID → domain.Main (includes SSO with id="aegis")
25+
serviceKeyProvider key.Provider // audience → service.Key (includes SSO with id="aegis")
26+
appKeyProvider key.Provider // clientID → app.Key
2527

2628
domainSigners map[string]*Signer
2729
domainVerifiers map[string]*pkgtoken.Verifier
@@ -33,21 +35,21 @@ type Service struct {
3335

3436
func NewService(
3537
cache *cache.Manager,
36-
domainKeyStore *key.Store,
37-
serviceKeyStore *key.Store,
38-
appKeyStore *key.Store,
38+
domainKeyProvider key.Provider,
39+
serviceKeyProvider key.Provider,
40+
appKeyProvider key.Provider,
3941
) *Service {
4042
return &Service{
41-
issuer: config.GetIssuer(),
42-
cache: cache,
43-
domainKeyStore: domainKeyStore,
44-
serviceKeyStore: serviceKeyStore,
45-
appKeyStore: appKeyStore,
46-
domainSigners: make(map[string]*Signer),
47-
domainVerifiers: make(map[string]*pkgtoken.Verifier),
48-
serviceEncryptors: make(map[string]*Encryptor),
49-
serviceDecryptors: make(map[string]*pkgtoken.Decryptor),
50-
appVerifiers: make(map[string]*pkgtoken.Verifier),
43+
issuer: config.GetIssuer(),
44+
cache: cache,
45+
domainKeyProvider: domainKeyProvider,
46+
serviceKeyProvider: serviceKeyProvider,
47+
appKeyProvider: appKeyProvider,
48+
domainSigners: make(map[string]*Signer),
49+
domainVerifiers: make(map[string]*pkgtoken.Verifier),
50+
serviceEncryptors: make(map[string]*Encryptor),
51+
serviceDecryptors: make(map[string]*pkgtoken.Decryptor),
52+
appVerifiers: make(map[string]*pkgtoken.Verifier),
5153
}
5254
}
5355

@@ -131,14 +133,12 @@ func (s *Service) Verify(ctx context.Context, tokenString string) (Token, error)
131133
if err != nil {
132134
logger.Warnf("failed to get audience from token: %v", err)
133135
}
134-
claimsJSON, err := s.serviceDecryptor(audience).Decrypt(ctx, encryptedSub)
136+
innerToken, err := s.serviceDecryptor(audience).Decrypt(ctx, encryptedSub)
135137
if err != nil {
136138
return nil, fmt.Errorf("decrypt sub: %w", err)
137139
}
138140

139-
if err := s.unmarshalPayload(t, claimsJSON); err != nil {
140-
return nil, fmt.Errorf("unmarshal payload: %w", err)
141-
}
141+
s.applyPayload(t, innerToken)
142142
}
143143

144144
return t, nil
@@ -161,7 +161,7 @@ func (s *Service) domainSigner(clientID string) *Signer {
161161
return signer
162162
}
163163

164-
signer = NewSigner(s.domainKeyStore, clientID)
164+
signer = NewSigner(s.domainKeyProvider, clientID)
165165
s.domainSigners[clientID] = signer
166166
return signer
167167
}
@@ -181,7 +181,7 @@ func (s *Service) domainVerifier(clientID string) *pkgtoken.Verifier {
181181
return verifier
182182
}
183183

184-
verifier = pkgtoken.NewVerifier(s.domainKeyStore, clientID)
184+
verifier = pkgtoken.NewVerifier(s.domainKeyProvider, clientID)
185185
s.domainVerifiers[clientID] = verifier
186186
return verifier
187187
}
@@ -201,7 +201,7 @@ func (s *Service) serviceEncryptor(audience string) *Encryptor {
201201
return encryptor
202202
}
203203

204-
encryptor = NewEncryptor(s.serviceKeyStore, audience)
204+
encryptor = NewEncryptor(s.serviceKeyProvider, audience)
205205
s.serviceEncryptors[audience] = encryptor
206206
return encryptor
207207
}
@@ -221,7 +221,7 @@ func (s *Service) serviceDecryptor(audience string) *pkgtoken.Decryptor {
221221
return decryptor
222222
}
223223

224-
decryptor = pkgtoken.NewDecryptor(s.serviceKeyStore, audience)
224+
decryptor = pkgtoken.NewDecryptor(s.serviceKeyProvider, audience)
225225
s.serviceDecryptors[audience] = decryptor
226226
return decryptor
227227
}
@@ -241,7 +241,7 @@ func (s *Service) appVerifier(clientID string) *pkgtoken.Verifier {
241241
return verifier
242242
}
243243

244-
verifier = pkgtoken.NewVerifier(s.appKeyStore, clientID)
244+
verifier = pkgtoken.NewVerifier(s.appKeyProvider, clientID)
245245
s.appVerifiers[clientID] = verifier
246246
return verifier
247247
}
@@ -252,16 +252,16 @@ func (s *Service) appVerifier(clientID string) *pkgtoken.Verifier {
252252
func (*Service) marshalPayload(t tokendef.Token) ([]byte, bool) {
253253
switch v := t.(type) {
254254
case *tokendef.UserAccessToken:
255-
if !v.HasUser() {
255+
if !v.Identified() {
256256
return nil, false
257257
}
258-
data, err := v.MarshalUserPayload()
258+
data, err := v.MarshalIdentity()
259259
if err != nil {
260260
return nil, false
261261
}
262262
return data, true
263263
case *SSOToken:
264-
if !v.HasUser() {
264+
if v.GetIdentities() == nil {
265265
return nil, false
266266
}
267267
data, err := v.MarshalIdentities()
@@ -278,24 +278,11 @@ func (*Service) needsDecryption(tokenType tokendef.TokenType) bool {
278278
return tokenType == tokendef.TokenTypeUAT || tokenType == tokendef.TokenTypeSSO
279279
}
280280

281-
// unmarshalPayload decrypts and sets the payload on UAT and SSO tokens.
282-
func (*Service) unmarshalPayload(t tokendef.Token, data []byte) error {
281+
func (*Service) applyPayload(t tokendef.Token, inner *paseto.Token) {
283282
switch v := t.(type) {
284283
case *tokendef.UserAccessToken:
285-
info, err := tokendef.UnmarshalUserInfo(data)
286-
if err != nil {
287-
return err
288-
}
289-
v.SetUserInfo(info)
290-
return nil
284+
v.SetIdentity(inner)
291285
case *SSOToken:
292-
identities, err := UnmarshalIdentities(data)
293-
if err != nil {
294-
return err
295-
}
296-
v.SetIdentities(identities)
297-
return nil
298-
default:
299-
return fmt.Errorf("token type %s does not support payload decryption", t.Type())
286+
v.SetIdentities(inner)
300287
}
301288
}

aegis/internal/token/sso.go

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -87,14 +87,17 @@ func (s *SSOToken) MarshalIdentities() ([]byte, error) {
8787
return json.Marshal(s.identities)
8888
}
8989

90-
func (s *SSOToken) SetIdentities(identities map[string]string) {
90+
func (s *SSOToken) SetIdentities(t *paseto.Token) {
91+
claims := t.Claims()
92+
identities := make(map[string]string, len(claims))
93+
for k, v := range claims {
94+
if str, ok := v.(string); ok {
95+
identities[k] = str
96+
}
97+
}
9198
s.identities = identities
9299
}
93100

94-
func (s *SSOToken) HasUser() bool {
95-
return len(s.identities) > 0
96-
}
97-
98101
func (s *SSOToken) GetOpenID(domain string) string {
99102
if s.identities == nil {
100103
return ""
@@ -125,12 +128,3 @@ func ParseSSOToken(pasetoToken *paseto.Token) (*SSOToken, error) {
125128
Claims: claims,
126129
}, nil
127130
}
128-
129-
// UnmarshalIdentities deserializes identity mapping from decrypted inner token claims.
130-
func UnmarshalIdentities(data []byte) (map[string]string, error) {
131-
var identities map[string]string
132-
if err := json.Unmarshal(data, &identities); err != nil {
133-
return nil, fmt.Errorf("unmarshal identities: %w", err)
134-
}
135-
return identities, nil
136-
}

aegis/internal/types/authflow.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -362,8 +362,8 @@ func (f *AuthFlow) AllRequiredVerified() bool {
362362
return true
363363
}
364364

365-
// HasIdentifiedUser 是否存在待关联的已有用户(User 已设但 State 仍为 Initialized)
366-
func (f *AuthFlow) HasIdentifiedUser() bool {
365+
// IdentifiedUser 是否存在待关联的已有用户(User 已设但 State 仍为 Initialized)
366+
func (f *AuthFlow) IdentifiedUser() bool {
367367
return f.User != nil && f.State == FlowStateInitialized
368368
}
369369

@@ -416,8 +416,8 @@ func (f *AuthFlow) Fail(err AuthErrorInterface) {
416416
}
417417
}
418418

419-
// HasError 检查是否有错误
420-
func (f *AuthFlow) HasError() bool {
419+
// Failed 检查流程是否失败
420+
func (f *AuthFlow) Failed() bool {
421421
return f.Error != nil || f.State == FlowStateFailed
422422
}
423423

aegis/middleware/auth.go

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -60,15 +60,15 @@ func OptionalToken(v *web.Interpreter) gin.HandlerFunc {
6060
}
6161
}
6262

63-
// NewHermesKeyStore 创建 Hermes 使用的 KeyStore
64-
func NewHermesKeyStore() (*key.Store, error) {
63+
// NewHermesKeyProvider 创建 Hermes 使用的密钥 Provider
64+
func NewHermesKeyProvider() (key.Provider, error) {
6565
masterKey, err := hermesconfig.GetAegisSecretKeyBytes()
6666
if err != nil {
6767
return nil, fmt.Errorf("get hermes aegis secret key: %w", err)
6868
}
69-
return key.NewStore(key.FetcherFunc(func(ctx context.Context, id string) ([][]byte, error) {
70-
return [][]byte{masterKey}, nil
71-
}), nil), nil
69+
return key.LoadKeyFunc(func(_ context.Context, _ string) ([]byte, error) {
70+
return masterKey, nil
71+
}), nil
7272
}
7373

7474
func tokenPreview(tokenStr string, length int) string {

0 commit comments

Comments
 (0)