session
This commit is contained in:
parent
bfaf686ff0
commit
f6a914fd85
54
handle/yggdrasil/session.go
Normal file
54
handle/yggdrasil/session.go
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"net/http"
|
||||||
|
|
||||||
|
"github.com/julienschmidt/httprouter"
|
||||||
|
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
||||||
|
sutils "github.com/xmdhs/authlib-skin/service/utils"
|
||||||
|
"github.com/xmdhs/authlib-skin/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
func (y *Yggdrasil) SessionJoin() httprouter.Handle {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
|
ctx := r.Context()
|
||||||
|
a, has := getAnyModel[yggdrasil.Session](ctx, w, r.Body, y.validate, y.logger)
|
||||||
|
if !has {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
ip, err := utils.GetIP(r, y.config.RaelIP)
|
||||||
|
if err != nil {
|
||||||
|
y.logger.WarnContext(ctx, err.Error())
|
||||||
|
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
err = y.yggdrasilService.SessionJoin(ctx, a, ip)
|
||||||
|
if err != nil {
|
||||||
|
if errors.Is(err, sutils.ErrTokenInvalid) {
|
||||||
|
y.logger.DebugContext(ctx, err.Error())
|
||||||
|
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: "Invalid token.", Error: "ForbiddenOperationException"}, 403)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
y.logger.WarnContext(ctx, err.Error())
|
||||||
|
handleYgError(ctx, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
w.WriteHeader(204)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func (y *Yggdrasil) HasJoined() httprouter.Handle {
|
||||||
|
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
|
ctx := r.Context()
|
||||||
|
name := r.FormValue("username")
|
||||||
|
serverId := r.FormValue("serverId")
|
||||||
|
ip := r.FormValue("ip")
|
||||||
|
if name == "" || serverId == "" {
|
||||||
|
y.logger.DebugContext(ctx, "name 或 serverID 为空")
|
||||||
|
w.WriteHeader(204)
|
||||||
|
return
|
||||||
|
}
|
||||||
|
y.yggdrasilService.HasJoined(ctx, name, serverId, ip, r.Host)
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,7 @@ import (
|
|||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"github.com/go-playground/validator/v10"
|
"github.com/go-playground/validator/v10"
|
||||||
|
"github.com/xmdhs/authlib-skin/config"
|
||||||
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
||||||
yggdrasilS "github.com/xmdhs/authlib-skin/service/yggdrasil"
|
yggdrasilS "github.com/xmdhs/authlib-skin/service/yggdrasil"
|
||||||
"github.com/xmdhs/authlib-skin/utils"
|
"github.com/xmdhs/authlib-skin/utils"
|
||||||
@ -16,13 +17,15 @@ type Yggdrasil struct {
|
|||||||
logger *slog.Logger
|
logger *slog.Logger
|
||||||
validate *validator.Validate
|
validate *validator.Validate
|
||||||
yggdrasilService *yggdrasilS.Yggdrasil
|
yggdrasilService *yggdrasilS.Yggdrasil
|
||||||
|
config config.Config
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewYggdrasil(logger *slog.Logger, validate *validator.Validate, yggdrasilService *yggdrasilS.Yggdrasil) *Yggdrasil {
|
func NewYggdrasil(logger *slog.Logger, validate *validator.Validate, yggdrasilService *yggdrasilS.Yggdrasil, config config.Config) *Yggdrasil {
|
||||||
return &Yggdrasil{
|
return &Yggdrasil{
|
||||||
logger: logger,
|
logger: logger,
|
||||||
validate: validate,
|
validate: validate,
|
||||||
yggdrasilService: yggdrasilService,
|
yggdrasilService: yggdrasilService,
|
||||||
|
config: config,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -57,3 +57,9 @@ type UserProperties struct {
|
|||||||
Value string `json:"value"`
|
Value string `json:"value"`
|
||||||
Signature string `json:"signature,omitempty"`
|
Signature string `json:"signature,omitempty"`
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type Session struct {
|
||||||
|
AccessToken string `json:"accessToken" validate:"required,jwt"`
|
||||||
|
SelectedProfile string `json:"selectedProfile" validate:"required,uuid"`
|
||||||
|
ServerID string `json:"serverId"`
|
||||||
|
}
|
||||||
|
@ -35,6 +35,9 @@ func newYggdrasil(r *httprouter.Router, handelY yggdrasil.Yggdrasil) error {
|
|||||||
r.GET("/api/yggdrasil/sessionserver/session/minecraft/profile/:uuid", warpHJSON(handelY.GetProfile()))
|
r.GET("/api/yggdrasil/sessionserver/session/minecraft/profile/:uuid", warpHJSON(handelY.GetProfile()))
|
||||||
r.POST("/api/yggdrasil/api/profiles/minecraft", warpHJSON(handelY.BatchProfile()))
|
r.POST("/api/yggdrasil/api/profiles/minecraft", warpHJSON(handelY.BatchProfile()))
|
||||||
|
|
||||||
|
r.POST("/api/yggdrasil/sessionserver/session/minecraft/join", warpHJSON(handelY.SessionJoin()))
|
||||||
|
r.GET("/api/yggdrasil/sessionserver/session/minecraft/hasJoined", warpHJSON(handelY.SessionJoin()))
|
||||||
|
|
||||||
r.GET("/api/yggdrasil", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
r.GET("/api/yggdrasil", func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
|
||||||
w.Write([]byte(`{
|
w.Write([]byte(`{
|
||||||
"meta": {
|
"meta": {
|
||||||
|
@ -44,7 +44,7 @@ func InitializeRoute(ctx context.Context, c config.Config) (*http.Server, func()
|
|||||||
return nil, nil, err
|
return nil, nil, err
|
||||||
}
|
}
|
||||||
yggdrasilYggdrasil := yggdrasil.NewYggdrasil(client, cache, c, privateKey)
|
yggdrasilYggdrasil := yggdrasil.NewYggdrasil(client, cache, c, privateKey)
|
||||||
yggdrasil3 := yggdrasil2.NewYggdrasil(logger, validate, yggdrasilYggdrasil)
|
yggdrasil3 := yggdrasil2.NewYggdrasil(logger, validate, yggdrasilYggdrasil, c)
|
||||||
webService := service.NewWebService(c, client)
|
webService := service.NewWebService(c, client)
|
||||||
handel := handle.NewHandel(webService, validate, c, logger)
|
handel := handle.NewHandel(webService, validate, c, logger)
|
||||||
router, err := route.NewRoute(yggdrasil3, handel)
|
router, err := route.NewRoute(yggdrasil3, handel)
|
||||||
|
64
service/yggdrasil/session.go
Normal file
64
service/yggdrasil/session.go
Normal file
@ -0,0 +1,64 @@
|
|||||||
|
package yggdrasil
|
||||||
|
|
||||||
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"github.com/samber/lo"
|
||||||
|
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
|
||||||
|
"github.com/xmdhs/authlib-skin/model"
|
||||||
|
"github.com/xmdhs/authlib-skin/model/yggdrasil"
|
||||||
|
sutils "github.com/xmdhs/authlib-skin/service/utils"
|
||||||
|
)
|
||||||
|
|
||||||
|
type sessionWithIP struct {
|
||||||
|
user model.TokenClaims
|
||||||
|
IP string
|
||||||
|
}
|
||||||
|
|
||||||
|
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)
|
||||||
|
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{
|
||||||
|
user: *t,
|
||||||
|
IP: ip,
|
||||||
|
})), time.Now().Add(30*time.Second))
|
||||||
|
if err != nil {
|
||||||
|
return fmt.Errorf("SessionJoin: %w", err)
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
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))
|
||||||
|
|
||||||
|
if ip != "" && ip != sIP.IP {
|
||||||
|
return yggdrasil.UserInfo{}, fmt.Errorf("ip 不相同")
|
||||||
|
}
|
||||||
|
|
||||||
|
up, err := y.client.UserProfile.Query().Where(userprofile.Name(username)).Only(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return yggdrasil.UserInfo{}, fmt.Errorf("HasJoined: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
if up.UUID != sIP.user.Subject {
|
||||||
|
return yggdrasil.UserInfo{}, fmt.Errorf("uuid 不相同")
|
||||||
|
}
|
||||||
|
|
||||||
|
u, err := y.GetProfile(ctx, up.UUID, false, host)
|
||||||
|
if err != nil {
|
||||||
|
return yggdrasil.UserInfo{}, fmt.Errorf("HasJoined: %w", err)
|
||||||
|
}
|
||||||
|
return u, nil
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user