From e081e4ecb6a9c4c23b3df8ab161fa5701e56012b Mon Sep 17 00:00:00 2001 From: veypi Date: Sat, 27 Nov 2021 12:28:45 +0800 Subject: [PATCH] =?UTF-8?q?=E7=94=A8=E6=88=B7=E6=9D=83=E9=99=90=E7=BC=96?= =?UTF-8?q?=E8=BE=91=20=E7=99=BB=E5=BD=95=E8=B7=B3=E8=BD=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/app/router.go | 34 ++++++++ api/role/role.go | 17 +++- api/role/router.go | 3 +- api/role/user.go | 86 +++++++++++++++++++ api/token/token.go | 2 +- api/user/user.go | 10 +-- go.mod | 2 +- libs/auth/auth.go | 28 ++++--- main.go | 3 +- oaf/src/api/index.ts | 2 + oaf/src/api/interface.ts | 4 - oaf/src/api/role.ts | 19 ++++- oaf/src/api/token.ts | 18 ++++ oaf/src/api/user.ts | 11 ++- oaf/src/components/app.vue | 4 +- oaf/src/components/avatar/avatar.vue | 2 +- oaf/src/components/connectors/roleauths.vue | 7 +- oaf/src/components/connectors/roleusers.vue | 87 +++++++++++++++++++- oaf/src/components/fullscreen/fullscreen.vue | 24 +++--- oaf/src/components/siderframe.vue | 56 ++++++------- oaf/src/components/userSelect.vue | 54 ++++++++++++ oaf/src/store/index.ts | 2 +- oaf/src/theme/index.ts | 12 +-- oaf/src/views/app.vue | 2 +- oaf/src/views/app/roles.vue | 21 ++++- oaf/src/views/home.vue | 8 -- oaf/src/views/login.vue | 41 ++++++--- oaf/vite.config.ts | 8 -- oalib/config.go | 4 +- oalib/main.go | 38 +++++++-- sub/static/index.html | 8 +- sub/web.go | 19 +++-- 32 files changed, 496 insertions(+), 140 deletions(-) create mode 100644 api/role/user.go create mode 100644 oaf/src/api/token.ts create mode 100644 oaf/src/components/userSelect.vue diff --git a/api/app/router.go b/api/app/router.go index cd8064b..3659fe9 100644 --- a/api/app/router.go +++ b/api/app/router.go @@ -1,12 +1,46 @@ package app import ( + "errors" + "github.com/veypi/OneAuth/cfg" + "github.com/veypi/OneAuth/models" + "github.com/veypi/OneAuth/oalib" "github.com/veypi/OneBD" "github.com/veypi/OneBD/rfc" + "github.com/veypi/utils/jwt" ) func Router(r OneBD.Router) { r.Set("/", appHandlerP, rfc.MethodPost, rfc.MethodGet) r.Set("/:uuid", appHandlerP, rfc.MethodGet, rfc.MethodPatch) r.Set("/:uuid/user/:id", auHandlerP, rfc.MethodAll) + r.Set("/:uuid/ping", ping, rfc.MethodGet) +} + +func ping(m OneBD.Meta) { + var err error + defer func() { + if err != nil { + m.WriteHeader(rfc.StatusBadRequest) + m.Write([]byte(err.Error())) + } else { + m.WriteHeader(rfc.StatusOK) + m.Write([]byte("ok")) + } + }() + t := m.GetHeader("auth_token") + uuid := m.Params("uuid") + a := &models.App{} + err = cfg.DB().Where("UUID = ?", uuid).First(a).Error + if err != nil { + return + } + p := &oalib.PayLoad{} + ok, err := jwt.ParseToken(t, p, []byte(a.Key)) + if err != nil { + return + } + if !ok { + err = errors.New("invalid key") + } } diff --git a/api/role/role.go b/api/role/role.go index f9a302e..cbaa819 100644 --- a/api/role/role.go +++ b/api/role/role.go @@ -1,12 +1,14 @@ package role import ( + "errors" "github.com/veypi/OneAuth/cfg" "github.com/veypi/OneAuth/libs/auth" "github.com/veypi/OneAuth/libs/base" "github.com/veypi/OneAuth/libs/oerr" "github.com/veypi/OneAuth/models" "github.com/veypi/OneBD" + "github.com/veypi/utils/log" "gorm.io/gorm" ) @@ -98,18 +100,25 @@ func (h *roleHandler) Patch() (interface{}, error) { } func (h *roleHandler) Delete() (interface{}, error) { - if !h.GetAuth(auth.Role).CanDelete() { + log.Warn().Msgf("%s %d", h.UUID, h.GetAuth(auth.Role, h.UUID)) + if !h.GetAuth(auth.Role, h.UUID).CanDelete() { return nil, oerr.NoAuth } rid := h.Meta().ParamsInt("id") - if rid <= 2 { - return nil, oerr.NoAuth + if rid <= 0 { + return nil, oerr.ApiArgsError } role := &models.Role{} role.ID = uint(rid) - err := cfg.DB().Where(role).First(role).Error + err := cfg.DB().Preload("Users").Where(role).First(role).Error if err != nil { return nil, err } + if role.AppUUID != h.UUID { + return nil, oerr.NoAuth + } + if len(role.Users) != 0 { + return nil, errors.New("关联用户未删除") + } return nil, cfg.DB().Delete(role).Error } diff --git a/api/role/router.go b/api/role/router.go index f07a454..4f91870 100644 --- a/api/role/router.go +++ b/api/role/router.go @@ -8,5 +8,6 @@ import ( func Router(r OneBD.Router) { r.Set("/", roleP, rfc.MethodGet, rfc.MethodPost) r.Set("/:id", roleP, rfc.MethodGet, rfc.MethodDelete, rfc.MethodPatch) - r.Set("/:id/auth/:aid", roleP, rfc.MethodGet) + r.Set("/:id/user/", ruP, rfc.MethodGet) + r.Set("/:id/user/:uid", ruP, rfc.MethodPost, rfc.MethodDelete) } diff --git a/api/role/user.go b/api/role/user.go new file mode 100644 index 0000000..4401ede --- /dev/null +++ b/api/role/user.go @@ -0,0 +1,86 @@ +package role + +import ( + "github.com/veypi/OneAuth/cfg" + "github.com/veypi/OneAuth/libs/auth" + "github.com/veypi/OneAuth/libs/base" + "github.com/veypi/OneAuth/libs/oerr" + "github.com/veypi/OneAuth/models" + "github.com/veypi/OneBD" + "github.com/veypi/OneBD/core" +) + +/** +* @name: user +* @author: veypi +* @date: 2021-11-23 10:17 +* @description:user +**/ + +var ruP = OneBD.NewHandlerPool(func() core.Handler { + return &roleUserHandler{} +}) + +type roleUserHandler struct { + base.AppHandler +} + +func (h *roleUserHandler) Get() (interface{}, error) { + if !h.GetAuth(auth.Role, h.UUID).CanRead() { + return nil, oerr.NoAuth + } + id := h.Meta().ParamsInt("id") + if id <= 0 { + return nil, oerr.ApiArgsMissing + } + r := &models.Role{} + err := cfg.DB().Preload("Users").Where("ID = ?", id).First(r).Error + if err != nil { + return nil, err + } + if r.AppUUID != h.UUID { + return nil, oerr.NoAuth + } + return r.Users, nil +} + +func (h *roleUserHandler) Post() (interface{}, error) { + if !h.GetAuth(auth.Role, h.UUID).CanCreate() { + return nil, oerr.NoAuth + } + id := h.Meta().ParamsInt("id") + uid := h.Meta().ParamsInt("uid") + if id <= 0 || uid <= 0 { + return nil, oerr.ApiArgsMissing + } + r := &models.Role{} + err := cfg.DB().Where("ID = ?", id).First(r).Error + if err != nil { + return nil, err + } + if r.AppUUID != h.UUID { + return nil, oerr.NoAuth + } + err = auth.BindUserRole(cfg.DB(), uint(uid), uint(id)) + return nil, err +} +func (h *roleUserHandler) Delete() (interface{}, error) { + if !h.GetAuth(auth.Role, h.UUID).CanCreate() { + return nil, oerr.NoAuth + } + id := h.Meta().ParamsInt("id") + uid := h.Meta().ParamsInt("uid") + if id <= 0 || uid <= 0 { + return nil, oerr.ApiArgsMissing + } + r := &models.Role{} + err := cfg.DB().Where("ID = ?", id).First(r).Error + if err != nil { + return nil, err + } + if r.AppUUID != h.UUID { + return nil, oerr.NoAuth + } + err = auth.UnBindUserRole(cfg.DB(), uint(uid), uint(id)) + return nil, err +} diff --git a/api/token/token.go b/api/token/token.go index 4771a41..27a27b0 100644 --- a/api/token/token.go +++ b/api/token/token.go @@ -17,7 +17,7 @@ func Router(r OneBD.Router) { p := OneBD.NewHandlerPool(func() OneBD.Handler { return &tokenHandler{} }) - r.Set("/:uuid", p, rfc.MethodGet) + r.Set("/", p, rfc.MethodGet) } type tokenHandler struct { diff --git a/api/user/user.go b/api/user/user.go index 7c99cfe..6c0cb0a 100644 --- a/api/user/user.go +++ b/api/user/user.go @@ -42,15 +42,15 @@ type handler struct { // Get get user data func (h *handler) Get() (interface{}, error) { - userID := h.Meta().ParamsInt("user_id") + userID := uint(h.Meta().ParamsInt("user_id")) + if userID != h.Payload.ID && !h.Payload.GetAuth(auth.User, "").CanRead() { + return nil, oerr.NoAuth.AttachStr("to read user data") + } if userID != 0 { user := &models.User{} - user.ID = uint(userID) + user.ID = userID return user, cfg.DB().Where(user).First(user).Error } else { - if !h.Payload.GetAuth(auth.User, "").CanRead() { - return nil, oerr.NoAuth.AttachStr("to read user list") - } username := h.Meta().Query("username") if username != "" { users := make([]*models.User, 0, 10) diff --git a/go.mod b/go.mod index 5a19e5b..b282116 100644 --- a/go.mod +++ b/go.mod @@ -12,4 +12,4 @@ require ( gorm.io/gorm v1.21.3 ) -//replace github.com/veypi/OneBD v0.4.3 => ../OceanCurrent/OneBD +replace github.com/veypi/OneBD v0.4.3 => ../OceanCurrent/OneBD diff --git a/libs/auth/auth.go b/libs/auth/auth.go index 97f0d9f..f122d15 100644 --- a/libs/auth/auth.go +++ b/libs/auth/auth.go @@ -1,9 +1,9 @@ package auth import ( + "errors" "github.com/veypi/OneAuth/models" "github.com/veypi/OneAuth/oalib" - "github.com/veypi/utils" "gorm.io/gorm" ) @@ -21,20 +21,28 @@ const ( ) func BindUserRole(tx *gorm.DB, userID uint, roleID uint) error { - r := &models.Role{} - r.ID = roleID - err := tx.Where(r).First(r).Error - if err != nil { - return err + ur := &models.UserRole{} + ur.RoleID = roleID + ur.UserID = userID + err := tx.Where(ur).First(ur).Error + if errors.Is(err, gorm.ErrRecordNotFound) { + err = tx.Create(ur).Error + if err == nil { + tx.Model(&models.Role{}).Where("ID = ?", roleID). + Update("UserCount", gorm.Expr("UserCount + ?", 1)) + } } + return err +} +func UnBindUserRole(tx *gorm.DB, userID uint, roleID uint) error { ur := &models.UserRole{} ur.RoleID = roleID ur.UserID = userID - err = utils.MultiErr( - tx.Where(ur).FirstOrCreate(ur).Error, + err := tx.Unscoped().Where(ur).Delete(ur).Error + if err == nil { tx.Model(&models.Role{}).Where("ID = ?", roleID). - Update("UserCount", gorm.Expr("UserCount + ?", 1)).Error, - ) + Update("UserCount", gorm.Expr("UserCount - ?", 1)) + } return err } diff --git a/main.go b/main.go index f1e1fb9..bc1e69a 100644 --- a/main.go +++ b/main.go @@ -14,7 +14,7 @@ const Version = "v0.1.0" func main() { cmd.LoadCfg(cfg.Path, cfg.CFG) app := cli.NewApp() - app.Name = "github.com/veypi/OneAuth" + app.Name = "oneauth" app.Usage = "one auth" app.Version = Version app.Flags = []cli.Flag{ @@ -59,7 +59,6 @@ func main() { if cfg.CFG.Debug { cfg.CFG.LoggerLevel = "debug" } - cfg.ConnectDB() return nil } _ = app.Run(os.Args) diff --git a/oaf/src/api/index.ts b/oaf/src/api/index.ts index ca0ebe2..d9abf7d 100644 --- a/oaf/src/api/index.ts +++ b/oaf/src/api/index.ts @@ -10,10 +10,12 @@ import app from './app' import user from './user' import auth from './auth' import resource from './resource' +import token from './token' const api = { user: user, + token: token, app: app, auth: auth, role: role, diff --git a/oaf/src/api/interface.ts b/oaf/src/api/interface.ts index 85896b8..5a0fae1 100644 --- a/oaf/src/api/interface.ts +++ b/oaf/src/api/interface.ts @@ -54,10 +54,6 @@ export class Interface { } } else { newFail(data) - if (data.code === 41001) { - store.commit('user/logout') - // bus.$emit('log_out') - } } } this.method(this.api, this.data, newSuccess, newFail) diff --git a/oaf/src/api/role.ts b/oaf/src/api/role.ts index 9aba9d2..18b6018 100644 --- a/oaf/src/api/role.ts +++ b/oaf/src/api/role.ts @@ -16,10 +16,25 @@ export default (uuid: string) => { }, create(Name: string, Tag: string) { return new Interface(ajax.post, this.local, { - Name,Tag + Name, Tag, }) }, - bind(id: number, aid: number) { + delete(id: number) { + return new Interface(ajax.delete, this.local + id) + }, + user(id: number) { + return { + local: this.local + id + '/user/', + list() { + return new Interface(ajax.get, this.local) + }, + create(uid: number) { + return new Interface(ajax.post, this.local + uid) + }, + delete(uid: number) { + return new Interface(ajax.delete, this.local + uid) + }, + } }, } } diff --git a/oaf/src/api/token.ts b/oaf/src/api/token.ts new file mode 100644 index 0000000..ea088a4 --- /dev/null +++ b/oaf/src/api/token.ts @@ -0,0 +1,18 @@ +/* +* @name: token +* @author: veypi +* @date: 2021-11-26 19:22 +* @description:token +*/ + +import {Interface} from '@/api/interface' +import ajax from './ajax' + +export default (uuid: string) => { + return { + local: '/api/app/' + uuid + '/token/', + get() { + return new Interface(ajax.get, this.local) + }, + } +} diff --git a/oaf/src/api/user.ts b/oaf/src/api/user.ts index 5d74d06..7511b4e 100644 --- a/oaf/src/api/user.ts +++ b/oaf/src/api/user.ts @@ -1,4 +1,4 @@ -import {Base64} from "js-base64"; +import {Base64} from 'js-base64' import {Interface} from './interface' import ajax from './ajax' import {BaseUrl} from './setting' @@ -8,16 +8,19 @@ export default { register(username: string, password: string, prop?: any) { const data = Object.assign({ username: username, - password: Base64.encode(password) + password: Base64.encode(password), }, prop) return new Interface(ajax.post, this.local, data) }, login(username: string, password: string) { return new Interface(ajax.head, this.local + username, { UidType: 'username', - password: Base64.encode(password) + password: Base64.encode(password), }) }, + search(q: string) { + return new Interface(ajax.get, this.local, {username: q}) + }, get(id: number) { return new Interface(ajax.get, this.local + id) }, @@ -26,5 +29,5 @@ export default { }, update(id: number, props: any) { return new Interface(ajax.patch, this.local + id, props) - } + }, } diff --git a/oaf/src/components/app.vue b/oaf/src/components/app.vue index 159d2f3..8079b73 100644 --- a/oaf/src/components/app.vue +++ b/oaf/src/components/app.vue @@ -2,7 +2,7 @@
- +
@@ -13,7 +13,7 @@
diff --git a/oaf/src/store/index.ts b/oaf/src/store/index.ts index bf04405..986f175 100644 --- a/oaf/src/store/index.ts +++ b/oaf/src/store/index.ts @@ -26,7 +26,7 @@ export const store = createStore({ }, // @ts-ignore state: { - oauuid: '', + oauuid: 'jU5Jo5hM', title: '', height: 'calc(100vh - 108px)', hideHeader: false, diff --git a/oaf/src/theme/index.ts b/oaf/src/theme/index.ts index fbccfae..9c217f1 100644 --- a/oaf/src/theme/index.ts +++ b/oaf/src/theme/index.ts @@ -18,27 +18,27 @@ let intputNone = { color: 'url(0) no-repeat', colorFocus: 'url(0) no-repeat', colorFocusWarning: 'url(0) no-repeat', - colorFocusError: 'url(0) no-repeat' + colorFocusError: 'url(0) no-repeat', } light.overrides = { - Input: Object.assign({}, intputNone) + Input: Object.assign({}, intputNone), } dark.overrides = { Input: Object.assign({ - border: '1px solid #aaa' - }, intputNone) + border: '1px solid #aaa', + }, intputNone), } light.common.cardColor = '#f4f4f4' light.common.bodyColor = '#eee' dark.common.bodyColor = '#2e2e2e' light.me = { lightBox: '#f4f4f4', - lightBoxShadow: '18px 18px 36px #c6c6c6, -18px -18px 36px #fff' + lightBoxShadow: '18px 18px 36px #c6c6c6, -18px -18px 36px #fff', } dark.me = { lightBox: '#2e2e2e', - lightBoxShadow: '21px 21px 42px #272727, -21px -21px 42px #353535' + lightBoxShadow: '21px 21px 42px #272727, -21px -21px 42px #353535', } export const OsThemeRef = useOsTheme() diff --git a/oaf/src/views/app.vue b/oaf/src/views/app.vue index 0ceea17..e542db1 100644 --- a/oaf/src/views/app.vue +++ b/oaf/src/views/app.vue @@ -1,7 +1,7 @@ - + OA + + - +
diff --git a/sub/web.go b/sub/web.go index cc8278b..5620eae 100644 --- a/sub/web.go +++ b/sub/web.go @@ -1,6 +1,7 @@ package sub import ( + "embed" "github.com/urfave/cli/v2" "github.com/veypi/OneAuth/api" "github.com/veypi/OneAuth/cfg" @@ -8,14 +9,14 @@ import ( "github.com/veypi/utils/log" ) -// go:embed static/static -//var staticFiles embed.FS +//go:embed static/static +var staticFiles embed.FS -// go:embed static/favicon.ico -//var icon []byte +//go:embed static/favicon.ico +var icon []byte -// go:embed static/index.html -//var indexFile []byte +//go:embed static/index.html +var indexFile []byte var Web = &cli.Command{ Name: "web", @@ -40,9 +41,9 @@ func RunWeb(c *cli.Context) error { // TODO media 文件需要检验权限 app.Router().SubRouter("/media/").Static("/", cfg.CFG.MediaDir) - //app.Router().EmbedDir("/static", staticFiles, "static/static/") - //app.Router().EmbedFile("/favicon.ico", icon) - //app.Router().EmbedFile("/*", indexFile) + app.Router().EmbedDir("/static", staticFiles, "static/static/") + app.Router().EmbedFile("/favicon.ico", icon) + app.Router().EmbedFile("/*", indexFile) log.Info().Msg("\nRouting Table\n" + app.Router().String()) return app.Run()