diff --git a/api/app/init.go b/api/app/init.go index 30ba67c..1caf969 100644 --- a/api/app/init.go +++ b/api/app/init.go @@ -9,13 +9,14 @@ package app import ( "github.com/veypi/OneAuth/cfg" + "github.com/veypi/OneAuth/libs/auth" "github.com/veypi/OneAuth/models" "github.com/vyes/vigo" "github.com/vyes/vigo/contrib/crud" ) var Router = vigo.NewRouter() -var appRouter = Router.SubRouter(":app_id") +var appRouter = Router.SubRouter(":app_id").UseBefore(auth.Check("app", ":app_id", 2)) func init() { crud.All(appRouter.SubRouter("resource"), cfg.DB, models.Resource{}) diff --git a/api/init.go b/api/init.go index c8f5ff7..b98a768 100644 --- a/api/init.go +++ b/api/init.go @@ -11,11 +11,12 @@ import ( "github.com/veypi/OneAuth/api/app" "github.com/veypi/OneAuth/api/token" "github.com/veypi/OneAuth/api/user" + "github.com/veypi/OneAuth/libs/auth" "github.com/vyes/vigo" "github.com/vyes/vigo/contrib/common" ) -var Router = vigo.NewRouter().UseAfter(common.JsonResponse, common.JsonErrorResponse) +var Router = vigo.NewRouter().UseBefore(auth.CheckJWT).UseAfter(common.JsonResponse, common.JsonErrorResponse) var ( _ = Router.Extend("user", user.Router) diff --git a/api/token/base.go b/api/token/base.go index 042108a..3d46d95 100644 --- a/api/token/base.go +++ b/api/token/base.go @@ -8,7 +8,7 @@ import ( "github.com/vyes/vigo" ) -var _ = Router.Patch("/:token_id", tokenPatch) +// var _ = Router.Patch("/:token_id", tokenPatch) type patchOpts struct { ID string `json:"id" parse:"path@token_id"` diff --git a/api/token/create.go b/api/token/create.go index c1ae401..4a1c742 100644 --- a/api/token/create.go +++ b/api/token/create.go @@ -30,7 +30,7 @@ type postOpts struct { Device *string `json:"device" parse:"json"` } -var _ = Router.Post("/", tokenPost) +var _ = Router.Post("/", vigo.SkipBefore, tokenPost) // for user login app func tokenPost(x *vigo.X) (any, error) { diff --git a/api/token/get.go b/api/token/get.go index d45d405..8f14aa9 100644 --- a/api/token/get.go +++ b/api/token/get.go @@ -17,7 +17,7 @@ type getOpts struct { ID string `json:"id" parse:"path@token_id"` } -var _ = Router.Get("/:token_id", tokenGet) +// var _ = Router.Get("/:token_id", tokenGet) func tokenGet(x *vigo.X) (any, error) { opts := &getOpts{} @@ -36,7 +36,7 @@ type listOpts struct { AppID string `json:"app_id" gorm:"index;type:varchar(32)" parse:"query"` } -var _ = Router.Get("/", tokenList) +// var _ = Router.Get("/", tokenList) func tokenList(x *vigo.X) (any, error) { opts := &listOpts{} diff --git a/api/user/create.go b/api/user/create.go index 954e857..3b5cd45 100644 --- a/api/user/create.go +++ b/api/user/create.go @@ -23,7 +23,7 @@ import ( "gorm.io/gorm" ) -var _ = Router.Post("/", userPost) +var _ = Router.Post("/", vigo.SkipBefore, publicLimits, userPost) type postOpts struct { Username string `json:"username" gorm:"varchar(100);unique;default:not null" parse:"json"` diff --git a/api/user/init.go b/api/user/init.go index 6b3414c..74e278a 100644 --- a/api/user/init.go +++ b/api/user/init.go @@ -9,14 +9,15 @@ package user import ( "github.com/veypi/OneAuth/cfg" + "github.com/veypi/OneAuth/libs/auth" "github.com/veypi/OneAuth/models" "github.com/vyes/vigo" "github.com/vyes/vigo/contrib/crud" ) var Router = vigo.NewRouter() +var userRouter = Router.SubRouter("/:user_id").UseBefore(userGet) func init() { - crud.All(Router.SubRouter("/:user_id/user_role"), cfg.DB, models.UserRole{}) - + crud.All(Router.SubRouter("/:user_id/user_role"), cfg.DB, models.UserRole{}).UseBefore(auth.Check("user", "", 4)) } diff --git a/api/user/login.go b/api/user/login.go index eddfe60..e8f241b 100644 --- a/api/user/login.go +++ b/api/user/login.go @@ -17,10 +17,19 @@ import ( "github.com/veypi/OneAuth/libs/utils" "github.com/veypi/OneAuth/models" "github.com/vyes/vigo" + "github.com/vyes/vigo/contrib/limiter" "github.com/vyes/vigo/logv" ) -var _ = Router.Post("/login", userLogin) +var publicLimits = limiter.NewAdvancedRequestLimiter(limiter.LimiterConfig{ + Window: time.Minute * 5, + MaxRequests: 20, + MinInterval: time.Second * 3, +}).Limit + +var _ = Router.Post("/login", + vigo.SkipBefore, publicLimits, + userLogin) type loginOpts struct { UserName string `json:"username" parse:"json"` diff --git a/api/user/user.go b/api/user/user.go index 5585de5..b92be1f 100644 --- a/api/user/user.go +++ b/api/user/user.go @@ -8,7 +8,7 @@ import ( "github.com/vyes/vigo/contrib/crud" ) -var _ = Router.Delete("/:user_id", auth.Check("user", "user_id", auth.DoDelete), userDelete) +var _ = Router.Delete("/:user_id", auth.Check("user", "user_id", auth.DoDelete, checkOwner), userDelete) func userDelete(x *vigo.X) (any, error) { data := &models.User{} @@ -16,65 +16,22 @@ func userDelete(x *vigo.X) (any, error) { return data, err } -var _ = Router.Get("/:user_id", auth.Check("user", "user_id", auth.DoRead), userGet) +var _ = Router.Get("/:user_id", auth.Check("user", "user_id", auth.DoRead, checkOwner), vigo.DiliverData) -type getOpts struct { - ID string `json:"id" parse:"path@user_id"` +func checkOwner(x *vigo.X, data any) bool { + u, ok1 := data.(*models.User) + return ok1 && u.ID == x.Params.Get("user_id") } func userGet(x *vigo.X) (any, error) { - opts := &getOpts{} - err := x.Parse(opts) - if err != nil { - return nil, err - } data := &models.User{} - - err = cfg.DB().Where("id = ?", opts.ID).First(data).Error - + err := cfg.DB().Where("id = ?", x.Params.Get("user_id")).First(data).Error return data, err } -var _ = Router.Get("/", "list user", listOpts{}, auth.Check("user", "", auth.DoUpdate), crud.List(cfg.DB, &models.User{})) - -type listOpts struct { - Username *string `json:"username" parse:"query"` - Nickname *string `json:"nickname" parse:"query"` - Email *string `json:"email" parse:"query"` - Phone *string `json:"phone" parse:"query"` - Status *uint `json:"status" parse:"query"` -} +var _ = Router.Get("/", "list user", auth.Check("user", "", auth.DoUpdate), crud.List(cfg.DB, &models.User{})) -func userList(x *vigo.X) (any, error) { - opts := &listOpts{} - err := x.Parse(opts) - if err != nil { - return nil, err - } - data := make([]*models.User, 0, 10) - - query := cfg.DB() - if opts.Username != nil { - query = query.Where("username LIKE ?", opts.Username) - } - if opts.Nickname != nil { - query = query.Where("nickname LIKE ?", opts.Nickname) - } - if opts.Email != nil { - query = query.Where("email LIKE ?", opts.Email) - } - if opts.Phone != nil { - query = query.Where("phone LIKE ?", opts.Phone) - } - if opts.Status != nil { - query = query.Where("status = ?", opts.Status) - } - err = query.Find(&data).Error - - return data, err -} - -var _ = Router.Patch("/:user_id", auth.Check("user", "user_id", auth.DoUpdate), userPatch) +var _ = Router.Patch("/:user_id", auth.Check("user", "user_id", auth.DoUpdate, checkOwner), userPatch) type patchOpts struct { ID string `json:"id" parse:"path@user_id"` @@ -87,18 +44,14 @@ type patchOpts struct { Status *uint `json:"status" parse:"json"` } -func userPatch(x *vigo.X) (any, error) { +func userPatch(x *vigo.X, args any) (any, error) { opts := &patchOpts{} err := x.Parse(opts) if err != nil { return nil, err } - data := &models.User{} + data := args.(*models.User) - err = cfg.DB().Where("id = ?", opts.ID).First(data).Error - if err != nil { - return nil, err - } optsMap := make(map[string]any) if opts.Username != nil { optsMap["username"] = opts.Username diff --git a/cfg/cfg.go b/cfg/cfg.go index ac88881..1a31546 100644 --- a/cfg/cfg.go +++ b/cfg/cfg.go @@ -21,4 +21,6 @@ var Config = &Options{ TokenExpire: time.Second * 10, ID: "test", Key: "asdfghjklqwertyuiopzxcvbnm1234567890", + DSN: "root:123456@tcp(127.0.0.1:3306)/test?charset=utf8&parseTime=True&loc=Local", + DB: "mysql", } diff --git a/libs/auth/jwt.go b/libs/auth/jwt.go index 7136439..9d02ed9 100644 --- a/libs/auth/jwt.go +++ b/libs/auth/jwt.go @@ -86,20 +86,33 @@ func CheckJWT(x *vigo.X) (any, error) { return checkJWT(x) } -func Check(target string, pid string, l AuthLevel) func(x *vigo.X) (any, error) { - return func(x *vigo.X) (any, error) { - claims, err := checkJWT(x) - if err != nil { - return nil, err - // return nil, err +type CustomCheckFunc = func(x *vigo.X, data any) bool + +func Check(target string, pid string, l AuthLevel, funcs ...CustomCheckFunc) func(x *vigo.X, data any) (any, error) { + return func(x *vigo.X, data any) (any, error) { + var err error + claims, ok := x.Get("token").(*Claims) + if !ok { + claims, err = checkJWT(x) + if err != nil { + return nil, err + } } tid := "" - if pid != "" { - tid = x.Params.Get(pid) + if strings.HasPrefix(pid, "@") { + tid, _ = x.Get(pid[1:]).(string) + } + if strings.HasPrefix(pid, ":") { + tid = x.Params.Get(pid[1:]) } if !claims.Access.Check(target, tid, l) { - return nil, AuthNoPerm + err = AuthNoPerm + } + for _, fn := range funcs { + if fn(x, data) { + return data, nil + } } - return claims, nil + return data, err } } diff --git a/ui/env.js b/ui/env.js index 79cc7b6..8066815 100644 --- a/ui/env.js +++ b/ui/env.js @@ -6,7 +6,8 @@ export default ($env) => { token.setBaseUrl($env.root) token.wrapAxios($env.$axios) $env.$G.token = token - $env.$G.user = token.body() + let user = token.body() + $env.$G.user = user $env.$router.addRoutes(routes) @@ -18,17 +19,18 @@ export default ($env) => { if (token.isExpired()) { token.logout(to.fullPath) } + if (!token.check('app', '', 2)) { + next('/') + } } else { next(); } }; $env.$axios.interceptors.response.use(function(response) { - if (response?.data) { - return response.data - } - return response; + return response?.data || response; }, function(error) { - let data = error.response ? error.response.data : error.response - return Promise.reject(data.message || data); + console.error('Axios Error:', error); + error = error?.response?.data || error?.response || error + return Promise.reject(error.message || error); }); } diff --git a/ui/page/index.html b/ui/page/index.html index cf41483..5ac2f5b 100644 --- a/ui/page/index.html +++ b/ui/page/index.html @@ -1,696 +1,9 @@ - + -
-