From 599c8535fcd12d0cfed3faabe8c5530c597bc597 Mon Sep 17 00:00:00 2001 From: xmdhs Date: Tue, 12 Sep 2023 13:19:13 +0800 Subject: [PATCH] =?UTF-8?q?=E9=89=B4=E6=9D=83=E5=A2=9E=E5=8A=A0=E7=BC=93?= =?UTF-8?q?=E5=AD=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- db/cache/cache.go | 30 +++++++++++++++++++++++++++++- service/utils/auth.go | 31 +++++++++++++++++++++++-------- service/yggdrasil/session.go | 17 ++++++++--------- service/yggdrasil/texture.go | 4 ++-- service/yggdrasil/user.go | 21 ++++++++++++++++----- 5 files changed, 78 insertions(+), 25 deletions(-) diff --git a/db/cache/cache.go b/db/cache/cache.go index 99b77c2..1ea41b5 100644 --- a/db/cache/cache.go +++ b/db/cache/cache.go @@ -1,9 +1,37 @@ package cache -import "time" +import ( + "encoding/json" + "time" +) type Cache interface { Del(k []byte) error Get(k []byte) ([]byte, error) Put(k []byte, v []byte, timeOut time.Time) error } + +type CacheHelp[T any] struct { + Cache +} + +func (c CacheHelp[T]) Get(k []byte) (T, error) { + var t T + b, err := c.Cache.Get(k) + if err != nil { + return t, err + } + err = json.Unmarshal(b, &t) + if err != nil { + return t, err + } + return t, nil +} + +func (c CacheHelp[T]) Put(k []byte, v T, timeOut time.Time) error { + b, err := json.Marshal(v) + if err != nil { + return err + } + return c.Cache.Put(k, b, timeOut) +} diff --git a/service/utils/auth.go b/service/utils/auth.go index 69d5116..ffce23b 100644 --- a/service/utils/auth.go +++ b/service/utils/auth.go @@ -9,6 +9,7 @@ import ( "time" "github.com/golang-jwt/jwt/v5" + "github.com/xmdhs/authlib-skin/db/cache" "github.com/xmdhs/authlib-skin/db/ent" "github.com/xmdhs/authlib-skin/db/ent/user" "github.com/xmdhs/authlib-skin/db/ent/usertoken" @@ -20,7 +21,7 @@ var ( ErrTokenInvalid = errors.New("token 无效") ) -func Auth(ctx context.Context, t yggdrasil.ValidateToken, client *ent.Client, pubkey *rsa.PublicKey, tmpInvalid bool) (*model.TokenClaims, error) { +func Auth(ctx context.Context, t yggdrasil.ValidateToken, client *ent.Client, c cache.Cache, pubkey *rsa.PublicKey, tmpInvalid bool) (*model.TokenClaims, error) { token, err := jwt.ParseWithClaims(t.AccessToken, &model.TokenClaims{}, func(t *jwt.Token) (interface{}, error) { return pubkey, nil }) @@ -50,16 +51,30 @@ func Auth(ctx context.Context, t yggdrasil.ValidateToken, client *ent.Client, pu return nil, fmt.Errorf("Auth: %w", ErrTokenInvalid) } } - - ut, err := client.UserToken.Query().Where(usertoken.HasUserWith(user.ID(claims.UID))).First(ctx) - if err != nil { - var ne *ent.NotFoundError - if !errors.As(err, &ne) { - return nil, fmt.Errorf("Auth: %w", errors.Join(err, ErrTokenInvalid)) + tokenID, err := func() (uint64, error) { + c := cache.CacheHelp[uint64]{Cache: c} + key := []byte("auth" + strconv.Itoa(claims.UID)) + t, err := c.Get(key) + if err != nil { + return 0, err } + if t != 0 { + return t, nil + } + ut, err := client.UserToken.Query().Where(usertoken.HasUserWith(user.ID(claims.UID))).First(ctx) + if err != nil { + var ne *ent.NotFoundError + if !errors.As(err, &ne) { + return 0, errors.Join(err, ErrTokenInvalid) + } + return 0, err + } + return ut.TokenID, c.Put(key, ut.TokenID, time.Now().Add(20*time.Minute)) + }() + if err != nil { return nil, fmt.Errorf("Auth: %w", err) } - if strconv.FormatUint(ut.TokenID, 10) != claims.Tid { + if strconv.FormatUint(tokenID, 10) != claims.Tid { return nil, fmt.Errorf("Auth: %w", ErrTokenInvalid) } return claims, nil diff --git a/service/yggdrasil/session.go b/service/yggdrasil/session.go index 98ccfa5..ad8441b 100644 --- a/service/yggdrasil/session.go +++ b/service/yggdrasil/session.go @@ -2,11 +2,10 @@ package yggdrasil import ( "context" - "encoding/json" "fmt" "time" - "github.com/samber/lo" + "github.com/xmdhs/authlib-skin/db/cache" "github.com/xmdhs/authlib-skin/db/ent/userprofile" "github.com/xmdhs/authlib-skin/model" "github.com/xmdhs/authlib-skin/model/yggdrasil" @@ -21,17 +20,17 @@ type sessionWithIP struct { func (y *Yggdrasil) SessionJoin(ctx context.Context, s yggdrasil.Session, ip string) error { t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{ AccessToken: s.AccessToken, - }, y.client, &y.prikey.PublicKey, true) + }, y.client, y.cache, &y.prikey.PublicKey, true) if err != nil { return fmt.Errorf("SessionJoin: %w", err) } if s.SelectedProfile != t.Subject { return fmt.Errorf("SessionJoin: %w", sutils.ErrTokenInvalid) } - err = y.cache.Put([]byte("session"+s.ServerID), lo.Must1(json.Marshal(sessionWithIP{ + err = cache.CacheHelp[sessionWithIP]{Cache: y.cache}.Put([]byte("session"+s.ServerID), sessionWithIP{ user: *t, IP: ip, - })), time.Now().Add(30*time.Second)) + }, time.Now().Add(30*time.Second)) if err != nil { return fmt.Errorf("SessionJoin: %w", err) } @@ -39,10 +38,10 @@ func (y *Yggdrasil) SessionJoin(ctx context.Context, s yggdrasil.Session, ip str } func (y *Yggdrasil) HasJoined(ctx context.Context, username, serverId string, ip string, host string) (yggdrasil.UserInfo, error) { - b := lo.Must1(y.cache.Get([]byte("session" + serverId))) - sIP := sessionWithIP{} - lo.Must0(json.Unmarshal(b, &sIP)) - + sIP, err := cache.CacheHelp[sessionWithIP]{Cache: y.cache}.Get([]byte("session" + serverId)) + if err != nil { + return yggdrasil.UserInfo{}, fmt.Errorf("HasJoined: %w", err) + } if ip != "" && ip != sIP.IP { return yggdrasil.UserInfo{}, fmt.Errorf("ip 不相同") } diff --git a/service/yggdrasil/texture.go b/service/yggdrasil/texture.go index 877a8a6..356c5b3 100644 --- a/service/yggdrasil/texture.go +++ b/service/yggdrasil/texture.go @@ -79,7 +79,7 @@ func (y *Yggdrasil) delTexture(ctx context.Context, userProfileID int, textureTy } func (y *Yggdrasil) DelTexture(ctx context.Context, uuid string, token string, textureType string) error { - t, err := utilsService.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token}, y.client, &y.prikey.PublicKey, true) + t, err := utilsService.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token}, y.client, y.cache, &y.prikey.PublicKey, true) if err != nil { return fmt.Errorf("DelTexture: %w", err) } @@ -98,7 +98,7 @@ func (y *Yggdrasil) DelTexture(ctx context.Context, uuid string, token string, t } func (y *Yggdrasil) PutTexture(ctx context.Context, token string, texturebyte []byte, model string, uuid string, textureType string) error { - t, err := utilsService.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token}, y.client, &y.prikey.PublicKey, true) + t, err := utilsService.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token}, y.client, y.cache, &y.prikey.PublicKey, true) if err != nil { return fmt.Errorf("PutTexture: %w", err) } diff --git a/service/yggdrasil/user.go b/service/yggdrasil/user.go index d87df11..766099c 100644 --- a/service/yggdrasil/user.go +++ b/service/yggdrasil/user.go @@ -85,7 +85,10 @@ func (y *Yggdrasil) Authenticate(cxt context.Context, auth yggdrasil.Authenticat if err != nil { return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err) } - + err = y.cache.Del([]byte("auth" + strconv.Itoa(u.ID))) + if err != nil { + return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err) + } jwts, err := newJwtToken(y.prikey, strconv.FormatUint(utoken.TokenID, 10), clientToken, u.Edges.Profile.UUID, u.ID) if err != nil { return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err) @@ -107,7 +110,7 @@ func (y *Yggdrasil) Authenticate(cxt context.Context, auth yggdrasil.Authenticat } func (y *Yggdrasil) ValidateToken(ctx context.Context, t yggdrasil.ValidateToken) error { - _, err := sutils.Auth(ctx, t, y.client, &y.prikey.PublicKey, true) + _, err := sutils.Auth(ctx, t, y.client, y.cache, &y.prikey.PublicKey, true) if err != nil { return fmt.Errorf("ValidateToken: %w", err) } @@ -131,11 +134,15 @@ func (y *Yggdrasil) SignOut(ctx context.Context, t yggdrasil.Pass) error { if err != nil { return fmt.Errorf("SignOut: %w", err) } + err = y.cache.Del([]byte("auth" + strconv.Itoa(u.ID))) + if err != nil { + return fmt.Errorf("SignOut: %w", err) + } return nil } func (y *Yggdrasil) Invalidate(ctx context.Context, accessToken string) error { - t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{AccessToken: accessToken}, y.client, &y.prikey.PublicKey, true) + t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{AccessToken: accessToken}, y.client, y.cache, &y.prikey.PublicKey, true) if err != nil { return fmt.Errorf("Invalidate: %w", err) } @@ -143,11 +150,15 @@ func (y *Yggdrasil) Invalidate(ctx context.Context, accessToken string) error { if err != nil { return fmt.Errorf("Invalidate: %w", err) } + err = y.cache.Del([]byte("auth" + strconv.Itoa(t.UID))) + if err != nil { + return fmt.Errorf("Invalidate: %w", err) + } return nil } func (y *Yggdrasil) Refresh(ctx context.Context, token yggdrasil.RefreshToken) (yggdrasil.Token, error) { - t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token.AccessToken, ClientToken: token.ClientToken}, y.client, &y.prikey.PublicKey, false) + t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token.AccessToken, ClientToken: token.ClientToken}, y.client, y.cache, &y.prikey.PublicKey, false) if err != nil { return yggdrasil.Token{}, fmt.Errorf("Refresh: %w", err) } @@ -257,7 +268,7 @@ func (y *Yggdrasil) BatchProfile(ctx context.Context, names []string) ([]yggdras } func (y *Yggdrasil) PlayerCertificates(ctx context.Context, token string) (yggdrasil.Certificates, error) { - t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token}, y.client, &y.prikey.PublicKey, false) + t, err := sutils.Auth(ctx, yggdrasil.ValidateToken{AccessToken: token}, y.client, y.cache, &y.prikey.PublicKey, false) if err != nil { return yggdrasil.Certificates{}, fmt.Errorf("PlayerCertificates: %w", err) }