鉴权增加缓存
This commit is contained in:
parent
a3fa8cbe47
commit
599c8535fc
30
db/cache/cache.go
vendored
30
db/cache/cache.go
vendored
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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 不相同")
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user