登录部分

This commit is contained in:
xmdhs 2023-09-03 23:19:38 +08:00
parent dc39b89657
commit 94bb72eae4
No known key found for this signature in database
GPG Key ID: E809D6D43DEFCC95
16 changed files with 174 additions and 81 deletions

View File

@ -25,6 +25,12 @@ func main() {
Node: 0, Node: 0,
Epoch: 1693645718534, Epoch: 1693645718534,
Debug: true, Debug: true,
Cache: struct {
Type string
Ram int
}{
Ram: 1000 * 1000 * 50,
},
} }
s, c, err := server.InitializeRoute(ctx, config) s, c, err := server.InitializeRoute(ctx, config)
if err != nil { if err != nil {

View File

@ -40,6 +40,10 @@ func (f *FastCache) Del(k []byte) error {
func (f *FastCache) Get(k []byte) ([]byte, error) { func (f *FastCache) Get(k []byte) ([]byte, error) {
b := f.c.GetBig(nil, k) b := f.c.GetBig(nil, k)
if b == nil {
return nil, nil
}
me := ttlCache{} me := ttlCache{}
err := binary.Unmarshal(b, &me) err := binary.Unmarshal(b, &me)
if err != nil { if err != nil {

View File

@ -67,11 +67,18 @@ var (
OnDelete: schema.SetNull, OnDelete: schema.SetNull,
}, },
}, },
Indexes: []*schema.Index{
{
Name: "user_email",
Unique: true,
Columns: []*schema.Column{UsersColumns[1]},
},
},
} }
// UserProfilesColumns holds the columns for the "user_profiles" table. // UserProfilesColumns holds the columns for the "user_profiles" table.
UserProfilesColumns = []*schema.Column{ UserProfilesColumns = []*schema.Column{
{Name: "id", Type: field.TypeInt, Increment: true}, {Name: "id", Type: field.TypeInt, Increment: true},
{Name: "name", Type: field.TypeString}, {Name: "name", Type: field.TypeString, Unique: true},
{Name: "uuid", Type: field.TypeString}, {Name: "uuid", Type: field.TypeString},
{Name: "user_profile", Type: field.TypeInt, Unique: true}, {Name: "user_profile", Type: field.TypeInt, Unique: true},
} }

View File

@ -5,6 +5,5 @@ package runtime
// The schema-stitching logic is generated in github.com/xmdhs/authlib-skin/db/ent/runtime.go // The schema-stitching logic is generated in github.com/xmdhs/authlib-skin/db/ent/runtime.go
const ( const (
Version = "v0.12.3" // Version of ent codegen. Version = "(devel)" // Version of ent codegen.
Sum = "h1:N5lO2EOrHpCH5HYfiMOCHYbo+oh5M8GjT0/cx5x6xkk=" // Sum of ent codegen.
) )

View File

@ -15,7 +15,7 @@ type UserProfile struct {
// Fields of the UserProfile. // Fields of the UserProfile.
func (UserProfile) Fields() []ent.Field { func (UserProfile) Fields() []ent.Field {
return []ent.Field{ return []ent.Field{
field.String("name"), field.String("name").Unique(),
field.String("uuid"), field.String("uuid"),
} }
} }

2
go.mod
View File

@ -9,6 +9,7 @@ require (
github.com/bwmarrin/snowflake v0.3.0 github.com/bwmarrin/snowflake v0.3.0
github.com/go-playground/validator/v10 v10.15.3 github.com/go-playground/validator/v10 v10.15.3
github.com/go-sql-driver/mysql v1.7.1 github.com/go-sql-driver/mysql v1.7.1
github.com/golang-jwt/jwt/v5 v5.0.0
github.com/google/uuid v1.3.1 github.com/google/uuid v1.3.1
github.com/google/wire v0.5.0 github.com/google/wire v0.5.0
github.com/julienschmidt/httprouter v1.3.0 github.com/julienschmidt/httprouter v1.3.0
@ -24,7 +25,6 @@ require (
github.com/go-openapi/inflect v0.19.0 // indirect github.com/go-openapi/inflect v0.19.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/golang-jwt/jwt/v5 v5.0.0 // indirect
github.com/golang/snappy v0.0.4 // indirect github.com/golang/snappy v0.0.4 // indirect
github.com/google/go-cmp v0.5.6 // indirect github.com/google/go-cmp v0.5.6 // indirect
github.com/hashicorp/hcl/v2 v2.13.0 // indirect github.com/hashicorp/hcl/v2 v2.13.0 // indirect

12
go.sum
View File

@ -54,6 +54,8 @@ github.com/google/wire v0.5.0 h1:I7ELFeVBr3yfPIcc8+MWvrjk+3VjbcSzoXm3JVa+jD8=
github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU= github.com/google/wire v0.5.0/go.mod h1:ngWDr9Qvq3yZA10YrxfyGELY/AFWGVpy9c1LTRi1EoU=
github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc= github.com/hashicorp/hcl/v2 v2.13.0 h1:0Apadu1w6M11dyGFxWnmhhcMjkbAiKCv7G1r/2QgCNc=
github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0= github.com/hashicorp/hcl/v2 v2.13.0/go.mod h1:e4z5nxYlWNPdDSNYX+ph14EvWYMFm3eP0zIUqPc2jr0=
github.com/inconshreveable/mousetrap v1.1.0 h1:wN+x4NVGpMsO7ErUn/mUI3vEoE6Jt13X2s0bqwp9tc8=
github.com/inconshreveable/mousetrap v1.1.0/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw=
github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U= github.com/julienschmidt/httprouter v1.3.0 h1:U0609e9tgbseu3rBINet9P48AI/D3oJs4dN7jwJOQ1U=
github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM= github.com/julienschmidt/httprouter v1.3.0/go.mod h1:JR6WtHb+2LUe8TCKY3cZOxFyyO8IZAc4RVcycCCAKdM=
github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= github.com/kr/pretty v0.1.0 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI=
@ -66,14 +68,22 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3v
github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k=
github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q= github.com/leodido/go-urn v1.2.4 h1:XlAE/cm/ms7TE/VMVoduSpNBoyc2dOxHs5MZSwAN63Q=
github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4= github.com/leodido/go-urn v1.2.4/go.mod h1:7ZrI8mTSeBSHl/UaRyKQW1qZeMgak41ANeCNaVckg+4=
github.com/mattn/go-runewidth v0.0.9 h1:Lm995f3rfxdpd6TSmuVCHVb/QhupuXlYr8sCI/QdE+0=
github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI=
github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y= github.com/mattn/go-sqlite3 v1.14.16 h1:yOQRA0RpS5PFz/oikGwBEqvAWhWg5ufRz4ETLjwpU1Y=
github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg= github.com/mattn/go-sqlite3 v1.14.16/go.mod h1:2eHXhiwb8IkHr+BDWZGa96P6+rkvnG63S2DGjv9HUNg=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7 h1:DpOJ2HYzCv8LZP15IdmG+YdwD2luVPHITV96TkirNBM=
github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo= github.com/mitchellh/go-wordwrap v0.0.0-20150314170334-ad45545899c7/go.mod h1:ZXFpozHsX6DPmq2I0TCekCxypsnAUbP2oI0UX1GXzOo=
github.com/olekukonko/tablewriter v0.0.5 h1:P2Ga83D34wi1o9J6Wh1mRuqd4mF/x/lgBS7N7AbDhec=
github.com/olekukonko/tablewriter v0.0.5/go.mod h1:hPp6KlRPjbx+hW8ykQs1w3UBbZlj6HuIJcUGPhkA7kY=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ= github.com/sergi/go-diff v1.0.0 h1:Kpca3qRNrduNnOQeazBd0ysaKrUJiIuISHxogkT9RPQ=
github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo=
github.com/spf13/cobra v1.7.0 h1:hyqWnYt1ZQShIddO5kBpj3vu05/++x6tJ6dg8EC572I=
github.com/spf13/cobra v1.7.0/go.mod h1:uLxZILRyS/50WlhOIKD7W6V5bgeIt+4sICxh6uRMrb0=
github.com/spf13/pflag v1.0.5 h1:iy+VFUOCP1a+8yFto/drg2CJ5u0yRoB7fZw3DKv/JXA=
github.com/spf13/pflag v1.0.5/go.mod h1:McXfInJRrz4CZXVZOBLb0bTZqETkiAhM9Iw0y3An2Bg=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
@ -107,6 +117,8 @@ golang.org/x/text v0.8.0 h1:57P1ETyNKtuIjB4SRd15iJxuhj8Gc416Y78H3qgMh68=
golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8= golang.org/x/text v0.8.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs=
golang.org/x/tools v0.8.1-0.20230428195545-5283a0178901 h1:0wxTF6pSjIIhNt7mo9GvjDfzyCOiWhmICgtO/Ah948s=
golang.org/x/tools v0.8.1-0.20230428195545-5283a0178901/go.mod h1:JxBZ99ISMI5ViVkT1tr6tdNmXeTrcpVSD3vZ1RsRdN4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=

View File

@ -1,10 +1,13 @@
package yggdrasil package yggdrasil
import ( import (
"encoding/json"
"errors"
"net/http" "net/http"
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
"github.com/xmdhs/authlib-skin/model/yggdrasil" "github.com/xmdhs/authlib-skin/model/yggdrasil"
yggdrasilS "github.com/xmdhs/authlib-skin/service/yggdrasil"
"github.com/xmdhs/authlib-skin/utils" "github.com/xmdhs/authlib-skin/utils"
) )
@ -13,11 +16,22 @@ func (y *Yggdrasil) Authenticate() httprouter.Handle {
cxt := r.Context() cxt := r.Context()
a, err := utils.DeCodeBody[yggdrasil.Authenticate](r.Body, y.validate) a, err := utils.DeCodeBody[yggdrasil.Authenticate](r.Body, y.validate)
if err != nil { if err != nil {
y.logger.InfoContext(cxt, err.Error()) y.logger.DebugContext(cxt, err.Error())
handleYgError(cxt, w, yggdrasil.Error{ErrorMessage: err.Error()}, 400) handleYgError(cxt, w, yggdrasil.Error{ErrorMessage: err.Error()}, 400)
return return
} }
t, err := y.yggdrasilService.Authenticate(cxt, a)
_ = a if err != nil {
if errors.Is(err, yggdrasilS.ErrPassWord) || errors.Is(err, yggdrasilS.ErrRate) {
y.logger.DebugContext(cxt, err.Error())
handleYgError(cxt, w, yggdrasil.Error{ErrorMessage: "Invalid credentials. Invalid username or password.", Error: "ForbiddenOperationException"}, 403)
return
}
y.logger.WarnContext(cxt, err.Error())
handleYgError(cxt, w, yggdrasil.Error{ErrorMessage: err.Error()}, 500)
return
}
b, _ := json.Marshal(t)
w.Write(b)
} }
} }

View File

@ -22,7 +22,7 @@ type Token struct {
AvailableProfiles []TokenProfile `json:"availableProfiles"` AvailableProfiles []TokenProfile `json:"availableProfiles"`
ClientToken string `json:"clientToken"` ClientToken string `json:"clientToken"`
SelectedProfile TokenProfile `json:"selectedProfile"` SelectedProfile TokenProfile `json:"selectedProfile"`
User TokenUser `json:"user"` User TokenUser `json:"user,omitempty"`
} }
type TokenProfile struct { type TokenProfile struct {

View File

@ -6,7 +6,7 @@ import (
"github.com/julienschmidt/httprouter" "github.com/julienschmidt/httprouter"
) )
func warpCtJSON(handle httprouter.Handle) httprouter.Handle { func warpHJSON(handle httprouter.Handle) httprouter.Handle {
return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) { return func(w http.ResponseWriter, r *http.Request, p httprouter.Params) {
w.Header().Set("Content-Type", "application/json; charset=utf-8") w.Header().Set("Content-Type", "application/json; charset=utf-8")
handle(w, r, p) handle(w, r, p)

View File

@ -10,7 +10,7 @@ import (
func NewRoute(yggService *yggdrasil.Yggdrasil, handel *handle.Handel) (*httprouter.Router, error) { func NewRoute(yggService *yggdrasil.Yggdrasil, handel *handle.Handel) (*httprouter.Router, error) {
r := httprouter.New() r := httprouter.New()
err := newYggdrasil(r) err := newYggdrasil(r, *yggService)
if err != nil { if err != nil {
return nil, fmt.Errorf("NewRoute: %w", err) return nil, fmt.Errorf("NewRoute: %w", err)
} }
@ -21,8 +21,8 @@ func NewRoute(yggService *yggdrasil.Yggdrasil, handel *handle.Handel) (*httprout
return r, nil return r, nil
} }
func newYggdrasil(r *httprouter.Router) error { func newYggdrasil(r *httprouter.Router, handelY yggdrasil.Yggdrasil) error {
r.POST("/api/authserver/authenticate", nil) r.POST("/api/authserver/authenticate", warpHJSON(handelY.Authenticate()))
return nil return nil
} }

View File

@ -3,7 +3,6 @@ package service
import ( import (
"context" "context"
"crypto/md5" "crypto/md5"
"database/sql"
"encoding/hex" "encoding/hex"
"errors" "errors"
"fmt" "fmt"
@ -11,7 +10,9 @@ import (
"time" "time"
"github.com/google/uuid" "github.com/google/uuid"
"github.com/xmdhs/authlib-skin/db/ent"
"github.com/xmdhs/authlib-skin/db/ent/user" "github.com/xmdhs/authlib-skin/db/ent/user"
"github.com/xmdhs/authlib-skin/db/ent/userprofile"
"github.com/xmdhs/authlib-skin/model" "github.com/xmdhs/authlib-skin/model"
"github.com/xmdhs/authlib-skin/utils" "github.com/xmdhs/authlib-skin/utils"
) )
@ -22,46 +23,48 @@ var (
) )
func (w *WebService) Reg(ctx context.Context, u model.User) error { func (w *WebService) Reg(ctx context.Context, u model.User) error {
tx, err := w.client.BeginTx(ctx, &sql.TxOptions{Isolation: sql.LevelReadCommitted})
if err != nil {
return fmt.Errorf("Reg: %w", err)
}
defer tx.Rollback()
count, err := tx.User.Query().Where(user.EmailEQ(u.Email)).ForUpdate().Count(ctx)
if err != nil {
return fmt.Errorf("Reg: %w", err)
}
if count != 0 {
return fmt.Errorf("Reg: %w", ErrExistUser)
}
p, s := utils.Argon2ID(u.Password)
du, err := w.client.User.Create().
SetEmail(u.Email).
SetPassword(p).
SetSalt(s).
SetRegTime(time.Now().Unix()).
SetState(0).Save(ctx)
if err != nil {
return fmt.Errorf("Reg: %w", err)
}
var userUuid string var userUuid string
if w.config.OfflineUUID { if w.config.OfflineUUID {
userUuid = uuidGen(u.Name) userUuid = uuidGen(u.Name)
} else { } else {
userUuid = strings.ReplaceAll(uuid.New().String(), "-", "") userUuid = strings.ReplaceAll(uuid.New().String(), "-", "")
} }
p, s := utils.Argon2ID(u.Password)
_, err = w.client.UserProfile.Create(). err := utils.WithTx(ctx, w.client, func(tx *ent.Tx) error {
SetUser(du). count, err := tx.User.Query().Where(user.EmailEQ(u.Email)).ForUpdate().Count(ctx)
SetName(u.Name). if err != nil {
SetUUID(userUuid). return err
Save(ctx) }
if err != nil { if count != 0 {
return fmt.Errorf("Reg: %w", err) return ErrExistUser
} }
err = tx.Commit() nameCount, err := tx.UserProfile.Query().Where(userprofile.NameEQ(u.Name)).ForUpdate().Count(ctx)
if err != nil {
return err
}
if nameCount != 0 {
return ErrExitsName
}
du, err := tx.User.Create().
SetEmail(u.Email).
SetPassword(p).
SetSalt(s).
SetRegTime(time.Now().Unix()).
SetState(0).Save(ctx)
if err != nil {
return err
}
_, err = tx.UserProfile.Create().
SetUser(du).
SetName(u.Name).
SetUUID(userUuid).
Save(ctx)
if err != nil {
return err
}
return nil
})
if err != nil { if err != nil {
return fmt.Errorf("Reg: %w", err) return fmt.Errorf("Reg: %w", err)
} }

View File

@ -5,6 +5,7 @@ import (
"encoding/binary" "encoding/binary"
"errors" "errors"
"fmt" "fmt"
"strconv"
"strings" "strings"
"time" "time"
@ -37,13 +38,13 @@ func (y *Yggdrasil) Authenticate(cxt context.Context, auth yggdrasil.Authenticat
} }
} }
b := make([]byte, 8) b := make([]byte, 8)
binary.BigEndian.PutUint64(b, uint64(time.Now().Add(10*time.Second).Unix())) binary.BigEndian.PutUint64(b, uint64(time.Now().Add(5*time.Second).Unix()))
err = y.cache.Put(key, b, time.Now().Add(20*time.Second)) err = y.cache.Put(key, b, time.Now().Add(20*time.Second))
if err != nil { if err != nil {
return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err) return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err)
} }
u, err := y.client.User.Query().Where(user.EmailEQ(auth.Username)).WithProfile().WithToken().First(cxt) u, err := y.client.User.Query().Where(user.EmailEQ(auth.Username)).WithProfile().First(cxt)
if err != nil { if err != nil {
var nf *ent.NotFoundError var nf *ent.NotFoundError
if errors.As(err, &nf) { if errors.As(err, &nf) {
@ -59,15 +60,59 @@ func (y *Yggdrasil) Authenticate(cxt context.Context, auth yggdrasil.Authenticat
clientToken = strings.ReplaceAll(uuid.New().String(), "-", "") clientToken = strings.ReplaceAll(uuid.New().String(), "-", "")
} }
var utoken *ent.UserToken
err = utils.WithTx(cxt, y.client, func(tx *ent.Tx) error {
utoken, err = tx.User.QueryToken(u).ForUpdate().First(cxt)
if err != nil {
var nf *ent.NotFoundError
if !errors.As(err, &nf) {
return err
}
}
if utoken == nil {
ut, err := tx.UserToken.Create().SetTokenID(1).Save(cxt)
if err != nil {
return err
}
err = tx.User.UpdateOne(u).SetToken(ut).Exec(cxt)
if err != nil {
return err
}
utoken = ut
}
return nil
})
if err != nil {
return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err)
}
claims := model.TokenClaims{ claims := model.TokenClaims{
Tid: u.Edges.Profile.UUID, Tid: strconv.FormatUint(utoken.TokenID, 10),
RegisteredClaims: jwt.RegisteredClaims{ RegisteredClaims: jwt.RegisteredClaims{
ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * 24 * time.Hour)), ExpiresAt: jwt.NewNumericDate(time.Now().Add(15 * 24 * time.Hour)),
Issuer: "authlib-skin", Issuer: "authlib-skin",
Subject: u.Edges.Profile.UUID, Subject: u.Edges.Profile.UUID,
IssuedAt: jwt.NewNumericDate(time.Now()),
}, },
} }
_ = claims token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
jwts, err := token.SignedString([]byte(y.config.JwtKey))
if err != nil {
return yggdrasil.Token{}, fmt.Errorf("Authenticate: %w", err)
}
p := yggdrasil.TokenProfile{
ID: u.Edges.Profile.UUID,
Name: u.Edges.Profile.Name,
}
return yggdrasil.Token{}, nil return yggdrasil.Token{
AccessToken: jwts,
AvailableProfiles: []yggdrasil.TokenProfile{p},
ClientToken: clientToken,
SelectedProfile: p,
User: yggdrasil.TokenUser{
ID: u.Edges.Profile.UUID,
Properties: []any{},
},
}, nil
} }

View File

@ -9,13 +9,13 @@ import (
type Yggdrasil struct { type Yggdrasil struct {
client *ent.Client client *ent.Client
cache cache.Cache cache cache.Cache
c config.Config config config.Config
} }
func NewYggdrasil(client *ent.Client, cache cache.Cache, c config.Config) *Yggdrasil { func NewYggdrasil(client *ent.Client, cache cache.Cache, c config.Config) *Yggdrasil {
return &Yggdrasil{ return &Yggdrasil{
client: client, client: client,
cache: cache, cache: cache,
c: c, config: c,
} }
} }

View File

@ -19,7 +19,7 @@ func Argon2ID(pass string) (password string, salt string) {
} }
func Argon2Compare(pass, hashPass string, salt string) bool { func Argon2Compare(pass, hashPass string, salt string) bool {
s, err := base64.StdEncoding.DecodeString(hashPass) s, err := base64.StdEncoding.DecodeString(salt)
if err != nil { if err != nil {
return false return false
} }

View File

@ -1,28 +1,31 @@
package utils package utils
// func WithTx(ctx context.Context, opts *sql.TxOptions, q mysql.Querier, db *sql.DB, f func(mysql.Querier) error) error { import (
// w, ok := q.(interface { "context"
// WithTx(tx *sql.Tx) *mysql.Queries "fmt"
// })
// var tx *sql.Tx "github.com/xmdhs/authlib-skin/db/ent"
// if ok { )
// var err error
// tx, err = db.BeginTx(ctx, opts) func WithTx(ctx context.Context, client *ent.Client, fn func(tx *ent.Tx) error) error {
// if err != nil { tx, err := client.Tx(ctx)
// return fmt.Errorf("WithTx: %w", err) if err != nil {
// } return err
// defer tx.Rollback() }
// q = w.WithTx(tx) defer func() {
// } if v := recover(); v != nil {
// err := f(q) tx.Rollback()
// if err != nil { panic(v)
// return fmt.Errorf("WithTx: %w", err) }
// } }()
// if tx != nil { if err := fn(tx); err != nil {
// err := tx.Commit() if rerr := tx.Rollback(); rerr != nil {
// if err != nil { err = fmt.Errorf("%w: rolling back transaction: %v", err, rerr)
// return fmt.Errorf("WithTx: %w", err) }
// } return err
// } }
// return nil if err := tx.Commit(); err != nil {
// } return fmt.Errorf("committing transaction: %w", err)
}
return nil
}