鉴权增加缓存

This commit is contained in:
xmdhs 2023-09-12 13:19:13 +08:00
parent a3fa8cbe47
commit 599c8535fc
No known key found for this signature in database
GPG Key ID: E809D6D43DEFCC95
5 changed files with 78 additions and 25 deletions

30
db/cache/cache.go vendored
View File

@ -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)
}

View File

@ -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)
}
}
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 nil, fmt.Errorf("Auth: %w", errors.Join(err, ErrTokenInvalid))
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

View File

@ -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 不相同")
}

View File

@ -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)
}

View File

@ -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)
}