From 3b9cbe1c1b3dddb40d32bf1056bfaf8adcd48f3a Mon Sep 17 00:00:00 2001 From: veypi Date: Fri, 27 Jun 2025 20:38:58 +0800 Subject: [PATCH] feat: change axios and add auth refresh --- README.md | 13 ++-- api/app/app.go | 6 +- api/token/create.go | 4 +- api/user/create.go | 2 +- cfg/cfg.go | 17 +++-- errs/errors.go | 96 ++------------------------ libs/auth/jwt.go | 30 +++++---- ui/c/app/create.html | 2 +- ui/layout/default.html | 2 +- ui/page/app.html | 2 +- ui/page/app/auth.html | 2 +- ui/page/app/main.html | 2 +- ui/page/app/user.html | 17 ++--- ui/page/login.html | 5 +- ui/page/profile.html | 4 +- ui/root.html | 14 +++- ui/token.js | 150 ++++++++++++++++++++++++++++++++++------- 17 files changed, 196 insertions(+), 172 deletions(-) diff --git a/README.md b/README.md index 79f248d..75bcbd0 100644 --- a/README.md +++ b/README.md @@ -4,18 +4,13 @@ [Demo](https://oa.veypi.com) +## 使用方法 -## Auth +## 引入 + /init.go -code用来兑换本身应用token和兑换其他应用付出权限token -oa code 可以用来生成其他code和刷新本身code +```go - -### 依赖库 - -```bash -docker run -dit --name=tsdb -v /Users/veypi/test/vdb:/victoria-metrics-data -p 8428:8428 victoriametrics/victoria-metrics -search.latencyOffset=1s -nats-server -c ./script/nats.cfg ``` diff --git a/api/app/app.go b/api/app/app.go index 2d547e8..4991606 100644 --- a/api/app/app.go +++ b/api/app/app.go @@ -6,7 +6,6 @@ import ( "time" "github.com/veypi/OneAuth/cfg" - "github.com/veypi/OneAuth/errs" "github.com/veypi/OneAuth/libs/auth" "github.com/veypi/OneAuth/models" "github.com/veypi/OneBD/rest" @@ -19,7 +18,7 @@ var _ = Router.Get("/:app_id/key", auth.Check("app", "app_id", auth.DoDelete), a func appKey(x *rest.X) (any, error) { id := x.Params.Get("app_id") if id == "" { - return nil, errs.ArgsInvalid.WithStr("missing app_id") + return nil, rest.ErrArgMissing.WithArgs("app_id") } data := &models.App{} data.ID = id @@ -65,8 +64,9 @@ func appList(x *rest.X) (any, error) { models.App UserStatus string `json:"user_status"` }, 0, 10) - token, err := auth.CheckJWT(x) + tokenAny, err := auth.CheckJWT(x) if err == nil { + token := tokenAny.(*auth.Claims) uid := token.UID query := cfg.DB().Table("apps").Select("apps.*,app_users.status user_status") if opts.Name != nil { diff --git a/api/token/create.go b/api/token/create.go index f32b717..407b422 100644 --- a/api/token/create.go +++ b/api/token/create.go @@ -68,7 +68,7 @@ func tokenPost(x *rest.X) (any, error) { claim.UID = refresh.UID claim.Name = refresh.Name claim.Icon = refresh.Icon - claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Minute * 10)) + claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(cfg.Config.TokenExpire)) if typ == "app" { if refresh.AID == aid { // refresh token @@ -113,7 +113,7 @@ func tokenPost(x *rest.X) (any, error) { claim.UID = refresh.UID claim.Name = refresh.Name claim.Icon = refresh.Icon - claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(time.Minute * 10)) + claim.ExpiresAt = jwt.NewNumericDate(time.Now().Add(cfg.Config.TokenExpire)) claim.Access = auth.Access{ {Name: "fs", TID: "/", Level: auth.Do}, } diff --git a/api/user/create.go b/api/user/create.go index 7ad5588..0e2bd7b 100644 --- a/api/user/create.go +++ b/api/user/create.go @@ -60,7 +60,7 @@ func userPost(x *rest.X) (any, error) { } ncode, err := utils.AesDecrypt([]byte(data.Code), code, []byte(data.Salt)) if err != nil || ncode != data.ID { - return nil, rest.ErrInternalServer.AppendString("code decrypt failed") + return nil, rest.ErrInternalServer.WithString("code decrypt failed") } if opts.Nickname != nil { data.Nickname = *opts.Nickname diff --git a/cfg/cfg.go b/cfg/cfg.go index bcb24a1..6aeee60 100644 --- a/cfg/cfg.go +++ b/cfg/cfg.go @@ -7,11 +7,18 @@ package cfg +import "time" + type Options struct { - DSN string `json:"dsn"` // Data Source Name - DB string `json:"db"` // DB type: mysql, postgres, sqlite - ID string `json:"id"` - Key string `json:"key"` + DSN string `json:"dsn"` // Data Source Name + DB string `json:"db"` // DB type: mysql, postgres, sqlite + ID string `json:"id"` + Key string `json:"key"` + TokenExpire time.Duration `json:"token_expire"` // Token expiration time in seconds } -var Config = &Options{} +var Config = &Options{ + TokenExpire: time.Minute / 2, + ID: "test", + Key: "asdfghjklqwertyuiopzxcvbnm1234567890", +} diff --git a/errs/errors.go b/errs/errors.go index 8e8c7c0..66a9506 100644 --- a/errs/errors.go +++ b/errs/errors.go @@ -7,96 +7,12 @@ package errs -import ( - "errors" - "fmt" - "net/http" - - "github.com/go-sql-driver/mysql" - "github.com/veypi/OneBD/rest" - "github.com/veypi/utils/logv" - "gorm.io/gorm" -) - -func JsonResponse(x *rest.X, data any) error { - x.WriteHeader(http.StatusOK) - return x.JSON(map[string]any{"code": 0, "data": data}) -} - -func JsonErrorResponse(x *rest.X, err error) { - code, msg := errIter(err) - x.WriteHeader(code / 100) - x.JSON(map[string]any{"code": code, "err": msg}) -} - -func errIter(err error) (code int, msg string) { - code = 50000 - msg = err.Error() - switch e := err.(type) { - case *CodeErr: - code = e.Code - msg = e.Msg - case *mysql.MySQLError: - if e.Number == 1062 { - code = DuplicateKey.Code - msg = DuplicateKey.Msg - } else { - logv.Warn().Msgf("unhandled db error %d: %s", e.Number, err) - msg = "db error" - } - case interface{ Unwrap() error }: - code, _ = errIter(e.Unwrap()) - default: - if errors.Is(e, gorm.ErrRecordNotFound) { - code = ResourceNotFound.Code - msg = ResourceNotFound.Msg - } else { - logv.Warn().Msgf("unhandled error type: %T\n%s", err, err) - msg = e.Error() - } - } - return -} - -type CodeErr struct { - Code int - Msg string -} - -func (c *CodeErr) Error() string { - return fmt.Sprintf("code: %d, msg: %s", c.Code, c.Msg) -} - -func (c *CodeErr) WithErr(e error) error { - nerr := &CodeErr{ - Code: c.Code, - Msg: fmt.Errorf("%s: %w", c.Msg, e).Error(), - } - return nerr -} - -func (c *CodeErr) WithStr(m string) error { - nerr := &CodeErr{ - Code: c.Code, - Msg: fmt.Errorf("%s: %s", c.Msg, m).Error(), - } - return nerr -} - -// New creates a new CodeMsg. -func New(code int, msg string) *CodeErr { - return &CodeErr{Code: code, Msg: msg} -} +import "github.com/veypi/OneBD/rest" var ( - ArgsInvalid = New(40001, "args invalid") - DuplicateKey = New(40002, "duplicate key") - AuthNotFound = New(40100, "auth not found") - AuthFailed = New(40101, "auth failed") - AuthExpired = New(40102, "auth expired") - AuthInvalid = New(40103, "auth invalid") - AuthNoPerm = New(40104, "no permission") - NotFound = New(40400, "not found") - ResourceNotFound = New(40401, "resource not found") - DBError = New(50010, "db error") + AuthNotFound = rest.NewError("auth not found").WithCode(40100) + AuthFailed = rest.NewError("auth failed").WithCode(40101) + AuthExpired = rest.NewError("auth expired").WithCode(40102) + AuthInvalid = rest.NewError("auth invalid").WithCode(40103) + AuthNoPerm = rest.NewError("auth no permission").WithCode(40104) ) diff --git a/libs/auth/jwt.go b/libs/auth/jwt.go index 64e2368..32b9b13 100644 --- a/libs/auth/jwt.go +++ b/libs/auth/jwt.go @@ -8,7 +8,6 @@ package auth import ( - "context" "errors" "fmt" "strings" @@ -50,40 +49,45 @@ func ParseJwt(tokenString string) (*Claims, error) { return claims, nil } -func CheckJWT(x *rest.X) (*Claims, error) { +func checkJWT(x *rest.X) (*Claims, error) { authHeader := x.Request.Header.Get("Authorization") if authHeader == "" { - return nil, errs.AuthNotFound + authHeader = x.Request.URL.Query().Get("Authorization") + if authHeader == "" { + return nil, errs.AuthNotFound + } } // Token is typically in the format "Bearer " tokenString := strings.TrimPrefix(authHeader, "Bearer ") - if tokenString == authHeader { - return nil, errs.AuthInvalid - } // Parse the token claims, err := ParseJwt(tokenString) if err != nil { return nil, err } + x.Set("token", claims) return claims, nil } -func Check(target string, pid string, l AuthLevel) func(x *rest.X) error { - return func(x *rest.X) error { - claims, err := CheckJWT(x) +func CheckJWT(x *rest.X) (any, error) { + return checkJWT(x) +} + +func Check(target string, pid string, l AuthLevel) func(x *rest.X) (any, error) { + return func(x *rest.X) (any, error) { + claims, err := checkJWT(x) if err != nil { - // return err + return nil, err + // return nil, err } tid := "" if pid != "" { tid = x.Params.Get(pid) } if !claims.Access.Check(target, tid, l) { - // return errs.AuthNoPerm + // return nil, errs.AuthNoPerm } - x.Request = x.Request.WithContext(context.WithValue(x.Request.Context(), "uid", claims.UID)) - return nil + return claims, nil } } diff --git a/ui/c/app/create.html b/ui/c/app/create.html index 2d98191..8f5187b 100644 --- a/ui/c/app/create.html +++ b/ui/c/app/create.html @@ -179,7 +179,7 @@ init_url: init_url, }; - api.Post('/api/app', newApp) + $api.Post('/api/app', newApp) .then(() => { onsuccess() name = ''; diff --git a/ui/layout/default.html b/ui/layout/default.html index 8dbc4c3..19bd6bd 100644 --- a/ui/layout/default.html +++ b/ui/layout/default.html @@ -117,7 +117,7 @@ token.logout() } user = token.body() - api.wrapFetch(token.fetch()) + token.wrapAxios($axios) $env.Guser = user diff --git a/ui/page/app.html b/ui/page/app.html index 0f0b073..b0055d1 100644 --- a/ui/page/app.html +++ b/ui/page/app.html @@ -414,7 +414,7 @@ }; sync = () => { show_create_app = false - api.Get('/api/app').then((res) => { + $api.Get('/api/app').then((res) => { apps = res; loading = false; }); diff --git a/ui/page/app/auth.html b/ui/page/app/auth.html index 458816e..42f45f1 100644 --- a/ui/page/app/auth.html +++ b/ui/page/app/auth.html @@ -107,7 +107,7 @@ access_api = { next: async (page, size) => { console.log(id) - return await api.Get(access_url, {query: {page, size, app_id: id, role_id: selected_role.id || ''}}) + return await $api.Get(access_url, {query: {page, size, app_id: id, role_id: selected_role.id || ''}}) } } diff --git a/ui/page/app/main.html b/ui/page/app/main.html index d31bdfd..cd50fdd 100644 --- a/ui/page/app/main.html +++ b/ui/page/app/main.html @@ -304,7 +304,7 @@ return } - api.Get(`/api/app/${id}`) + $api.Get(`/api/app/${id}`) .then((data) => { Object.assign(app, data) document.title = `${app.name} - 项目主页` diff --git a/ui/page/app/user.html b/ui/page/app/user.html index 9aa91b1..f1c1103 100644 --- a/ui/page/app/user.html +++ b/ui/page/app/user.html @@ -84,15 +84,6 @@ rows = [] - update_status = (id, n, old) => { - api.app.user(app.id).update(id, n).then(() => { - msg.Info('修改成功') - }).catch(() => { - const a = rows.find(a => a.id = id) || {} - a.status = old - }) - } - user_role_data = [] selected = {} show_user = async (row) => { @@ -105,7 +96,7 @@ } user_role_api = { next: async (page, size) => { - return await api.Get(user_role_url, {query: {page, size}}) + return await $api.Get(user_role_url, {query: {page, size}}) } } @@ -116,7 +107,7 @@ cancel: true, persistent: true }).onOk(() => { - api.user.reset(id).then(() => { + $api.user.reset(id).then(() => { msg.Info('重置成功 ') }).catch((e) => { msg.Warn('失败 ' + e) @@ -132,11 +123,11 @@ history.back() return } - api.Get(`/api/app/${id}`) + $api.Get(`/api/app/${id}`) .then((data) => { Object.assign(app, data) document.title = `${app.name} - 项目主页` - api.Get(`/api/user/`).then((e) => { + $api.Get(`/api/user/`).then((e) => { rows = e console.log(e) }) diff --git a/ui/page/login.html b/ui/page/login.html index 44c85ca..7884185 100644 --- a/ui/page/login.html +++ b/ui/page/login.html @@ -6,7 +6,6 @@ 登录与注册 -