├── .github └── ISSUE_TEMPLATE │ └── bug_report.md ├── .gitignore ├── .golangci.yml ├── .travis.yml ├── .vscode └── settings.json ├── Dockerfile ├── LICENSE ├── Makefile ├── README-EN.md ├── README.md ├── cmd ├── api │ └── server.go ├── cobra.go └── migrate │ └── migrate.go ├── config ├── casbin │ └── rbac_model_0.conf ├── in-cluster.yaml ├── in-local.yaml └── locale │ ├── locale_en-US.ini │ └── locale_zh-CN.ini ├── covprofile ├── docs ├── docs.go ├── en │ └── CONTRIBUTING.md ├── images │ ├── arch.png │ ├── dber.png │ ├── logo.png │ ├── screenshot1.png │ ├── screenshot2.png │ ├── screenshot3.png │ ├── wechatqun.jpg │ └── wx.jpg ├── swagger.json ├── swagger.yaml └── zh │ ├── CHANGELOG.md │ ├── CONTRIBUTING.md │ ├── GenrsaKey.md │ ├── Roadmap.md │ └── Swag.md ├── go.mod ├── go.sum ├── keys ├── jwt_private_key.pem └── jwt_public_key.pem ├── main.go ├── pkg ├── api │ ├── cache │ │ ├── init.go │ │ └── redis.go │ ├── controllers │ │ ├── account.go │ │ ├── auth.go │ │ ├── base.go │ │ ├── data_perm.go │ │ ├── dept.go │ │ ├── domain.go │ │ ├── install.go │ │ ├── log.go │ │ ├── menu.go │ │ ├── probe.go │ │ ├── role.go │ │ ├── setting.go │ │ ├── sync.go │ │ └── user.go │ ├── dao │ │ ├── data_perm.go │ │ ├── dept.go │ │ ├── domain.go │ │ ├── init.go │ │ ├── log.go │ │ ├── menu.go │ │ ├── menu_perm_alias.go │ │ ├── role.go │ │ ├── role_data_perm.go │ │ ├── user.go │ │ ├── user_oauth.go │ │ └── user_secret.go │ ├── domain │ │ ├── account │ │ │ ├── account.go │ │ │ ├── account_test.go │ │ │ ├── ldap │ │ │ │ ├── init.go │ │ │ │ └── ldap.go │ │ │ └── login │ │ │ │ ├── 2fa_handler.go │ │ │ │ ├── 2fa_handler_test.go │ │ │ │ ├── dingding.go │ │ │ │ ├── dingding_test.go │ │ │ │ ├── general.go │ │ │ │ ├── general_test.go │ │ │ │ └── weixin.go │ │ ├── dept │ │ │ └── sync │ │ │ │ └── dingtalk.go │ │ ├── perm │ │ │ ├── adapter │ │ │ │ ├── adapter.go │ │ │ │ └── mysql │ │ │ │ │ └── gorm.go │ │ │ ├── dataperm │ │ │ │ ├── data_perm.go │ │ │ │ └── data_perm_test.go │ │ │ ├── perm.go │ │ │ ├── perm_test.csv │ │ │ ├── perm_test.go │ │ │ └── rbac_model_0.conf │ │ ├── role │ │ │ ├── role.go │ │ │ └── role_test.go │ │ ├── search │ │ │ ├── adapter │ │ │ │ ├── adapter.go │ │ │ │ └── statement │ │ │ │ │ └── sql.go │ │ │ ├── lexer │ │ │ │ ├── lexer │ │ │ │ │ ├── lexer.go │ │ │ │ │ ├── stm.go │ │ │ │ │ ├── stm_begin.go │ │ │ │ │ ├── stm_delimiter.go │ │ │ │ │ ├── stm_equal.go │ │ │ │ │ ├── stm_key.go │ │ │ │ │ ├── stm_test.go │ │ │ │ │ └── stm_val.go │ │ │ │ └── token │ │ │ │ │ └── token.go │ │ │ └── parser │ │ │ │ ├── parser.go │ │ │ │ └── parser_test.go │ │ ├── sync │ │ │ └── dingdingtalk │ │ │ │ ├── sync.go │ │ │ │ └── sync_test.go │ │ └── user │ │ │ ├── user.go │ │ │ └── user_test.go │ ├── dto │ │ ├── data_perm.go │ │ ├── dept.go │ │ ├── domain.go │ │ ├── general.go │ │ ├── init.go │ │ ├── install.go │ │ ├── login.go │ │ ├── login_log.go │ │ ├── menu.go │ │ ├── myaccount.go │ │ ├── operation_log.go │ │ ├── perm.go │ │ ├── role.go │ │ ├── role_data_perm.go │ │ ├── setting.go │ │ ├── user.go │ │ ├── user_oauth.go │ │ └── user_secret.go │ ├── log │ │ └── logger.go │ ├── middleware │ │ ├── cors.go │ │ ├── jwt.go │ │ ├── locale.go │ │ ├── log.go │ │ ├── perm.go │ │ └── prepare.go │ ├── model │ │ ├── base.go │ │ ├── casbin_rule.go │ │ ├── data_perm.go │ │ ├── department.go │ │ ├── domain.go │ │ ├── login_log.go │ │ ├── menu.go │ │ ├── menu_perm_alias.go │ │ ├── operation_log.go │ │ ├── role.go │ │ ├── role_data_perm.go │ │ ├── setting.go │ │ ├── user.go │ │ ├── user_oauth.go │ │ ├── user_role.go │ │ └── user_secret.go │ ├── router │ │ └── router.go │ ├── service │ │ ├── data_perm.go │ │ ├── dept.go │ │ ├── dingtalk.go │ │ ├── domain.go │ │ ├── install.go │ │ ├── log.go │ │ ├── menu.go │ │ ├── menu_perm_alias.go │ │ ├── myaccount.go │ │ ├── role.go │ │ ├── setting.go │ │ ├── user.go │ │ └── user_secret.go │ └── utils │ │ ├── mailTemplate │ │ └── verify.go │ │ └── utils.go └── webui │ ├── .babelrc │ ├── .editorconfig │ ├── .eslintignore │ ├── .eslintrc.js │ ├── .gitignore │ ├── .postcssrc.js │ ├── .travis.yml │ ├── build │ ├── build.js │ ├── check-versions.js │ ├── utils.js │ ├── vue-loader.conf.js │ ├── webpack.base.conf.js │ ├── webpack.dev.conf.js │ └── webpack.prod.conf.js │ ├── config │ ├── dev.env.js │ ├── index.js │ ├── prev.env.js │ ├── prod.env.js │ ├── test.env.js │ └── work.env.js │ ├── favicon.ico │ ├── index.html │ ├── node_modules │ └── .bin │ │ └── acorn │ ├── package.json │ ├── readme.md │ ├── src │ ├── App.vue │ ├── api │ │ ├── dataPerm.js │ │ ├── dept.js │ │ ├── domain.js │ │ ├── log.js │ │ ├── login.js │ │ ├── menu.js │ │ ├── qiniu.js │ │ ├── remoteSearch.js │ │ ├── role.js │ │ ├── transaction.js │ │ └── user.js │ ├── assets │ │ ├── 401_images │ │ │ └── 401.gif │ │ ├── 404_images │ │ │ ├── 404.png │ │ │ └── 404_cloud.png │ │ ├── custom-theme │ │ │ ├── fonts │ │ │ │ ├── element-icons.ttf │ │ │ │ └── element-icons.woff │ │ │ └── index.css │ │ └── images │ │ │ ├── background.jpg │ │ │ ├── dingtalk.png │ │ │ ├── error-page │ │ │ ├── error-401.svg │ │ │ ├── error-404.svg │ │ │ └── error-500.svg │ │ │ ├── favicon.png │ │ │ ├── github.png │ │ │ ├── google-authenticator.png │ │ │ ├── logo-min.png │ │ │ ├── logo.png │ │ │ └── wechat.png │ ├── components │ │ ├── BackToTop │ │ │ └── index.vue │ │ ├── Breadcrumb │ │ │ └── index.vue │ │ ├── Charts │ │ │ ├── keyboard.vue │ │ │ ├── lineMarker.vue │ │ │ ├── mixChart.vue │ │ │ └── mixins │ │ │ │ └── resize.js │ │ ├── DndList │ │ │ └── index.vue │ │ ├── DragSelect │ │ │ └── index.vue │ │ ├── Dropzone │ │ │ └── index.vue │ │ ├── ErrorLog │ │ │ └── index.vue │ │ ├── GithubCorner │ │ │ └── index.vue │ │ ├── Hamburger │ │ │ └── index.vue │ │ ├── ImageCropper │ │ │ ├── index.vue │ │ │ └── utils │ │ │ │ ├── data2blob.js │ │ │ │ ├── effectRipple.js │ │ │ │ ├── language.js │ │ │ │ └── mimes.js │ │ ├── JsonEditor │ │ │ └── index.vue │ │ ├── Kanban │ │ │ └── index.vue │ │ ├── LangSelect │ │ │ └── index.vue │ │ ├── MDinput │ │ │ └── index.vue │ │ ├── MarkdownEditor │ │ │ ├── defaultOptions.js │ │ │ └── index.vue │ │ ├── Pagination │ │ │ └── index.vue │ │ ├── PanThumb │ │ │ └── index.vue │ │ ├── Screenfull │ │ │ └── index.vue │ │ ├── ScrollPane │ │ │ └── index.vue │ │ ├── Share │ │ │ └── dropdownMenu.vue │ │ ├── SizeSelect │ │ │ └── index.vue │ │ ├── Sticky │ │ │ └── index.vue │ │ ├── SvgIcon │ │ │ └── index.vue │ │ ├── TextHoverEffect │ │ │ └── Mallki.vue │ │ ├── ThemePicker │ │ │ └── index.vue │ │ ├── Tinymce │ │ │ ├── components │ │ │ │ └── editorImage.vue │ │ │ ├── index.vue │ │ │ ├── plugins.js │ │ │ └── toolbar.js │ │ ├── TreeTable │ │ │ ├── eval.js │ │ │ ├── index.vue │ │ │ └── readme.md │ │ ├── Upload │ │ │ ├── singleImage.vue │ │ │ ├── singleImage2.vue │ │ │ └── singleImage3.vue │ │ └── UploadExcel │ │ │ └── index.vue │ ├── config │ │ └── index.js │ ├── directive │ │ ├── clipboard │ │ │ ├── clipboard.js │ │ │ └── index.js │ │ ├── customEval.js │ │ ├── el-dragDialog │ │ │ ├── drag.js │ │ │ └── index.js │ │ ├── index.js │ │ ├── permission │ │ │ ├── index.js │ │ │ └── permission.js │ │ ├── sticky.js │ │ └── waves │ │ │ ├── index.js │ │ │ ├── waves.css │ │ │ └── waves.js │ ├── filters │ │ └── index.js │ ├── icons │ │ ├── index.js │ │ ├── svg │ │ │ ├── 404.svg │ │ │ ├── bug.svg │ │ │ ├── chart.svg │ │ │ ├── clipboard.svg │ │ │ ├── component.svg │ │ │ ├── dashboard.svg │ │ │ ├── documentation.svg │ │ │ ├── drag.svg │ │ │ ├── edit.svg │ │ │ ├── email.svg │ │ │ ├── example.svg │ │ │ ├── excel.svg │ │ │ ├── eye.svg │ │ │ ├── form.svg │ │ │ ├── guide 2.svg │ │ │ ├── guide.svg │ │ │ ├── icon.svg │ │ │ ├── international.svg │ │ │ ├── language.svg │ │ │ ├── link.svg │ │ │ ├── list.svg │ │ │ ├── lock.svg │ │ │ ├── message.svg │ │ │ ├── money.svg │ │ │ ├── nested.svg │ │ │ ├── password.svg │ │ │ ├── people.svg │ │ │ ├── peoples.svg │ │ │ ├── qq.svg │ │ │ ├── shopping.svg │ │ │ ├── size.svg │ │ │ ├── star.svg │ │ │ ├── tab.svg │ │ │ ├── table.svg │ │ │ ├── theme.svg │ │ │ ├── tree.svg │ │ │ ├── user.svg │ │ │ ├── wechat.svg │ │ │ └── zip.svg │ │ └── svgo.yml │ ├── lang │ │ ├── en.js │ │ ├── index.js │ │ └── zh.js │ ├── main.js │ ├── mock │ │ ├── index.js │ │ ├── login.js │ │ ├── remoteSearch.js │ │ └── transaction.js │ ├── plugin │ │ ├── error-store │ │ │ └── index.js │ │ └── index.js │ ├── router │ │ ├── index.js │ │ ├── modules │ │ │ ├── charts.js │ │ │ ├── components.js │ │ │ ├── nested.js │ │ │ └── table.js │ │ └── routers.js │ ├── store │ │ ├── getters.js │ │ ├── index.js │ │ └── modules │ │ │ ├── app.js │ │ │ ├── errorLog.js │ │ │ ├── permission.js │ │ │ ├── tagsView.js │ │ │ └── user.js │ ├── styles │ │ ├── btn.scss │ │ ├── element-ui.scss │ │ ├── index.scss │ │ ├── mixin.scss │ │ ├── sidebar.scss │ │ ├── transition.scss │ │ └── variables.scss │ ├── utils │ │ ├── auth.js │ │ ├── clipboard.js │ │ ├── createUniqueString.js │ │ ├── i18n.js │ │ ├── index.js │ │ ├── openWindow.js │ │ ├── permission.js │ │ ├── request.js │ │ ├── requireIcons.js │ │ ├── scrollTo.js │ │ └── validate.js │ ├── vendor │ │ ├── Export2Excel.js │ │ └── Export2Zip.js │ └── views │ │ ├── dashboard │ │ └── index.vue │ │ ├── errorPage │ │ ├── 401.vue │ │ └── 404.vue │ │ ├── install │ │ ├── index.vue │ │ └── install.block.js │ │ ├── layout │ │ ├── Layout.vue │ │ ├── components │ │ │ ├── AppMain.vue │ │ │ ├── Navbar.vue │ │ │ ├── Sidebar │ │ │ │ ├── FixiOSBug.js │ │ │ │ ├── Item.vue │ │ │ │ ├── Link.vue │ │ │ │ ├── SidebarItem.vue │ │ │ │ └── index.vue │ │ │ ├── TagsView.vue │ │ │ └── index.js │ │ └── mixin │ │ │ ├── PreCheck.js │ │ │ ├── PwdChangeCheck.js │ │ │ └── ResizeHandler.js │ │ ├── login │ │ ├── authredirect.vue │ │ ├── index.vue │ │ └── socialsignin.vue │ │ ├── logs │ │ ├── error.vue │ │ ├── login.vue │ │ └── operation.vue │ │ ├── my │ │ ├── index.vue │ │ ├── personal.block.js │ │ ├── personal.vue │ │ ├── psw.vue │ │ ├── security.vue │ │ └── third.vue │ │ ├── permission │ │ ├── dept.vue │ │ ├── deptrw.vue │ │ ├── member.vue │ │ ├── role.vue │ │ └── user.vue │ │ ├── redirect │ │ └── index.vue │ │ ├── setting │ │ ├── auth.block.js │ │ ├── auth.vue │ │ ├── email.block.js │ │ └── email.vue │ │ └── system │ │ ├── dataPerm.vue │ │ ├── domain.vue │ │ ├── menu.vue │ │ └── params.vue │ ├── static │ ├── images │ │ ├── wave-back.png │ │ ├── wave-front.png │ │ └── wave-middle.png │ └── tinymce4.7.5 │ │ ├── langs │ │ └── zh_CN.js │ │ ├── plugins │ │ ├── codesample │ │ │ └── css │ │ │ │ └── prism.css │ │ ├── emoticons │ │ │ └── img │ │ │ │ ├── smiley-cool.gif │ │ │ │ ├── smiley-cry.gif │ │ │ │ ├── smiley-embarassed.gif │ │ │ │ ├── smiley-foot-in-mouth.gif │ │ │ │ ├── smiley-frown.gif │ │ │ │ ├── smiley-innocent.gif │ │ │ │ ├── smiley-kiss.gif │ │ │ │ ├── smiley-laughing.gif │ │ │ │ ├── smiley-money-mouth.gif │ │ │ │ ├── smiley-sealed.gif │ │ │ │ ├── smiley-smile.gif │ │ │ │ ├── smiley-surprised.gif │ │ │ │ ├── smiley-tongue-out.gif │ │ │ │ ├── smiley-undecided.gif │ │ │ │ ├── smiley-wink.gif │ │ │ │ └── smiley-yell.gif │ │ └── visualblocks │ │ │ └── css │ │ │ └── visualblocks.css │ │ ├── skins │ │ └── lightgray │ │ │ ├── content.inline.min.css │ │ │ ├── content.min.css │ │ │ ├── fonts │ │ │ ├── tinymce-mobile.woff │ │ │ ├── tinymce-small.eot │ │ │ ├── tinymce-small.svg │ │ │ ├── tinymce-small.ttf │ │ │ ├── tinymce-small.woff │ │ │ ├── tinymce.eot │ │ │ ├── tinymce.svg │ │ │ ├── tinymce.ttf │ │ │ └── tinymce.woff │ │ │ ├── img │ │ │ ├── anchor.gif │ │ │ ├── loader.gif │ │ │ ├── object.gif │ │ │ └── trans.gif │ │ │ ├── skin.min.css │ │ │ └── skin.min.css.map │ │ └── tinymce.min.js │ └── yarn.lock └── scripts ├── apppkg.sh ├── build ├── build.sh ├── docker ├── docker.sh ├── getlatest.sh ├── init.sql ├── pack.sh ├── run.sh ├── sdk ├── go │ ├── README.md │ ├── perm.go │ ├── perm_test.go │ └── pub_key.pub ├── java │ ├── .gitignore │ ├── README.md │ ├── pom.xml │ └── src │ │ ├── main │ │ └── java │ │ │ └── cn │ │ │ └── bullteam │ │ │ └── PermCenter.java │ │ └── test │ │ └── java │ │ └── Test.java ├── php │ ├── .gitignore │ ├── README.md │ ├── composer.json │ └── src │ │ └── Auth │ │ ├── JWToken.php │ │ └── PermCenter.php └── python │ ├── README.md │ ├── app.py │ ├── permission_center.py │ └── requirements.txt ├── tag.sh ├── ui ├── ui.sh ├── upx ├── linux │ └── upx └── windows │ └── upx └── version.sh /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Create a report to help us improve 4 | title: '' 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | **Describe the bug** 11 | A clear and concise description of what the bug is. 12 | 13 | **To Reproduce** 14 | Steps to reproduce the behavior: 15 | 1. Go to '...' 16 | 2. Click on '....' 17 | 3. Scroll down to '....' 18 | 4. See error 19 | 20 | **Expected behavior** 21 | A clear and concise description of what you expected to happen. 22 | 23 | **Screenshots** 24 | If applicable, add screenshots to help explain your problem. 25 | 26 | **Desktop (please complete the following information):** 27 | - OS: [e.g. iOS] 28 | - Browser [e.g. chrome, safari] 29 | - Version [e.g. 22] 30 | 31 | **Smartphone (please complete the following information):** 32 | - Device: [e.g. iPhone6] 33 | - OS: [e.g. iOS8.1] 34 | - Browser [e.g. stock browser, safari] 35 | - Version [e.g. 22] 36 | 37 | **Additional context** 38 | Add any other context about the problem here. 39 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Binaries for programs and plugins 2 | *.exe 3 | *.exe~ 4 | *.dll 5 | *.so 6 | *.dylib 7 | 8 | # Test binary, build with `go test -c` 9 | *.test 10 | 11 | # Output of the go coverage tool, specifically when used with LiteIDE 12 | *.out 13 | .idea/ 14 | .vscode/ 15 | cmd/api/zeus 16 | zeus 17 | keys/ 18 | .company_sns_access_token_file 19 | pkg/webui/node_modules/ 20 | pkg/webui/.vscode/settings.json 21 | pkg/webui/package-lock.json 22 | pkg/webui/dist/ 23 | data/ 24 | config/in-local.yaml 25 | build/ 26 | -------------------------------------------------------------------------------- /.golangci.yml: -------------------------------------------------------------------------------- 1 | # https://github.com/golangci/golangci/wiki/Configuration 2 | 3 | service: 4 | prepare: 5 | - go get -t ./... 6 | linters: 7 | enable: 8 | - gofmt -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: go 2 | go: 3 | - master 4 | os: 5 | - linux 6 | - osx 7 | dist: trusty 8 | sudo: false 9 | install: true 10 | env: 11 | - GO111MODULE=on 12 | script: 13 | - go build -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "go.inferGopath": false 3 | } -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM alpine 2 | #go build --ldflags "-extldflags -static" -o zeus 3 | COPY zeus /zeus 4 | COPY config /config 5 | COPY keys /keys 6 | COPY data /data 7 | COPY pkg/webui/dist /pkg/webui/dist 8 | WORKDIR / 9 | ENTRYPOINT ["/zeus", "server","--config=./config/in-cluster.yaml","--port=80","--cors=false"] -------------------------------------------------------------------------------- /README-EN.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/README-EN.md -------------------------------------------------------------------------------- /cmd/cobra.go: -------------------------------------------------------------------------------- 1 | package cmd 2 | 3 | import ( 4 | "github.com/spf13/cobra" 5 | "os" 6 | "zeus/cmd/api" 7 | "zeus/cmd/migrate" 8 | ) 9 | 10 | var rootCmd = &cobra.Command{ 11 | Use: "zeus", 12 | Short: "zeus API server", 13 | SilenceUsage: true, 14 | DisableAutoGenTag: true, 15 | Long: `Start zeus API server`, 16 | PersistentPreRunE: func(*cobra.Command, []string) error { return nil }, 17 | } 18 | 19 | func init() { 20 | rootCmd.AddCommand(api.StartCmd) 21 | rootCmd.AddCommand(migrate.MigrateCmd) 22 | } 23 | 24 | //Execute : run commands 25 | func Execute() { 26 | if err := rootCmd.Execute(); err != nil { 27 | os.Exit(-1) 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /config/casbin/rbac_model_0.conf: -------------------------------------------------------------------------------- 1 | [request_definition] 2 | r = sub, obj, act, domain 3 | 4 | [policy_definition] 5 | p = sub, obj, act, domain 6 | 7 | [role_definition] 8 | g = _, _ 9 | g2 = _, _ 10 | 11 | [policy_effect] 12 | e = some(where (p.eft == allow)) 13 | 14 | [matchers] 15 | m = (g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act && r.domain == p.domain) || (g2(r.obj, p.sub) && r.act == p.act && r.domain == p.domain) -------------------------------------------------------------------------------- /config/locale/locale_zh-CN.ini: -------------------------------------------------------------------------------- 1 | [ok] 2 | ActionSuccess=操作成功 3 | UpdateDone=更新成功 4 | DeletedDone=删除成功 5 | [err] 6 | Err404 =页面没有找到 7 | Err403 =您没有相关权限 8 | ErrInstall =安装失败 9 | ErrInputData=数据输入错误 10 | ErrDatabase=服务器错误 11 | ErrDupUser=用户信息已存在 12 | ErrNoUser=用户信息不存在 13 | ErrPass=用户信息不存在或密码不正确 14 | ErrDifferentPasswords=输入的密码不一致 15 | ErrSamePasswords=请输入与旧密码不一样的密码 16 | ErrNoUserPass=用户信息不存在或密码不正确 17 | ErrNoUserChange=用户信息不存在或数据未改变 18 | ErrInvalidUser=用户信息不正确 19 | ErrOpenFile=服务器错误 20 | ErrWriteFile=写文件出错 21 | ErrSystem=操作系统错误 22 | ErrExpired=登录已过期 23 | ErrPermission=没有权限 24 | ErrGenJwt=获取令牌失败 25 | ErrChkJwt=无效的令牌 26 | ErrIdData=此ID无数据记录 27 | ErrAddFail=创建失败 28 | ErrEditFail=更新失败 29 | ErrDelFail=删除失败 30 | ErrInvalidParams=验证失败 31 | ErrRoleAssignFail=权限分配失败 32 | ErrMenuData=请传递菜单ids 33 | ErrCaptchaEmpty=验证码不能为空 34 | ErrCaptcha=验证码错误 35 | ErrDeptDel=部门无法删除 36 | ErrDeptHasMember=部门不可删除 37 | ErrDupRecord=记录已存在 38 | ErrWrongRefreshToken =无效的refresh令牌 39 | ErrBindDingtalk=绑定钉钉失败 40 | ErrUnBindDingtalk=解除绑定钉钉失败 41 | ErrGoogleBindCode=无效验证码 42 | ErrSendMail=发送邮件失败 43 | ErrValidate=请求参数验证失败 44 | ErrRoleExists=角色已存在 45 | ErrDuplicated=记录已存在 46 | ErrNoRecord=记录不存在 47 | ErrHasSubRecord=子节点不为空 48 | ErrUploadAvatar=上传头像失败 49 | ErrLogin=账号名或密码不正确 50 | ErrSendCode=验证码发送失败 -------------------------------------------------------------------------------- /covprofile: -------------------------------------------------------------------------------- 1 | mode: set 2 | -------------------------------------------------------------------------------- /docs/en/CONTRIBUTING.md: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/en/CONTRIBUTING.md -------------------------------------------------------------------------------- /docs/images/arch.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/arch.png -------------------------------------------------------------------------------- /docs/images/dber.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/dber.png -------------------------------------------------------------------------------- /docs/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/logo.png -------------------------------------------------------------------------------- /docs/images/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/screenshot1.png -------------------------------------------------------------------------------- /docs/images/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/screenshot2.png -------------------------------------------------------------------------------- /docs/images/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/screenshot3.png -------------------------------------------------------------------------------- /docs/images/wechatqun.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/wechatqun.jpg -------------------------------------------------------------------------------- /docs/images/wx.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/docs/images/wx.jpg -------------------------------------------------------------------------------- /docs/zh/CHANGELOG.md: -------------------------------------------------------------------------------- 1 | # Changelog 2 | -------------------------------------------------------------------------------- /docs/zh/CONTRIBUTING.md: -------------------------------------------------------------------------------- 1 | ### 从官方仓库 fork 代码 2 | 3 | 1. 浏览器访问 https://zeus 4 | 2. 点击 "Fork" 按钮 (位于页面的右上方) 5 | 6 | ### 从你自己的仓库 Clone 代码 7 | 8 | ```bash 9 | cd $NAFTIS 10 | git clone https://github.com/$YOUR_GITHUB_ACCOUNT/zeus 11 | cd naftis 12 | git remote add upstream 'https://zeus' 13 | git config --global --add http.followRedirects 1 14 | ``` 15 | 16 | ### 创建分支并修改代码 17 | 18 | ```bash 19 | git checkout -b my-feature # 创建一个 my-feature 分支 20 | # 修改代码,加入你自己的变更 21 | ``` 22 | 23 | ### 让你 fork 仓库和官方仓库同步 24 | 25 | ```bash 26 | git fetch upstream 27 | git rebase upstream/master 28 | ``` 29 | 30 | ### 向你 fork 仓库提交 commits 31 | 32 | ```bash 33 | git add . 34 | git commit 35 | git push origin my-feature # 推送 my-featur 到你自己的仓库 36 | ``` 37 | ### 提交 PR 38 | 39 | ```bash 40 | 你可以访问 https://github.com/$YOUR_GITHUB_ACCOUNT/zeus 或者 https://zeus 来浏览你的分支 (比如 "my-feature")。 41 | 42 | 点击 "Compare" 按钮来比较变更, 然后点击你的 "my-feature" 分支旁边的 "Pull request" 按钮来提交 PR。 43 | ``` 44 | 45 | ### Review 代码 46 | 47 | 一个 PR 必须至少有一个人 review,review 无误后由 admin 合并至 master 分支。 48 | 49 | ## 代码结构 50 | 51 | ```bash 52 | 53 | ``` 54 | ## 代码风格 55 | - [Go: CodeReviewComments](https://github.com/golang/go/wiki/CodeReviewComments) -------------------------------------------------------------------------------- /docs/zh/GenrsaKey.md: -------------------------------------------------------------------------------- 1 | # 生成公钥和密钥 2 | 1. 打开终端`Terminal`或者`iTerm`输入以下命令生成私钥: 3 | 4 | ``` 5 | openssl genrsa -out rsa_private_key.pem 1024 6 | ``` 7 | 2. 把`RSA`私钥转换成`PKCS8`格式 8 | 9 | ``` 10 | openssl pkcs8 -topk8 -inform PEM -in rsa_private_key.pem -outform PEM -nocrypt 11 | 12 | ``` 13 | 注意把控制台输出的私钥内容替换到私钥文件(`rsa_private_key.pem`)中去。 14 | 15 | 3. 生成公钥 16 | 17 | ``` 18 | openssl rsa -in rsa_private_key.pem -out rsa_public_key.pem -pubout 19 | 20 | ``` 21 | 4. 将生成的 `rsa_private_key.pem`,`rsa_public_key.pem` 替换 `cmd/api-server/keys` 22 | -------------------------------------------------------------------------------- /docs/zh/Roadmap.md: -------------------------------------------------------------------------------- 1 | # roadmap 2 | ## 1.0 3 | - 项目基于 VUE + Golang + gin + casbin + gorm 开发 4 | - 功能包括: 5 | - 用户管理 6 | - 角色管理 7 | - 部门管理 8 | - 项目管理 9 | - 菜单管理 10 | - 数据权限 11 | - 个人中心(支持钉钉扫码登陆、Google 两步验证) 12 | 13 | ## 1.1 14 | - 支持 Ldap 15 | - 在线安装功能 16 | - docker 安装 17 | - 安装和使用文档 18 | 19 | ## 1.2 20 | - 配置开关(Ldap后台配置、钉钉、微信等密钥配置) 21 | - 组织架构调整支持钉钉组织架构同步 22 | - 项目管理升级为应用管理(支持OAuth2.0),白名单,自由化设置 23 | ## 1.3 24 | - 登录日志 25 | - 操作日志 26 | - 安全防范(验证码) 27 | ## 1.4 28 | - 支持企业微信登录 29 | ## 1.5 30 | - 支持企业微信组织架构同步 31 | ## 1.6 32 | - 支持普通微信登录 33 | - 支持QQ登陆 34 | ## 1.7 35 | - 支持github登录 36 | - 支持OpenId 37 | - 支持Facebook登录 38 | - 支持Google登录 39 | - 支持twitter登录 40 | ## 1.8 41 | - 支持小程序登录 42 | - 支持钉钉应用登录 43 | 44 | ## 2.0 45 | - 自己 APP 的扫码登录 46 | - geetest 验证码 47 | - vaptcha 验证码 48 | - 多语言 49 | - 多因素认证 50 | - 人脸识别登录(旷视,腾讯AI,阿里云AI) 51 | -------------------------------------------------------------------------------- /docs/zh/Swag.md: -------------------------------------------------------------------------------- 1 | # 如何使用SWaggo 开发 2 | 3 | ## 安装SWAG 4 | 5 | ``` 6 | $ go get -u github.com/swaggo/swag/cmd/swag 7 | ``` 8 | 国内网络如果无法安装,请使用代理。 9 | ``` 10 | export GOPROXY=https://goproxy.io 11 | ``` 12 | 若 `$GOPATH/bin` 没有加入`$PATH`中,你需要执行将其可执行文件移动到`$GOBIN`下 13 | 14 | ``` 15 | mv $GOPATH/bin/swag /usr/local/go/bin 16 | ``` 17 | 18 | ## 验证是否安装成功 19 | 20 | ``` 21 | $ swag -v 22 | swag version v1.1.1 23 | ``` 24 | 25 | ## 生成 26 | 27 | ``` 28 | swag init 29 | ``` 30 | ``` 31 | [root@go-dev zeus-admin]# /root/go/bin/swag init 32 | 2019/05/28 00:21:53 Generate swagger docs.... 33 | 2019/05/28 00:21:53 Generate general API Info 34 | 2019/05/28 00:21:53 create docs.go at docs/docs.go 35 | 2019/05/28 00:21:53 create swagger.json at docs/swagger.json 36 | 2019/05/28 00:21:53 create swagger.yaml at docs/swagger.yaml 37 | ``` 38 | 完毕后会在项目根目录下生成`docs` 39 | ``` 40 | docs/ 41 | ├── docs.go 42 | └── swagger 43 | ├── swagger.json 44 | └── swagger.yaml 45 | ``` 46 | 我们可以检查 `docs.go` 文件中的 `doc` 变量,详细记载中我们文件中所编写的注解和说明 47 | 48 | ## 验证访问 49 | 50 | ``` 51 | http://127.0.0.1/swagger/index.html 52 | http://api.bullteam.cn/swagger/index.html 53 | ``` -------------------------------------------------------------------------------- /keys/jwt_private_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN RSA PRIVATE KEY----- 2 | MIICWwIBAAKBgQC/TYKuXsgYdoICfEZOiy1L12CbyPdudhrCjrjwVcIrhGNn6Udq 3 | /SY5rh0ixm09I2tXPWLYuA1R55kyeo5RPFX+FrD+mQwfJkV/QfhaPsNjU4nCEHFM 4 | trsYCcLYJs9uX0tJdAtE6sg/VSulg1aMqCNWvtVtjrrVXSbu4zbyWzVkxQIDAQAB 5 | AoGAIJrzZQjejdzU99t6mDR8eeqxmpu8IGWc1gBBYSUcvRIJZ1KJS6Dt/PLCIIU1 6 | ZTA+QVZDHLDyBD23DLV6wDnKZgKQnTQSqfPeanT5Zomc96QUmtQBqZ5m/3P4LXTV 7 | HlYZPYeKlOCvL6fUtrb8o9sx2jk1T+d1da4CfmOffI/ZQ8ECQQDuFP+pz3m+DnMk 8 | yozNunRr8XcCk460A7lmHoCOg6l+jPbeXGEgQCBkzdgeEFWj1S8dAjyIETNGE7UI 9 | gUI5o8ydAkEAzbM9k/p08fJr+Sd8+WlYfT9NeDJpcJLXQp0FekJv9bNgRaYr0Wfj 10 | vW7XWV8VyephgAIC8S38CNyUPgqerrR8SQJAJ+9rxx8fK6se01AKeEPLXYPeU5dO 11 | u5FYWvHI3J7nImwgyMG0JQW8qUwB8WEKDHYo9fO3FZfVAu8xUaDk6+g23QJAUJuW 12 | 2/Bf95g6O67/yHVB2gL+hsWqkBTbCh2iUeDLIwuiBGkz7qG5mzheZ4VdcnzIrHMd 13 | WAnfJFHcPdvHh0rvEQJAVuiKX8+EPCpdymbmrK3dH3E2WHjozSksrJT0v6NdFnqY 14 | zeJFUH2EGnbk4M5+33zM8t3f53aGdgdVTA9VOonaow== 15 | -----END RSA PRIVATE KEY----- -------------------------------------------------------------------------------- /keys/jwt_public_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PUBLIC KEY----- 2 | MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQC/TYKuXsgYdoICfEZOiy1L12Cb 3 | yPdudhrCjrjwVcIrhGNn6Udq/SY5rh0ixm09I2tXPWLYuA1R55kyeo5RPFX+FrD+ 4 | mQwfJkV/QfhaPsNjU4nCEHFMtrsYCcLYJs9uX0tJdAtE6sg/VSulg1aMqCNWvtVt 5 | jrrVXSbu4zbyWzVkxQIDAQAB 6 | -----END PUBLIC KEY----- -------------------------------------------------------------------------------- /main.go: -------------------------------------------------------------------------------- 1 | package main 2 | 3 | import ( 4 | "zeus/cmd" 5 | ) 6 | 7 | // @title Zeus 宙斯权限后台 API 8 | // @version V0.1 9 | // @description Zeus 宙斯权限后台 10 | // @termsOfService http://swagger.io/terms/ 11 | // @contact.name API Support 12 | // @contact.email support@bullteam.cn 13 | // @license.name Apache 2.0 14 | // @license.url http://www.apache.org/licenses/LICENSE-2.0.html 15 | // @host 127.0.0.1:8012 16 | // @BasePath /v1 17 | // @securityDefinitions.apikey ApiKeyAuth 18 | // @in header 19 | // @name Authorization 20 | func main() { 21 | cmd.Execute() 22 | //dao.Shutdown() 23 | } 24 | -------------------------------------------------------------------------------- /pkg/api/cache/init.go: -------------------------------------------------------------------------------- 1 | package cache 2 | 3 | import "time" 4 | 5 | var adapter Adapter 6 | 7 | type Adapter interface { 8 | Connect() 9 | Get(key string) (string, error) 10 | Set(key string, val string, expire int) error 11 | Del(key string) error 12 | HashGet(hk, key string) (string, error) 13 | HashDel(hk, key string) error 14 | Increase(key string) error 15 | Expire(key string, dur time.Duration) error 16 | } 17 | 18 | func SetUp() { 19 | adapter = &Redis{} 20 | adapter.Connect() 21 | } 22 | 23 | // Set val in cache 24 | func Set(key, val string, expire int) error { 25 | return adapter.Set(key, val, expire) 26 | } 27 | 28 | // Get val in cache 29 | func Get(key string) (string, error) { 30 | return adapter.Get(key) 31 | } 32 | 33 | // Del delete key in cache 34 | func Del(key string) error { 35 | return adapter.Del(key) 36 | } 37 | 38 | // HashGet get val in hashtable cache 39 | func HashGet(hk, key string) (string, error) { 40 | return adapter.HashGet(hk, key) 41 | } 42 | 43 | // HashDel delete one key:value pair in hashtable cache 44 | func HashDel(hk, key string) error { 45 | return adapter.HashDel(hk, key) 46 | } 47 | 48 | // Increase value 49 | func Increase(key string) error { 50 | return adapter.Increase(key) 51 | } 52 | 53 | func Expire(key string, dur time.Duration) error { 54 | return adapter.Expire(key, dur) 55 | } 56 | -------------------------------------------------------------------------------- /pkg/api/controllers/auth.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | jwt "github.com/appleboy/gin-jwt/v2" 5 | "github.com/gin-gonic/gin" 6 | ) 7 | 8 | var jwtAuth *jwt.GinJWTMiddleware 9 | var jwtAuths *jwt.GinJWTMiddleware 10 | 11 | type AuthController struct { 12 | BaseController 13 | } 14 | 15 | // @Tags Users 16 | // @Summary 用户登陆 17 | // @Accept json 18 | // @Produce json 19 | // @Param username formData string true "登录名" 20 | // @Param password formData string true "密码" 21 | // @Param captchaid formData string false "验证码ID" 22 | // @Param captchaval formData string false "验证码" 23 | // @Success 200 {array} model.User "{"code":200,"data":{"id":1,"name":"wutong"}}" 24 | // @Failure 400 {string} json "{"code":10004,"msg": "用户信息不存在"}" 25 | // @Router /v1/users/login [post] 26 | func (u *AuthController) JwtAuthLogin(c *gin.Context) { 27 | jwtAuth.LoginHandler(c) 28 | } 29 | 30 | // @Tags Users 31 | // @Summary 用户refresh-token接口 32 | // @Accept json 33 | // @Produce json 34 | // @Accept multipart/form-data 35 | // @Produce json 36 | // @Success 200 {array} model.User "{"code":200,"data":{"id":1,"name":"wutong"}}" 37 | // @Failure 400 {string} json "{"code":10004,"msg": "用户信息不存在"}" 38 | // @Router /v1/users/login/refresh [post] 39 | func (u *AuthController) JwtAuthRefreshLogin(c *gin.Context) { 40 | jwtAuth.RefreshHandler(c) 41 | } 42 | -------------------------------------------------------------------------------- /pkg/api/controllers/install.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "zeus/pkg/api/dto" 6 | "zeus/pkg/api/service" 7 | ) 8 | 9 | type InstallController struct { 10 | BaseController 11 | } 12 | 13 | var installService = service.InstallService{} 14 | 15 | func (i *InstallController) Install(c *gin.Context) { 16 | var InstallDTO dto.InstallDTO 17 | if i.BindAndValidate(c, &InstallDTO) { 18 | ret := installService.Install(InstallDTO) 19 | if !ret { 20 | fail(c, ErrInstall) 21 | return 22 | } 23 | } 24 | resp(c, map[string]interface{}{ 25 | "result": InstallDTO, 26 | }) 27 | } 28 | 29 | func (i *InstallController) IsLock(c *gin.Context) { 30 | isLock := installService.Islock() 31 | resp(c, map[string]interface{}{ 32 | "result": isLock, 33 | }) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/api/controllers/probe.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | ) 6 | 7 | // @Tags Health 8 | // @Summary 健康检查 9 | // @Produce json 10 | // @Success 200 {string} json "{"code":200,"data":{""}}" 11 | // @Router /healthcheck [get] 12 | func Healthy(c *gin.Context) { 13 | //resp(c, gin.H{ 14 | // "data": true, 15 | //}) 16 | fail(c, Err404) 17 | } 18 | -------------------------------------------------------------------------------- /pkg/api/controllers/sync.go: -------------------------------------------------------------------------------- 1 | package controllers 2 | 3 | import ( 4 | "github.com/gin-gonic/gin" 5 | "zeus/pkg/api/service" 6 | ) 7 | 8 | type SyncController struct { 9 | BaseController 10 | } 11 | 12 | var dingTalkService = service.DingTalkService{} 13 | 14 | // @Tags Sync 15 | // @Summary 钉钉组织架构+用户同步 16 | // @Security ApiKeyAuth 17 | // @Produce json 18 | // @Success 200 {string} json "{"code":200,"data":""} 19 | // @Router /v1/sync/dingtalk [post] 20 | func (s *SyncController) SyncDingTalk(c *gin.Context) { 21 | dingTalkService.SyncUsersAndDepartments() 22 | ok(c, "ok.ActionSuccess") 23 | } 24 | -------------------------------------------------------------------------------- /pkg/api/dao/data_perm.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "zeus/pkg/api/domain/search/parser" 6 | "zeus/pkg/api/dto" 7 | "zeus/pkg/api/model" 8 | ) 9 | 10 | type DataPerm struct{} 11 | 12 | // List 13 | func (dp DataPerm) List(listDto dto.GeneralListDto) ([]model.DataPerm, int64) { 14 | var dataPerms []model.DataPerm 15 | var total int64 16 | db := GetDb() 17 | ps, err := parser.Parse(listDto.Q) 18 | if err == nil { 19 | for _, sv := range searchAdapter.GenerateConditions(ps, dto.DataPermListSearchMapping) { 20 | k := sv[0].(string) 21 | db = db.Where(k, sv[1:]...) 22 | } 23 | } 24 | db.Offset(listDto.Skip).Limit(listDto.Limit).Find(&dataPerms) 25 | db.Model(&model.DataPerm{}).Count(&total) 26 | return dataPerms, total 27 | } 28 | 29 | //Get 30 | func (dp DataPerm) Get(id int) model.DataPerm { 31 | var dataPerm model.DataPerm 32 | db := GetDb() 33 | db.Where("id = ?", id).First(&dataPerm) 34 | return dataPerm 35 | } 36 | 37 | // Create 38 | func (dp DataPerm) Create(dataPerm *model.DataPerm) *gorm.DB { 39 | db := GetDb() 40 | return db.Save(dataPerm) 41 | } 42 | 43 | // Update 44 | func (dp DataPerm) Update(dataPerm *model.DataPerm) *gorm.DB { 45 | db := GetDb() 46 | return db.Save(dataPerm) 47 | } 48 | 49 | // Create 50 | func (dp DataPerm) Delete(dataPerm *model.DataPerm) *gorm.DB { 51 | db := GetDb() 52 | return db.Delete(dataPerm) 53 | } 54 | 55 | func (dp DataPerm) GetDataPermsByRoute(route string) []model.DataPerm { 56 | data, _ := dp.List(dto.GeneralListDto{ 57 | Q: "r=" + route, 58 | Limit: 9999999, 59 | }) 60 | return data 61 | } 62 | -------------------------------------------------------------------------------- /pkg/api/dao/menu_perm_alias.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import "zeus/pkg/api/model" 4 | 5 | type MenuPermAlias struct { 6 | } 7 | 8 | // GetByAlias - get single row of alias 9 | func (MenuPermAlias) GetByAlias(alias string, domainId int) model.MenuPermAlias { 10 | var mpa model.MenuPermAlias 11 | db := GetDb() 12 | db.Where("alias = ? and domain_id = ?", alias, domainId).First(&mpa) 13 | return mpa 14 | } 15 | 16 | // GetByPerms - get all aliases rows of specific permission code 17 | func (MenuPermAlias) GetByPerms(perms string) []model.MenuPermAlias { 18 | var mpa []model.MenuPermAlias 19 | db := GetDb() 20 | db.Where("perms = ?", perms).Find(&mpa) 21 | return mpa 22 | } 23 | 24 | // Delete - delete of crud 25 | func (MenuPermAlias) Delete(menuPermAlias model.MenuPermAlias) { 26 | db := GetDb() 27 | db.Where("perms = ? and domain_id = ?", menuPermAlias.Perms, menuPermAlias.DomainId).Delete(menuPermAlias) 28 | } 29 | 30 | // Create - create of crud 31 | func (MenuPermAlias) Create(menuPermAlias *model.MenuPermAlias) { 32 | db := GetDb() 33 | db.Create(menuPermAlias) 34 | } 35 | -------------------------------------------------------------------------------- /pkg/api/dao/user_oauth.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "fmt" 5 | "github.com/jinzhu/gorm" 6 | "zeus/pkg/api/dto" 7 | "zeus/pkg/api/model" 8 | ) 9 | 10 | type UserOAuthDao struct { 11 | } 12 | 13 | // List - userOAuth list 14 | func (u UserOAuthDao) List(listDto dto.GeneralListDto) ([]model.UserOAuth, int64) { 15 | var UserOAuth []model.UserOAuth 16 | var total int64 17 | db := GetDb() 18 | for sk, sv := range dto.TransformSearch(listDto.Q, dto.UserListSearchMapping) { 19 | db = db.Where(fmt.Sprintf("%s = ?", sk), sv) 20 | } 21 | db.Offset(listDto.Skip).Limit(listDto.Limit).Find(&UserOAuth) 22 | db.Model(&model.UserOAuth{}).Count(&total) 23 | return UserOAuth, total 24 | } 25 | 26 | func (u UserOAuthDao) Get(id int) model.UserOAuth { 27 | var userOAuth model.UserOAuth 28 | db.Where("id = ?", id).First(&userOAuth) 29 | return userOAuth 30 | } 31 | 32 | func (u UserOAuthDao) Create(UserOAuth *model.UserOAuth) *gorm.DB { 33 | db := GetDb() 34 | return db.Save(UserOAuth) 35 | } 36 | 37 | func (u UserOAuthDao) Delete(UserOAuth *model.UserOAuth) *gorm.DB { 38 | db := GetDb() 39 | return db.Delete(UserOAuth) 40 | } 41 | 42 | func (dao *UserOAuthDao) GetUserByOpenId(openid string, from int) (model.UserOAuth, error) { 43 | var userOAuth model.UserOAuth 44 | db.Where("openid = ? and `from` = ?", openid, from).Find(&userOAuth) 45 | return userOAuth, nil 46 | } 47 | 48 | func (dao *UserOAuthDao) DeleteByUseridAndFrom(from int, user_id int) error { 49 | db := GetDb() 50 | var userOAuth model.UserOAuth 51 | db.Where("`from` = ? and user_id = ?", from, user_id).Delete(&userOAuth) 52 | return nil 53 | } 54 | -------------------------------------------------------------------------------- /pkg/api/dao/user_secret.go: -------------------------------------------------------------------------------- 1 | package dao 2 | 3 | import ( 4 | "github.com/jinzhu/gorm" 5 | "zeus/pkg/api/model" 6 | ) 7 | 8 | type UserSecretDao struct{} 9 | 10 | func (u UserSecretDao) Get(uid int) model.UserSecret { 11 | var userSecret model.UserSecret 12 | db.Where("user_id = ?", uid).First(&userSecret) 13 | return userSecret 14 | } 15 | 16 | func (u UserSecretDao) Create(UserSecret *model.UserSecret) *gorm.DB { 17 | db := GetDb() 18 | return db.Save(UserSecret) 19 | } 20 | 21 | // Update - update UserSecret 22 | func (u UserSecretDao) Update(UserSecret *model.UserSecret, ups map[string]interface{}) *gorm.DB { 23 | db := GetDb() 24 | return db.Model(UserSecret).Update(ups) 25 | } 26 | -------------------------------------------------------------------------------- /pkg/api/domain/account/account.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "crypto/rand" 5 | "fmt" 6 | "golang.org/x/crypto/scrypt" 7 | "io" 8 | ) 9 | 10 | const pwHashBytes = 64 11 | 12 | //login type 13 | var ( 14 | LoginStandard = 1 15 | LoginOAuth = 2 16 | LoginLdap = 3 17 | ) 18 | 19 | //login oauth type 20 | const ( 21 | OAuthDingTalk = iota 22 | //todo : ... 23 | OAuthWechat 24 | OAuthQQ 25 | OAuthFacebook 26 | OAuthGoogle 27 | ) 28 | 29 | // HashPassword : password hashing 30 | func HashPassword(password string, salt string) (hash string, err error) { 31 | h, err := scrypt.Key([]byte(password), []byte(salt), 16384, 8, 1, pwHashBytes) 32 | if err != nil { 33 | return "", err 34 | } 35 | return fmt.Sprintf("%x", h), nil 36 | } 37 | 38 | // MakeSalt : make password more complicated 39 | func MakeSalt() (salt string, err error) { 40 | buf := make([]byte, pwHashBytes) 41 | if _, err := io.ReadFull(rand.Reader, buf); err != nil { 42 | return "", err 43 | } 44 | return fmt.Sprintf("%x", buf), nil 45 | } 46 | -------------------------------------------------------------------------------- /pkg/api/domain/account/account_test.go: -------------------------------------------------------------------------------- 1 | package account 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | ) 7 | 8 | var ( 9 | salt = "" 10 | pwd = "zeus" 11 | err error 12 | ) 13 | 14 | func TestMakeSalt(t *testing.T) { 15 | salt, err = MakeSalt() 16 | assert.Equal(t, nil, err) 17 | } 18 | func TestHashPassword(t *testing.T) { 19 | pwd, err = HashPassword(pwd, salt) 20 | assert.Equal(t, nil, err) 21 | } 22 | -------------------------------------------------------------------------------- /pkg/api/domain/account/ldap/init.go: -------------------------------------------------------------------------------- 1 | package ldap 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | "zeus/pkg/api/log" 6 | ) 7 | 8 | var ldapConn LdapConfig 9 | 10 | func Setup() { 11 | ldapConn = LdapConfig{ 12 | Addr: viper.GetString("ldap.addr"), 13 | BaseDn: viper.GetString("ldap.baseDn"), 14 | UserDn: viper.GetString("ldap.userDn"), 15 | BindDn: viper.GetString("ldap.bindDn"), 16 | BindPass: viper.GetString("ldap.bindPass"), 17 | AuthFilter: viper.GetString("ldap.authFilter"), 18 | Attributes: viper.GetStringSlice("ldap.attributes"), 19 | TLS: viper.GetBool("ldap.tls"), 20 | StartTLS: viper.GetBool("ldap.startTLS"), 21 | } 22 | log.Info("Successfully init ldap config") 23 | } 24 | 25 | func ConnectLdap() { 26 | e := ldapConn.Connect() 27 | if e != nil { 28 | log.Fatal("ldap connect fail!") 29 | } 30 | } 31 | 32 | func GetLdap() LdapConfig { 33 | ConnectLdap() 34 | return ldapConn 35 | } 36 | -------------------------------------------------------------------------------- /pkg/api/domain/account/login/2fa_handler_test.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | //var handler = &SmsSendChebao{ 4 | // RequestApi: "http://sms-send-api", 5 | // PrivateKey: "*****", 6 | //} 7 | // 8 | //func TestTwoFaHandlerSms(t *testing.T) { 9 | // if err := handler.Send("135xxxxyyyy"); err != nil { 10 | // t.Error(err) 11 | // } else { 12 | // t.Log("send ok") 13 | // } 14 | //} 15 | -------------------------------------------------------------------------------- /pkg/api/domain/account/login/dingding.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | dingtalk "github.com/bullteam/go-dingtalk/src" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | type DingtalkUserInfo struct { 9 | Openid string 10 | Unionid string 11 | Nick string 12 | Dingid string 13 | } 14 | 15 | //GetDingTalkUserInfo - get dingdingtalk's userinfo by code 16 | func GetDingTalkUserInfo(code string) (UserInfo *DingtalkUserInfo, err error) { 17 | c := GetCompanyDingTalkClient() 18 | _ = c.RefreshSNSAccessToken() 19 | perInfo, err := c.SNSGetPersistentCode(code) 20 | if err != nil { 21 | return nil, err 22 | } 23 | snstoken, err := c.SNSGetSNSToken(perInfo.OpenID, perInfo.PersistentCode) 24 | if err != nil { 25 | return nil, err 26 | } 27 | dtUser, err := c.SNSGetUserInfo(snstoken.SnsToken) 28 | if err != nil { 29 | return nil, err 30 | } 31 | return &DingtalkUserInfo{ 32 | dtUser.UserInfo.OpenID, 33 | dtUser.UserInfo.UnionID, 34 | dtUser.UserInfo.Nick, 35 | dtUser.UserInfo.DingID, 36 | }, nil 37 | } 38 | 39 | func GetCompanyDingTalkClient() *dingtalk.DingTalkClient { 40 | return dingtalk.NewDingTalkCompanyClient(&dingtalk.DTConfig{ 41 | SNSAppID: viper.GetString("dingtalk.SNSAppID"), 42 | SNSSecret: viper.GetString("dingtalk.SNSSecret"), 43 | CachePath: viper.GetString("dingtalk.CachePath"), 44 | }) 45 | } 46 | -------------------------------------------------------------------------------- /pkg/api/domain/account/login/dingding_test.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | dingtalk "github.com/icepy/go-dingtalk/src" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | var dingTalkClient *dingtalk.DingTalkClient 10 | 11 | func init() { 12 | //Overwrite it for tests 13 | dingTalkClient = dingtalk.NewDingTalkCompanyClient(&dingtalk.DTConfig{ 14 | SNSAppID: "dingoatdqa3hb5eta4tlvi", 15 | SNSSecret: "RHNFFTJXh-uxQ2YosdoBt8u0gqBGwWhe8J3dMwqf5gz41vHq9zHvc7D9WNZSDuJ0", 16 | }) 17 | } 18 | 19 | func TestGetCompanyDingTalkClient(t *testing.T) { 20 | assert.NotEqual(t, nil, dingTalkClient) 21 | } 22 | -------------------------------------------------------------------------------- /pkg/api/domain/account/login/general.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "zeus/pkg/api/domain/account" 5 | "zeus/pkg/api/model" 6 | ) 7 | 8 | // VerifyPassword : verify password by salt 9 | func VerifyPassword(password string, userModel model.User) bool { 10 | if pwd, err := account.HashPassword(password, userModel.Salt); err == nil && pwd == userModel.Password { 11 | return true 12 | } 13 | return false 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/domain/account/login/general_test.go: -------------------------------------------------------------------------------- 1 | package login 2 | 3 | import ( 4 | "github.com/stretchr/testify/assert" 5 | "testing" 6 | "zeus/pkg/api/domain/account" 7 | "zeus/pkg/api/model" 8 | ) 9 | 10 | type verifyCases struct { 11 | sourcePwd string 12 | targetPwd string 13 | salt string 14 | expected bool 15 | } 16 | 17 | func TestVerifyPassword(t *testing.T) { 18 | salt, _ := account.MakeSalt() 19 | pwd, _ := account.HashPassword("zeus", salt) 20 | for _, cs := range []verifyCases{{ 21 | "zeus", pwd, salt, true, 22 | }, { 23 | "zeus0", pwd, salt, false, 24 | }, { 25 | "zeus", pwd, "wrong", false, 26 | }, { 27 | "zeus", "wrong", salt, false, 28 | }, 29 | } { 30 | assert.Equal(t, cs.expected, VerifyPassword(cs.sourcePwd, model.User{ 31 | Password: cs.targetPwd, 32 | Salt: cs.salt, 33 | }), "Cases of password verification") 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /pkg/api/domain/account/login/weixin.go: -------------------------------------------------------------------------------- 1 | package login 2 | -------------------------------------------------------------------------------- /pkg/api/domain/dept/sync/dingtalk.go: -------------------------------------------------------------------------------- 1 | package sync 2 | 3 | import ( 4 | dingtalk "github.com/bullteam/go-dingtalk/src" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | func GetDingTalkUserInfo() (deptInfos interface{}, err error) { 9 | c := GetCompanyDingTalkClient() 10 | _ = c.RefreshCompanyAccessToken() 11 | list, err := c.DepartmentList(1, "zh_CN") 12 | if err != nil { 13 | return nil, err 14 | } 15 | return list.Department, nil 16 | } 17 | 18 | func GetCompanyDingTalkClient() *dingtalk.DingTalkClient { 19 | return dingtalk.NewDingTalkCompanyClient(&dingtalk.DTConfig{ 20 | AppKey: viper.GetString("dingtalk.appkey"), 21 | AppSecret: viper.GetString("dingtalk.appsecret"), 22 | CachePath: viper.GetString("dingtalk.CachePath"), 23 | }) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/api/domain/perm/adapter/adapter.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import ( 4 | "github.com/casbin/casbin/v2/model" 5 | "zeus/pkg/api/domain/perm/adapter/mysql" 6 | ) 7 | 8 | type Adapter interface { 9 | LoadPolicy(model model.Model) error 10 | SavePolicy(model model.Model) error 11 | AddPolicy(sec string, ptype string, rule []string) error 12 | RemovePolicy(sec string, ptype string, rule []string) error 13 | RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error 14 | } 15 | 16 | // NewMysqlAdapter : delegate of adapter 17 | func NewMysqlAdapter() *mysqlAdapter { 18 | ad := &mysqlAdapter{ 19 | a: mysql.NewGormAdapter(), 20 | } 21 | return ad 22 | } 23 | 24 | type mysqlAdapter struct { 25 | a Adapter 26 | } 27 | 28 | func (ca *mysqlAdapter) LoadPolicy(model model.Model) error { return ca.a.LoadPolicy(model) } 29 | func (ca *mysqlAdapter) SavePolicy(model model.Model) error { return ca.a.SavePolicy(model) } 30 | func (ca *mysqlAdapter) AddPolicy(sec string, ptype string, rule []string) error { 31 | return ca.a.AddPolicy(sec, ptype, rule) 32 | } 33 | func (ca *mysqlAdapter) RemovePolicy(sec string, ptype string, rule []string) error { 34 | return ca.a.RemovePolicy(sec, ptype, rule) 35 | } 36 | func (ca *mysqlAdapter) RemoveFilteredPolicy(sec string, ptype string, fieldIndex int, fieldValues ...string) error { 37 | return ca.a.RemoveFilteredPolicy(sec, ptype, fieldIndex, fieldValues...) 38 | } 39 | -------------------------------------------------------------------------------- /pkg/api/domain/perm/dataperm/data_perm.go: -------------------------------------------------------------------------------- 1 | package dataperm 2 | 3 | // todo : 4 | // make a data perm rule system! 5 | // sample: 6 | // #1|casbin_rule.v1 == @current.user.id , casbin_rule.v2 == role.name : select(domain_id) 7 | // condition : sql=select [@columns] from [@table] where id in(#1.domain_id) 8 | -------------------------------------------------------------------------------- /pkg/api/domain/perm/dataperm/data_perm_test.go: -------------------------------------------------------------------------------- 1 | package dataperm 2 | 3 | var statement = ` 4 | { 5 | "p": [ 6 | "casbin_rule:casbin_rule.v0=@account.id", 7 | "role:@casbin_rule.v1=role.role_name" 8 | ], 9 | "c": "id=(join[@role.domain_id,','])", 10 | "r": "domain" 11 | } 12 | ` 13 | -------------------------------------------------------------------------------- /pkg/api/domain/perm/perm_test.csv: -------------------------------------------------------------------------------- 1 | p,role-1,zone-1,manage-all-things,department-1 2 | p,role-1,zone-2,manage-some-stuff,department-1 3 | p,role-1,zone-3,can-not-do-anything,department-2 4 | p,role-2,zone-1,see-report,department-1 5 | p,role-2,zone-2,can-not-do-anything,department-3 6 | p,role-3,zone-3,*,department-4 7 | p,role-4,zone-4,*,department-4 8 | p,role-5,zone-5,*,department-5 9 | p,role-6,zone-6,*,department-6 10 | g,100,u4 11 | g,101,u5 12 | g,101,q5 13 | g2,u5,role-5 14 | g2,q5,role-6 15 | g,100,role-6 -------------------------------------------------------------------------------- /pkg/api/domain/perm/rbac_model_0.conf: -------------------------------------------------------------------------------- 1 | [request_definition] 2 | r = sub, obj, act, domain 3 | 4 | [policy_definition] 5 | p = sub, obj, act, domain 6 | 7 | [role_definition] 8 | g = _, _ 9 | g2 = _, _ 10 | 11 | [policy_effect] 12 | e = some(where (p.eft == allow)) 13 | 14 | [matchers] 15 | m = (g(r.sub, p.sub) && r.obj == p.obj && r.act == p.act && r.domain == p.domain) || (g2(r.obj, p.sub) && r.act == p.act && r.domain == p.domain) -------------------------------------------------------------------------------- /pkg/api/domain/role/role.go: -------------------------------------------------------------------------------- 1 | package role 2 | 3 | import ( 4 | "zeus/pkg/api/domain/perm" 5 | ) 6 | 7 | // CheckPerm : check permission by role with domain 8 | func CheckPerm(roleName, zone, action, domain string) (bool, error) { 9 | return perm.Enforce(roleName, zone, action, domain) 10 | } 11 | 12 | // DeletePermWithDomain : clear role permission with domain 13 | func DeletePermWithDomain(roleName, domain string) { 14 | perm.DelRoleByDomain(roleName, domain) 15 | } 16 | 17 | // DeletePerm : delete role in casbin policies 18 | func DeletePerm(roleName string) { 19 | perm.DelRole(roleName) 20 | } 21 | 22 | // DeletePermPolicy : delete role in casbin policies 23 | func DeletePermPolicy(roleName string) { 24 | perm.DeleteRolePolicy(roleName) 25 | } 26 | 27 | // OverwritePerm : overwrite permissions 28 | // remove or create policy 29 | func OverwritePerm(roleName, domainCode string, polices [][]string) { 30 | currentPerms := perm.GetAllPermsByRoleDomain(roleName, domainCode) 31 | for k1, newPerm := range polices { 32 | for k2, currentPerm := range currentPerms { 33 | if newPerm[0] == currentPerm[0] && 34 | newPerm[1] == currentPerm[1] && 35 | newPerm[2] == currentPerm[2] && 36 | newPerm[3] == currentPerm[3] { 37 | polices[k1] = []string{"-skip"} 38 | currentPerms[k2] = []string{"-skip"} 39 | } 40 | } 41 | } 42 | for _, newPerm := range polices { 43 | if newPerm[0] == "-skip" { 44 | continue 45 | } 46 | perm.AddPerm(newPerm) 47 | } 48 | for _, remPerm := range currentPerms { 49 | if remPerm[0] == "-skip" { 50 | continue 51 | } 52 | perm.DelPerm(remPerm) 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /pkg/api/domain/search/adapter/adapter.go: -------------------------------------------------------------------------------- 1 | package adapter 2 | 3 | import "zeus/pkg/api/domain/search/parser" 4 | 5 | type SearchAdapter interface { 6 | GenerateConditions([]parser.ParsePair, map[string]string) [][]interface{} 7 | } 8 | -------------------------------------------------------------------------------- /pkg/api/domain/search/adapter/statement/sql.go: -------------------------------------------------------------------------------- 1 | package statement 2 | 3 | import ( 4 | "zeus/pkg/api/domain/search/lexer/token" 5 | "zeus/pkg/api/domain/search/parser" 6 | ) 7 | 8 | type SqlSearchAdapter struct{} 9 | 10 | func (msa *SqlSearchAdapter) GenerateConditions(statement []parser.ParsePair, keyMapping map[string]string) [][]interface{} { 11 | var stmt [][]interface{} 12 | for _, p := range statement { 13 | k := p.Key 14 | if _, ok := keyMapping[k]; ok { 15 | k = keyMapping[k] 16 | } 17 | switch p.St { 18 | case token.TOKEN_OP_TYPE_EQ: 19 | stmt = append(stmt, []interface{}{k + "=?", p.Value}) 20 | case token.TOKEN_OP_TYPE_LIKE: 21 | stmt = append(stmt, []interface{}{k + " like ?", "%" + p.Value.(string) + "%"}) 22 | case token.TOKEN_OP_TYPE_IN: 23 | stmt = append(stmt, []interface{}{k + " in (?)", p.Value}) 24 | case token.TOKEN_OP_TYPE_BETWEEN: 25 | val := p.Value.([]string) 26 | stmt = append(stmt, []interface{}{k + " between ? and ?", val[0], val[1]}) 27 | case token.TOKEN_OP_TYPE_GT: 28 | stmt = append(stmt, []interface{}{k + "> ?", p.Value}) 29 | case token.TOKEN_OP_TYPE_LT: 30 | stmt = append(stmt, []interface{}{k + "< ?", p.Value}) 31 | } 32 | } 33 | return stmt 34 | } 35 | -------------------------------------------------------------------------------- /pkg/api/domain/search/lexer/lexer/stm.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import ( 4 | "zeus/pkg/api/domain/search/lexer/token" 5 | ) 6 | 7 | const ( 8 | lexErrorSyntax = `Unexpected syntax` 9 | ) 10 | 11 | type StmHandler func(*lexer) StmHandler 12 | 13 | // StmError manages syntax error 14 | func StmError(l *lexer) StmHandler { 15 | l.Tokens <- token.Token{ 16 | Type: token.TOKEN_TYPE_ERROR, 17 | Value: "EOF", 18 | OpType: -1, 19 | } 20 | return nil 21 | } 22 | 23 | // StmEnd manages common ends 24 | func StmEnd(l *lexer) StmHandler { 25 | l.Tokens <- token.Token{ 26 | Type: token.TOKEN_TYPE_END, 27 | Value: "DONE", 28 | OpType: -1, 29 | } 30 | return nil 31 | } 32 | -------------------------------------------------------------------------------- /pkg/api/domain/search/lexer/lexer/stm_begin.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | // StmBegin start to do lexer process 4 | func StmBegin(l *lexer) StmHandler { 5 | return StmKey(l) 6 | } 7 | -------------------------------------------------------------------------------- /pkg/api/domain/search/lexer/lexer/stm_delimiter.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import "zeus/pkg/api/domain/search/lexer/token" 4 | 5 | // StmDelimiter 6 | func StmDelimiter(l *lexer) StmHandler { 7 | if l.EndOfString() { 8 | return StmEnd 9 | } 10 | l.Forward(len(token.TOEKN_DELIMITER)) 11 | l.Emit(token.TOKEN_TYPE_DELIMITER) 12 | return StmBegin 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/domain/search/lexer/lexer/stm_equal.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import "zeus/pkg/api/domain/search/lexer/token" 4 | 5 | // StmEqual mange equal sign 6 | func StmEqual(l *lexer) StmHandler { 7 | l.Forward(len(token.TOKEN_EQUAL)) 8 | l.Emit(token.TOKEN_TYPE_EQUAL) 9 | return StmValue 10 | } 11 | -------------------------------------------------------------------------------- /pkg/api/domain/search/lexer/lexer/stm_key.go: -------------------------------------------------------------------------------- 1 | package lexer 2 | 3 | import "zeus/pkg/api/domain/search/lexer/token" 4 | 5 | // StmKey find next key position 6 | func StmKey(l *lexer) StmHandler { 7 | for { 8 | if l.EndOfString() { 9 | return StmError 10 | } 11 | if l.HasPrefix(token.TOKEN_EQUAL) { 12 | if l.Pos == 0 { 13 | l.EmitError(lexErrorSyntax) 14 | return StmError 15 | } 16 | l.Emit(token.TOKEN_TYPE_KEY) 17 | return StmEqual 18 | } 19 | l.Forward(1) 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /pkg/api/domain/search/lexer/token/token.go: -------------------------------------------------------------------------------- 1 | package token 2 | 3 | const ( 4 | TOKEN_EQUAL = `=` 5 | TOEKN_DELIMITER = `|` 6 | TOKEN_LIKE = `~` 7 | TOKEN_IN_LEFT = `(` 8 | TOKEN_IN_RIGHT = `)` 9 | TOKEN_BETWEEN_LEFT = `[` 10 | TOKEN_BETWEEN_RIGHT = `]` 11 | TOKEN_LT = `<` 12 | TOKEN_GT = `>` 13 | ) 14 | 15 | type TokenType int 16 | 17 | const ( 18 | TOKEN_TYPE_ERROR TokenType = iota 19 | TOKEN_TYPE_KEY 20 | TOKEN_TYPE_EQUAL 21 | TOKEN_TYPE_VAL 22 | TOKEN_TYPE_LIKE 23 | TOKEN_TYPE_VAL_LIKE 24 | TOKEN_TYPE_GT 25 | TOKEN_TYPE_VAL_GT 26 | TOKEN_TYPE_LT 27 | TOKEN_TYPE_VAL_LT 28 | TOKEN_TYPE_VAL_IN 29 | TOKEN_TYPE_VAL_BETWEEN 30 | TOKEN_TYPE_IN_LEFT 31 | TOKEN_TYPE_BETWEEN_LEFT 32 | TOKEN_TYPE_DELIMITER 33 | TOKEN_TYPE_END 34 | ) 35 | 36 | type OpType int 37 | 38 | const ( 39 | TOKEN_OP_TYPE_EQ OpType = iota 40 | TOKEN_OP_TYPE_LIKE 41 | TOKEN_OP_TYPE_BETWEEN 42 | TOKEN_OP_TYPE_IN 43 | TOKEN_OP_TYPE_LT 44 | TOKEN_OP_TYPE_GT 45 | ) 46 | 47 | type Token struct { 48 | Type TokenType 49 | Value interface{} 50 | OpType OpType 51 | } 52 | -------------------------------------------------------------------------------- /pkg/api/domain/search/parser/parser.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "errors" 5 | "strconv" 6 | "strings" 7 | "zeus/pkg/api/domain/search/lexer/lexer" 8 | "zeus/pkg/api/domain/search/lexer/token" 9 | ) 10 | 11 | var ( 12 | ErrorUnexpectedToken = errors.New("unexpected syntax") 13 | ) 14 | 15 | type ParsePair struct { 16 | Key string `json:"key"` 17 | Value interface{} `json:"val"` 18 | St token.OpType `json:"st"` 19 | } 20 | 21 | func Parse(source string) ([]ParsePair, error) { 22 | lex := lexer.NewLexer(source) 23 | var tokens []ParsePair 24 | key := "" 25 | for { 26 | tk := lex.Token() 27 | switch tk.Type { 28 | case token.TOKEN_TYPE_ERROR: 29 | return tokens, ErrorUnexpectedToken 30 | case token.TOKEN_TYPE_END: 31 | return tokens, nil 32 | case token.TOKEN_TYPE_KEY: 33 | key = tk.Value.(string) 34 | case token.TOKEN_TYPE_VAL, 35 | token.TOKEN_TYPE_VAL_LIKE: 36 | tokens = append(tokens, ParsePair{ 37 | Key: key, 38 | Value: tk.Value, 39 | St: tk.OpType, 40 | }) 41 | key = "" 42 | case token.TOKEN_TYPE_VAL_GT, 43 | token.TOKEN_TYPE_VAL_LT: 44 | val, err := strconv.Atoi(tk.Value.(string)) 45 | if err != nil { 46 | return tokens, err 47 | } 48 | tokens = append(tokens, ParsePair{ 49 | Key: key, 50 | Value: val, 51 | St: tk.OpType, 52 | }) 53 | key = "" 54 | case token.TOKEN_TYPE_VAL_BETWEEN, 55 | token.TOKEN_TYPE_VAL_IN: 56 | tokens = append(tokens, ParsePair{ 57 | Key: key, 58 | Value: strings.Split(tk.Value.(string), ","), 59 | St: tk.OpType, 60 | }) 61 | key = "" 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /pkg/api/domain/search/parser/parser_test.go: -------------------------------------------------------------------------------- 1 | package parser 2 | 3 | import ( 4 | "encoding/json" 5 | "fmt" 6 | "github.com/stretchr/testify/assert" 7 | "testing" 8 | ) 9 | 10 | func TestParse(t *testing.T) { 11 | tks, err := Parse("u.name=lake|u.id=(1,2,3,4)|u.nick=~sun|u.create_time=[2020-01-01,2020-02-01]|id=>10|age=<20") 12 | assert.NoError(t, err) 13 | prettyTks, _ := json.MarshalIndent(tks, "", " ") 14 | t.Log(fmt.Sprintf("%s", prettyTks)) 15 | 16 | tks, err = Parse("u.name=lake|u.id=1,2,3,4)|u.nick=~sun|u.create_time=[2020-01-01,2020-02-01]") 17 | assert.NoError(t, err) 18 | 19 | tks, err = Parse("u.name=lake|u.id=(1,2,3,4|u.nick=~sun|u.create_time=[2020-01-01,2020-02-01]") 20 | assert.Error(t, err) 21 | 22 | tks, err = Parse("u.name=lake|u.id=(1,2,3,4)|u.nick=~sun|u.create_time=[2020-01-01,2020-02-01]") 23 | assert.NoError(t, err) 24 | } 25 | -------------------------------------------------------------------------------- /pkg/api/domain/sync/dingdingtalk/sync.go: -------------------------------------------------------------------------------- 1 | package dingdingtalk 2 | 3 | import ( 4 | dingtalk "github.com/bullteam/go-dingtalk/src" 5 | "github.com/spf13/viper" 6 | ) 7 | 8 | var dingTalkClient *dingtalk.DingTalkClient 9 | 10 | // connect to dingding api 11 | func SetUp() { 12 | dingTalkClient = dingtalk.NewDingTalkCompanyClient(&dingtalk.DTConfig{ 13 | AppKey: viper.GetString("dingtalk.appkey"), 14 | AppSecret: viper.GetString("dingtalk.appsecret"), 15 | CachePath: viper.GetString("dingtalk.CachePath"), 16 | }) 17 | } 18 | 19 | // GetDepartment - get departments of dingding 20 | func GetDepartments() (interface{}, error) { 21 | _ = dingTalkClient.RefreshCompanyAccessToken() 22 | var treeDepartment = map[int][]dingtalk.Department{} 23 | list, err := dingTalkClient.DepartmentList(1, "zh_CN") 24 | if err != nil { 25 | return nil, err 26 | } 27 | for _, d := range list.Department { 28 | treeDepartment[d.ParentId] = append(treeDepartment[d.ParentId], d) 29 | } 30 | return treeDepartment, nil 31 | } 32 | 33 | // GetUsers - get users of dingding 34 | func GetUsers(departmentId int) (interface{}, error) { 35 | list, err := dingTalkClient.UserList(departmentId) 36 | if err != nil { 37 | return nil, err 38 | } 39 | return list.UserList, nil 40 | } 41 | -------------------------------------------------------------------------------- /pkg/api/domain/sync/dingdingtalk/sync_test.go: -------------------------------------------------------------------------------- 1 | package dingdingtalk 2 | 3 | import ( 4 | dingtalk "github.com/bullteam/go-dingtalk/src" 5 | "github.com/stretchr/testify/assert" 6 | "testing" 7 | ) 8 | 9 | func init() { 10 | dingTalkClient = dingtalk.NewDingTalkCompanyClient(&dingtalk.DTConfig{ 11 | AppKey: `dingvgvn9hdcp8qtarno`, 12 | AppSecret: `Sn887TtSQgGQNRcSaP-cNQXKYOkuT062vPgHoVvbTm5-HA2qnyew6xbdgZwhxD8N`, 13 | CachePath: `data/`, 14 | }) 15 | } 16 | func TestGetUsers(t *testing.T) { 17 | depts, err := GetDepartments() 18 | assert.NoError(t, err) 19 | if err != nil && depts != nil { 20 | for _, depts := range depts.(map[int][]dingtalk.Department) { 21 | for _, dept := range depts { 22 | users, _ := GetUsers(dept.Id) 23 | if len(users.([]dingtalk.UDetailedList)) > 1 { 24 | t.Log(users) 25 | } 26 | } 27 | } 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /pkg/api/domain/user/user.go: -------------------------------------------------------------------------------- 1 | package user 2 | 3 | import ( 4 | "zeus/pkg/api/domain/perm" 5 | ) 6 | 7 | // Permission : where ,do what ,in which domain 8 | type Permission struct { 9 | Zone string 10 | Action string 11 | Domain string 12 | } 13 | 14 | // CheckPermission : check permission in all roles of account 15 | func CheckPermission(userId string, p Permission) (bool, error) { 16 | return perm.Enforce(userId, p.Zone, p.Action, p.Domain) 17 | } 18 | 19 | // OverwriteRoles : assign roles to specific user 20 | func OverwriteRoles(userId string, newRoles [][]string) { 21 | currentRoles := perm.GetGroupsByUser(userId) 22 | for k1, newRole := range newRoles { 23 | for k2, currentRole := range currentRoles { 24 | if newRole[0] == currentRole[0] && newRole[1] == currentRole[1] { 25 | newRoles[k1] = []string{"-skip"} 26 | currentRoles[k2] = []string{"-skip"} 27 | } 28 | } 29 | } 30 | for _, newRole := range newRoles { 31 | if newRole[0] == "-skip" { 32 | continue 33 | } 34 | perm.AddGroup(newRole) 35 | } 36 | for _, rmRole := range currentRoles { 37 | if rmRole[0] == "-skip" { 38 | continue 39 | } 40 | perm.DelGroup(rmRole) 41 | } 42 | } 43 | 44 | // DeleteUser Delete user's group policies 45 | func DeleteUser(uid string) { 46 | groups := perm.GetGroupsByUser(uid) 47 | for _, group := range groups { 48 | perm.DelGroup(group) 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /pkg/api/dto/dept.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import "time" 4 | 5 | //DeptCreateDto - binding domain creation params 6 | type DeptCreateDto struct { 7 | Id int `json:"id"` 8 | Name string `form:"name" json:"name" binding:"required"` 9 | ParentId int `form:"parent_id" json:"parent_id"` 10 | OrderNum int `form:"order_num" json:"order_num"` 11 | CreateTime time.Time `type(datetime)" json:"create_time"` 12 | UpdateTime time.Time `type(datetime)" json:"-"` 13 | } 14 | 15 | //DeptEditDto - binding domain edition params 16 | type DeptEditDto struct { 17 | Id int `uri:"id" json:"id" binding:"required"` 18 | Name string `form:"name" json:"name" binding:"required"` 19 | ParentId int `form:"parent_id" json:"parent_id" binding:"gte=0" ` 20 | OrderNum int `form:"order_num" json:"order_num"` 21 | } 22 | -------------------------------------------------------------------------------- /pkg/api/dto/domain.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import "time" 4 | 5 | // DomainListSearchMapping - define search query keys in domain list page 6 | var DomainListSearchMapping = map[string]string{ 7 | "id": "id", 8 | } 9 | 10 | //DomainCreateDto - binding domain creation params 11 | type DomainCreateDto struct { 12 | Id int `json:"id"` 13 | Name string `form:"name" json:"name" binding:"required"` 14 | Callbackurl string `form:"callbackurl" json:"callbackurl" binding:"required"` 15 | Remark string `form:"remark" json:"remark"` 16 | Code string `form:"code" json:"code" binding:"required"` 17 | CreateTime time.Time `type(datetime)" json:"create_time"` 18 | LastLoginTime time.Time `type(datetime)" json:"-"` 19 | } 20 | 21 | //DomainEditDto - binding domain edition params 22 | type DomainEditDto struct { 23 | Id int `uri:"id" json:"id" binding:"required"` 24 | Name string `form:"name" json:"name" binding:"required"` 25 | Callbackurl string `form:"callbackurl" json:"callbackurl"` 26 | Remark string `form:"remark" json:"remark"` 27 | Code string `form:"code" json:"code"` 28 | } 29 | -------------------------------------------------------------------------------- /pkg/api/dto/general.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import ( 4 | "strings" 5 | ) 6 | 7 | // GeneralListDto - General list request params 8 | type GeneralListDto struct { 9 | Skip int `form:"skip,default=0" json:"skip"` 10 | Limit int `form:"limit,default=20" json:"limit" binding:"max=10000"` 11 | Order string `form:"order" json:"order"` 12 | Q string `form:"q" json:"q"` 13 | } 14 | 15 | type GeneralTreeDto struct { 16 | Q string `form:"q" json:"q"` 17 | } 18 | type GeneralDelDto struct { 19 | Id int `uri:"id" json:"id" binding:"required"` 20 | } 21 | type GeneralGetDto struct { 22 | Id int `uri:"id" json:"id" binding:"required"` 23 | } 24 | 25 | // TransformSearch - transform search query 26 | func TransformSearch(qs string, mapping map[string]string) (ss map[string]string) { 27 | ss = make(map[string]string) 28 | for _, v := range strings.Split(qs, ",") { 29 | vs := strings.Split(v, "=") 30 | if _, ok := mapping[vs[0]]; ok { 31 | ss[mapping[vs[0]]] = vs[1] 32 | } 33 | } 34 | return 35 | } 36 | 37 | // 38 | //// TransformSearch - transform search query 39 | //func ReplaceSearch(qs string, mapping map[string]string) string { 40 | // var ss = make(map[string]string) 41 | // for _, v := range strings.Split(qs, ",") { 42 | // vs := strings.Split(v, "=") 43 | // if _, ok := mapping[vs[0]]; ok { 44 | // ss[mapping[vs[0]]] = vs[1] 45 | // } 46 | // } 47 | // return 48 | //} 49 | -------------------------------------------------------------------------------- /pkg/api/dto/init.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import ( 4 | "fmt" 5 | "github.com/gin-gonic/gin" 6 | "github.com/gin-gonic/gin/binding" 7 | "github.com/go-playground/validator/v10" 8 | "github.com/pkg/errors" 9 | "strings" 10 | "zeus/pkg/api/log" 11 | ) 12 | 13 | func init() { 14 | // Register custom validate methods 15 | if v, ok := binding.Validator.Engine().(*validator.Validate); ok { 16 | _ = v.RegisterValidation("pwdValidate", pwdValidate) 17 | _ = v.RegisterValidation("permsValidate", permsValidate) 18 | } else { 19 | log.Fatal("Gin fail to registered custom validator(v10)") 20 | } 21 | } 22 | 23 | // Bind : bind request dto and auto verify parameters 24 | func Bind(c *gin.Context, obj interface{}) error { 25 | _ = c.ShouldBindUri(obj) 26 | if err := c.ShouldBind(obj); err != nil { 27 | if fieldErr, ok := err.(validator.ValidationErrors); ok { 28 | var tagErrorMsg []string 29 | for _, v := range fieldErr { 30 | if _, has := ValidateErrorMessage[v.Tag()]; has { 31 | tagErrorMsg = append(tagErrorMsg, fmt.Sprintf(ValidateErrorMessage[v.Tag()], v.Field(), v.Value())) 32 | } else { 33 | tagErrorMsg = append(tagErrorMsg, err.Error()) 34 | } 35 | } 36 | return errors.New(strings.Join(tagErrorMsg, ",")) 37 | } 38 | } 39 | return nil 40 | } 41 | 42 | //ValidateErrorMessage : customize error messages 43 | var ValidateErrorMessage = map[string]string{ 44 | "customValidate": "%s can not be %s", 45 | "required": "%s is required,got empty %#v", 46 | "pwdValidate": "%s is not a valid password", 47 | "permsValidate": "perms [%s] is not allow to contains comma", 48 | } 49 | -------------------------------------------------------------------------------- /pkg/api/dto/login.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type LoginDto struct { 4 | Username string `form:"username" json:"username" binding:"required"` 5 | Password string `form:"password" json:"password" binding:"required"` 6 | Code string `form:"code" json:"code"` 7 | } 8 | 9 | type TwoFaDto struct { 10 | Username string `form:"username" json:"username" binding:"required"` 11 | } 12 | 13 | // LoginOAuthDto - oauth login 14 | type LoginOAuthDto struct { 15 | Code string `form:"code" binding:"required"` 16 | Type int `form:"type" binding:"required"` 17 | } 18 | 19 | // BindThirdDto - bind third-part account 20 | type BindThirdDto struct { 21 | From int `form:"from"` 22 | Code string `form:"code" binding:"required"` 23 | } 24 | 25 | // UnBindThirdDto - unbind third-part account 26 | type UnBindThirdDto struct { 27 | OAuthType int `form:"from"` 28 | } 29 | 30 | // LoginDingtalkDto - ding talk login 31 | type LoginDingtalkDto struct { 32 | Code string `form:"code"` 33 | } 34 | -------------------------------------------------------------------------------- /pkg/api/dto/login_log.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type LoginLogListDto struct { 4 | Username string `form:"username"` 5 | Ip string `form:"ip"` 6 | StartTime string `form:"start_time"` 7 | EndTime string `form:"end_time"` 8 | Skip int `form:"skip,default=0" json:"skip"` 9 | Limit int `form:"limit,default=20" json:"limit" binding:"max=10000"` 10 | Order string `form:"order" json:"order"` 11 | } 12 | 13 | type LoginLogDto struct { 14 | UserId int `form:"user_id" binding:"required"` 15 | Client string `form:"client"` 16 | Platform string `form:"form"` 17 | Ip string `form:"ip"` 18 | IpLocation string `form:"ip_location"` 19 | LoginResult string `form:"login_result"` 20 | LoginStatus int `form:"login_status"` 21 | OperationContent string `form:"operation_content"` 22 | } 23 | -------------------------------------------------------------------------------- /pkg/api/dto/myaccount.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type BindCodeDto struct { 4 | Google2faToken string `form:"google_2fa_token" valid:"Required"` // 验证码 5 | } 6 | 7 | type VerifyEmailDto struct { 8 | Email string `form:"email" json:"email" valid:"required"` // email 9 | } 10 | 11 | type EmailVerificationDto struct { 12 | Code string `form:"code" binding:"required"` // email 13 | } 14 | -------------------------------------------------------------------------------- /pkg/api/dto/operation_log.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type OperationLogListDto struct { 4 | Username string `form:"username"` 5 | Ip string `form:"ip"` 6 | StartTime string `form:"start_time"` 7 | EndTime string `form:"end_time"` 8 | Skip int `form:"skip,default=0" json:"skip"` 9 | Limit int `form:"limit,default=20" json:"limit" binding:"max=10000"` 10 | Order string `form:"order" json:"order"` 11 | } 12 | 13 | type OperationLogDto struct { 14 | RequestUrl string `form:"request_url"` 15 | OperationMethod string `form:"operation_method"` 16 | Params string `form:"params"` 17 | UserId int `form:"user_id" valid:"Required"` 18 | Ip string `form:"ip"` 19 | IpLocation string `form:"ip_location"` 20 | OperationResult string `form:"operation_result"` 21 | OperationSuccess int `form:"operation_success"` 22 | OperationContent string `form:"operation_content"` 23 | } 24 | -------------------------------------------------------------------------------- /pkg/api/dto/perm.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type CheckPermDto struct { 4 | Domain string `form:"domain" json:"domain" binding:"required"` 5 | Perm string `form:"perm" json:"perm" binding:"required"` 6 | } 7 | -------------------------------------------------------------------------------- /pkg/api/dto/role.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | // RoleListSearchMapping - define search query keys in role list page 4 | var RoleListSearchMapping = map[string]string{ 5 | "n": "name", 6 | "d": "domain_id", 7 | "r": "role_name", 8 | } 9 | 10 | // RoleCreateDto - dto for role's creation 11 | type RoleCreateDto struct { 12 | Name string `form:"name" json:"name" binding:"required"` 13 | DomainId int `form:"domain_id" json:"domain_id" binding:"required,gte=1"` 14 | RoleName string `form:"role_name" json:"role_name" binding:"required"` 15 | Remark string `form:"remark" json:"remark"` 16 | MenuIds string `form:"menu_ids" json:"menu_ids"` 17 | MenuIdsEle string `form:"menu_ids_ele" json:"menu_ids_ele"` 18 | DataPermIds string `form:"data_perm_ids" json:"data_perm_ids"` 19 | } 20 | 21 | // RoleEditDto - dto for role's modification 22 | type RoleEditDto struct { 23 | Id int `uri:"id" json:"id" binding:"required,gte=1"` 24 | Name string `form:"name" json:"name" binding:"required"` 25 | DomainId int `form:"domain_id" json:"domain_id" binding:"required,gte=1"` 26 | Remark string `form:"remark" json:"remark"` 27 | MenuIds string `form:"menu_ids" json:"menu_ids"` 28 | MenuIdsEle string `form:"menu_ids_ele" json:"menu_ids_ele"` 29 | DataPermIds string `form:"data_perm_ids" json:"data_perm_ids"` 30 | } 31 | -------------------------------------------------------------------------------- /pkg/api/dto/role_data_perm.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type AssignDataPermDto struct { 4 | RoleId int `form:"role_id"` 5 | DataPermId int `form:"data_perm_id"` 6 | } 7 | -------------------------------------------------------------------------------- /pkg/api/dto/setting.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | type SettingDTO struct { 4 | LdapUrl string `form:"ldapUrl" json:"ldapUrl"` 5 | LdapSearchDN string `form:"ldapSearchDN" json:"ldapSearchDN"` 6 | LdapSearchPassword string `form:"ldapSearchPassword" json:"ldapSearchPassword"` 7 | LdapBaseDN string `form:"ldapBaseDN" json:"ldapBaseDN"` 8 | LdapFilter string `form:"ldapFilter" json:"ldapFilter"` 9 | LdapUID string `form:"ldapUID" json:"ldapUID"` 10 | LdapGroupBaseDN string `form:"ldapGroupBaseDN" json:"ldapGroupBaseDN"` 11 | LdapGroupFilter string `form:"ldapGroupFilter" json:"ldapGroupFilter"` 12 | LdapGroupGID string `form:"ldapGroupGID" json:"ldapGroupGID"` 13 | LdapGroupAdminDN string `form:"ldapGroupAdminDN" json:"ldapGroupAdminDN"` 14 | } 15 | 16 | type EmailSettingDTO struct { 17 | Port int `form:"port" json:"port"` 18 | SmtpServer string `form:"smtpServer" json:"smtpServer"` 19 | SmtpAddress string `form:"smtpAddress" json:"smtpAddress"` 20 | SmtpUser string `form:"smtpUser" json:"smtpUser"` 21 | SmtpPassword string `form:"smtpPassword" json:"smtpPassword"` 22 | } 23 | -------------------------------------------------------------------------------- /pkg/api/dto/user_oauth.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import "time" 4 | 5 | type UserOAuthCreateDto struct { 6 | Id int `form:"id" json:"id"` 7 | From int `form:"from" json:"from"` 8 | User_id int `form:"user_id" json:"user_id"` 9 | Openid string `form:"openid" json:"openid"` 10 | Unionid string `form:"unionid" json:"unionid"` 11 | Avatar string `form:"avatar" json:"avatar"` 12 | Extra string `form:"extra" json:"extra"` 13 | Name string `form:"name" json:"name"` 14 | CreateTime time.Time `type(datetime)" json:"create_time"` 15 | UpdateTime time.Time `type(datetime)" json:"-"` 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/dto/user_secret.go: -------------------------------------------------------------------------------- 1 | package dto 2 | 3 | import "time" 4 | 5 | type UserSecretCreateDto struct { 6 | Id int `json:"id"` 7 | User_id int `form:"user_id" json:"user_id"` 8 | Account_name string `form:"account_name" json:"account_name"` 9 | Secret string `form:"secret" json:"secret"` 10 | CreateTime time.Time `type(datetime)" json:"create_time"` 11 | UpdateTime time.Time `type(datetime)" json:"-"` 12 | } 13 | 14 | type UserSecretRetDto struct { 15 | Is_open int `json:"is_open"` 16 | Code string `json:"code"` 17 | Account string `json:"account"` 18 | Secret string `json:"secret"` 19 | } 20 | -------------------------------------------------------------------------------- /pkg/api/middleware/cors.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/gin-contrib/cors" 5 | "github.com/gin-gonic/gin" 6 | "github.com/spf13/viper" 7 | "time" 8 | ) 9 | 10 | func Cors() gin.HandlerFunc { 11 | return cors.New(cors.Config{ 12 | AllowOrigins: viper.GetStringSlice("cors.allow_origins"), 13 | AllowMethods: viper.GetStringSlice("cors.allow_methods"), 14 | AllowHeaders: viper.GetStringSlice("cors.allow_headers"), 15 | AllowCredentials: viper.GetBool("cors.allow_credentials"), 16 | MaxAge: time.Second * time.Duration(viper.GetInt("cors.max_age")), 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /pkg/api/middleware/log.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "bytes" 5 | "encoding/json" 6 | "github.com/gin-gonic/gin" 7 | "io/ioutil" 8 | "zeus/pkg/api/dto" 9 | "zeus/pkg/api/log" 10 | "zeus/pkg/api/service" 11 | ) 12 | 13 | var logService = service.LogService{} 14 | var ignoreRoutes = map[string]bool{ 15 | "/v1/account/idle": true, 16 | "/v1/account/password": true, 17 | "/v1/account/require-change-pwd": true, 18 | } 19 | 20 | func AccessLog(c *gin.Context) { 21 | //ignore logs 22 | if _, ok := ignoreRoutes[c.Request.URL.Path]; ok { 23 | c.Next() 24 | return 25 | } 26 | b, _ := json.Marshal(c.Request.URL.Query()) 27 | body, _ := ioutil.ReadAll(c.Request.Body) 28 | c.Request.Body = ioutil.NopCloser(bytes.NewBuffer(body)) 29 | uid := 0 30 | if c.Value("userId") != nil { 31 | uid = int(c.Value("userId").(float64)) 32 | } 33 | orLogDto := dto.OperationLogDto{ 34 | UserId: uid, 35 | RequestUrl: c.Request.URL.Path, 36 | OperationMethod: c.Request.Method, 37 | Params: "[GET] -> " + string(b) + " | [POST] -> " + string(body), 38 | Ip: c.ClientIP(), 39 | IpLocation: "", //TODO...待接入获取ip位置服务 40 | OperationResult: "success", 41 | OperationSuccess: 1, 42 | OperationContent: "-", 43 | } 44 | err := logService.InsertOperationLog(orLogDto) 45 | if err != nil { 46 | log.Error(err.Error()) 47 | } 48 | c.Next() 49 | } 50 | -------------------------------------------------------------------------------- /pkg/api/middleware/perm.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "fmt" 5 | "github.com/beego/i18n" 6 | "github.com/gin-gonic/gin" 7 | "net/http" 8 | "strings" 9 | "zeus/pkg/api/log" 10 | ) 11 | 12 | // Ignored permissions 13 | var ignoredPerms = map[string]bool{} 14 | 15 | // PermCheck - check permission automatically 16 | func PermCheck(c *gin.Context) { 17 | route := strings.Split(c.Request.URL.RequestURI(), "?")[0] 18 | for _, p := range c.Params { 19 | route = strings.Replace(route, "/"+p.Value, "/:"+p.Key, 1) 20 | } 21 | route = strings.ToLower(c.Request.Method) + "@" + route 22 | uid := fmt.Sprintf("%#v", c.Value("userId")) 23 | if _, ok := ignoredPerms[route]; ok { 24 | c.Next() 25 | return 26 | } 27 | check, _ := accountService.CheckPermission(uid, "root", route) 28 | if !check { 29 | log.Warn(fmt.Sprintf("No permission for %s", route)) 30 | c.JSON(http.StatusOK, gin.H{ 31 | "code": 403, 32 | "msg": i18n.Tr(GetLang(), "err.Err403"), 33 | }) 34 | c.Abort() 35 | return 36 | } else { 37 | log.Info(fmt.Sprintf("Pass permission check for %s", route)) 38 | } 39 | c.Next() 40 | } 41 | -------------------------------------------------------------------------------- /pkg/api/middleware/prepare.go: -------------------------------------------------------------------------------- 1 | package middleware 2 | 3 | import ( 4 | "github.com/appleboy/gin-jwt/v2" 5 | "github.com/gin-gonic/gin" 6 | "zeus/pkg/api/model" 7 | ) 8 | 9 | // JwtPrepare : parse jwt and set login session info 10 | func JwtPrepare(c *gin.Context) { 11 | claims := jwt.ExtractClaims(c) 12 | user, _ := c.Get("id") 13 | c.Set("userId", claims["id"]) 14 | c.Set("userName", user.(model.UserClaims).Name) 15 | c.Next() 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/model/base.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Pagination struct { 4 | Start int 5 | Limit int 6 | } 7 | -------------------------------------------------------------------------------- /pkg/api/model/casbin_rule.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type CasbinRule struct { 4 | Id int 5 | PType string 6 | V0 string 7 | V1 string 8 | V2 string 9 | V3 string 10 | V4 string 11 | V5 string 12 | } 13 | 14 | func (CasbinRule) TableName() string { 15 | return "casbin_rule" 16 | } 17 | -------------------------------------------------------------------------------- /pkg/api/model/data_perm.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type DataPerm struct { 4 | Id int `json:"id"` // 自增ID 5 | ParentId int `json:"parent_id"` // 父级id 6 | Name string `json:"name"` // 名称 7 | Perms string `json:"perms"` // 数据权限标识 8 | PermsRule string `json:"perms_rule"` // 数据规则 9 | PermsType int `json:"perms_type"` // 类型 1=分类 2=数据权限 10 | OrderNum int `json:"order_num"` // 排序字段 11 | DomainId int `json:"domain_id"` 12 | Remarks string `json:"remarks"` // 说明 13 | } 14 | 15 | type DataPermQuery struct { 16 | DomainId int 17 | Name string 18 | Pagination *Pagination 19 | } 20 | 21 | func (dp *DataPerm) TableName() string { 22 | return "data_perm" 23 | } 24 | -------------------------------------------------------------------------------- /pkg/api/model/department.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type Department struct { 4 | Id int `json:"id"` 5 | Name string `json:"name"` 6 | OrderNum int `json:"order_num"` 7 | ParentId int `json:"parent_id"` 8 | ExtendField string `json:"extend_field"` 9 | Lft int `json:"lft"` 10 | Rgt int `json:"rgt"` 11 | Level int `json:"level"` 12 | Path string `json:"path"` 13 | } 14 | 15 | func (Department) TableName() string { 16 | return "department" 17 | } 18 | -------------------------------------------------------------------------------- /pkg/api/model/domain.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Domain struct { 8 | Id int `json:"id"` 9 | Name string `json:"name"` 10 | Callbackurl string `json:"callbackurl"` 11 | Remark string `json:"remark"` 12 | Code string `json:"code"` 13 | CreateTime time.Time `json:"create_time" gorm:"column:create_time;not null;default:CURRENT_TIMESTAMP"` 14 | LastUpdateTime time.Time `json:"updated_time" gorm:"column:last_update_time;not null;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"` 15 | } 16 | 17 | func (d *Domain) TableName() string { 18 | return "domain" 19 | } 20 | -------------------------------------------------------------------------------- /pkg/api/model/login_log.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | //login log mapping 8 | type LoginLog struct { 9 | Id int `json:"id"` 10 | UserId int `form:"user_id" json:"user_id" binding:"required"` 11 | Client string `form:"client" json:"client"` 12 | Platform string `form:"platform" json:"platform"` 13 | LoginResult string `form:"login_result" json:"login_result"` 14 | LoginStatus int `form:"login_status" json:"login_status"` 15 | LoginTime time.Time `gorm:"-" json:"login_time"` 16 | Ip string `form:"ip" json:"ip"` 17 | IpLocation string `json:"ip_location"` 18 | OperationTime string `gorm:"-" json:"operation_time"` 19 | OperationContent string `form:"operation_content" json:"operation_content"` 20 | CreateTime time.Time `gorm:"-" json:"-"` 21 | LastUpdateTime time.Time `gorm:"-" json:"-"` 22 | } 23 | 24 | func (log *LoginLog) TableName() string { 25 | return "login_log" 26 | } 27 | -------------------------------------------------------------------------------- /pkg/api/model/menu.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type Menu struct { 8 | Id int `json:"id"` 9 | ParentId int `json:"parent_id"` 10 | DomainId int `json:"domain_id"` 11 | Domain Domain `json:"domain"` 12 | Name string `json:"name"` 13 | Url string `json:"url"` 14 | Perms string `json:"perms"` 15 | Alias string `json:"alias"` 16 | MenuType int `json:"menu_type"` 17 | Icon string `json:"icon"` 18 | OrderNum int `json:"order_num"` 19 | CreateTime time.Time `gorm:"type:time;column:create_time;not null;default:CURRENT_TIMESTAMP" json:"created_time,omitempty" example:"2019-07-10 0:39"` 20 | LastUpdateTime time.Time `gorm:"type:time;column:last_update_time;not null;default:CURRENT_TIMESTAMP ON UPDATE" json:"last_update_time,omitempty" example:"2019-07-10 0:39"` 21 | } 22 | 23 | func (m *Menu) TableName() string { 24 | return "menu" 25 | } 26 | -------------------------------------------------------------------------------- /pkg/api/model/menu_perm_alias.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type MenuPermAlias struct { 4 | Id int `json:"id"` 5 | Perms string `json:"perms"` 6 | Alias string `json:"alias"` 7 | DomainId int `json:"domain_id"` 8 | CreatedTime int64 `json:"created_time"` 9 | UpdatedTime int64 `json:"updated_time"` 10 | } 11 | 12 | func (*MenuPermAlias) TableName() string { 13 | return "menu_perm_alias" 14 | } 15 | -------------------------------------------------------------------------------- /pkg/api/model/operation_log.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | //operation log mapping 6 | type OperationLog struct { 7 | Id int `json:"id"` 8 | LogNo string `form:"log_no" json:"log_no" binding:"required"` 9 | Module string `form:"module" json:"module"` 10 | RequestUrl string `form:"request_url" json:"request_url"` 11 | OperationMethod string `form:"operation_method" json:"operation_method"` 12 | Params string `form:"params" json:"params"` 13 | ExceptionStack string `form:"exception_stack" json:"exception_stack"` 14 | OperationResult string `form:"operation_result" json:"operation_result"` 15 | OperationSuccess int `form:"operation_success" json:"operation_success"` 16 | OperationTime time.Time `gorm:"-" form:"operation_time" json:"operation_time"` 17 | UserId int `form:"user_id" json:"user_id"` 18 | Ip string `form:"ip" json:"ip"` 19 | IpLocation string `form:"ip_location" json:"ip_location"` 20 | OperationContent string `form:"operation_content" json:"operation_content"` 21 | CreateTime time.Time `json:"create_time" gorm:"column:create_time;not null;default:CURRENT_TIMESTAMP"` 22 | LastUpdateTime time.Time `json:"updated_time" gorm:"column:last_update_time;not null;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP"` 23 | } 24 | 25 | func (log *OperationLog) TableName() string { 26 | return "operation_log" 27 | } 28 | -------------------------------------------------------------------------------- /pkg/api/model/role.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | // Role model 4 | type Role struct { 5 | Id int `json:"id"` 6 | Name string `json:"name"` 7 | DomainId int `json:"domain_id"` 8 | Domain Domain `json:"domain"` 9 | DataPerm []DataPerm `json:"data_perm" gorm:"many2many:role_data_perm";"ForeignKey:RoleId"` 10 | RoleName string `json:"role_name"` 11 | Remark string `json:"remark"` 12 | //Users []*User `json:"users" orm:"reverse(many)"` 13 | MenuIds string `json:"menu_ids"` 14 | MenuIdsEle string `json:"menu_ids_ele"` 15 | } 16 | 17 | func (Role) TableName() string { 18 | return "role" 19 | } 20 | 21 | //for更新创建 22 | type RoleEntity struct { 23 | Id int `json:"id"` 24 | Name string `json:"name"` 25 | DomainId int `json:"domain_id"` 26 | RoleName string `json:"role_name"` 27 | Remark string `json:"remark"` 28 | MenuIds string `json:"menu_ids"` 29 | MenuIdsEle string `json:"menu_ids_ele"` 30 | } 31 | -------------------------------------------------------------------------------- /pkg/api/model/role_data_perm.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type RoleDataPerm struct { 4 | Id int `json:"id"` 5 | RoleId int `json:"role_id"` 6 | DataPermId int `json:"data_perm_id"` 7 | } 8 | 9 | type GetByRoleIdData struct { 10 | Id int `json:"id"` 11 | RoleId int `json:"role_id"` 12 | Name string `json:"name"` 13 | Perms string `json:"perms"` 14 | } 15 | 16 | func (r *RoleDataPerm) TableName() string { 17 | return "role_data_perm" 18 | } 19 | -------------------------------------------------------------------------------- /pkg/api/model/setting.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type LdapSetting struct { 4 | LdapUrl string `json:"ldapUrl"` 5 | LdapSearchDN string `json:"ldapSearchDN"` 6 | LdapSearchPassword string `json:"ldapSearchPassword"` 7 | LdapBaseDN string `json:"ldapBaseDN"` 8 | LdapFilter string `json:"ldapFilter"` 9 | LdapUID string `json:"ldapUID"` 10 | LdapGroupBaseDN string `json:"ldapGroupBaseDN"` 11 | LdapGroupFilter string `json:"ldapGroupFilter"` 12 | LdapGroupGID string `json:"ldapGroupGID"` 13 | LdapGroupAdminDN string `json:"ldapGroupAdminDN"` 14 | } 15 | 16 | type EmailSetting struct { 17 | Port int `json:"port"` 18 | SmtpServer string `json:"smtpServer"` 19 | SmtpAddress string `json:"smtpAddress"` 20 | SmtpUser string `json:"smtpUser"` 21 | SmtpPassword string `json:"smtpPassword"` 22 | } 23 | -------------------------------------------------------------------------------- /pkg/api/model/user.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import ( 4 | "time" 5 | ) 6 | 7 | type User struct { 8 | Id int `json:"id" example:"1"` 9 | Username string `json:"username" example:"wutongci"` 10 | Mobile string `json:"mobile" example:"186000000"` 11 | Sex int `json:"sex" example:"1"` 12 | Realname string `json:"realname" example:"黄梧桐"` 13 | Password string `json:"-"` 14 | Salt string `json:"-"` 15 | DepartmentId int `json:"department_id" example:"1"` 16 | Department Department `json:"department" example:"1"` 17 | Faceicon string `json:"faceicon" example:"http://xxx.com"` 18 | Email string `json:"email" example:"xxxx@hotmail.com"` 19 | Title string `json:"title" example:"title"` 20 | Status int `json:"status" example:"1"` 21 | CreateTime time.Time `gorm:"type:time;column:create_time;not null;default:CURRENT_TIMESTAMP" json:"created_time,omitempty" example:"2019-07-10 0:39"` 22 | LastLoginTime time.Time `gorm:"type:time;column:last_login_time;not null;default:CURRENT_TIMESTAMP" json:"logined_time,omitempty" example:"2019-07-10 0:39"` 23 | //Roles []Role `gorm:"many2many:user_role;" json:"roles" example:"roles"` 24 | } 25 | 26 | func (User) TableName() string { 27 | return "user" 28 | } 29 | 30 | type UserClaims struct { 31 | Id int `json:"id"` 32 | Name string `json:"name"` 33 | } 34 | -------------------------------------------------------------------------------- /pkg/api/model/user_oauth.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type UserOAuth struct { 6 | Id int `json:"id"` 7 | From int `json:"from"` 8 | UserId int `json:"user_id"` 9 | Openid string `json:"openid"` 10 | UnionId string `json:"unionid" gorm:"column:unionid"` 11 | Avatar string `json:"avatar"` 12 | Extra string `json:"extra"` 13 | Name string `json:"name"` 14 | CreateTime time.Time `gorm:"type:time;column:create_time;not null;default:CURRENT_TIMESTAMP" json:"create_time,omitempty" example:"2019-07-10 0:39"` 15 | UpdateTime time.Time `gorm:"type:time;column:update_time;not null;default:CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP" json:"update_time,omitempty" example:"2019-07-10 0:39"` 16 | } 17 | 18 | func (ur *UserOAuth) TableName() string { 19 | return "user_oauth" 20 | } 21 | -------------------------------------------------------------------------------- /pkg/api/model/user_role.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | type UserRole struct { 4 | Id int 5 | UserId int `sql:"index"` 6 | RoleId int `sql:"index"` 7 | } 8 | 9 | func (UserRole) TableName() string { 10 | return "user_role" 11 | } 12 | -------------------------------------------------------------------------------- /pkg/api/model/user_secret.go: -------------------------------------------------------------------------------- 1 | package model 2 | 3 | import "time" 4 | 5 | type UserSecret struct { 6 | Id int `json:"id"` 7 | User_id int `json:"user_id"` 8 | Account_name string `json:"account_name"` 9 | Secret string `json:"secret"` 10 | Is_open int `json:"is_open"` 11 | CreateTime time.Time `json:"create_time"` 12 | UpdateTime time.Time `json:"update_time"` 13 | } 14 | 15 | type UserSecretQuery struct { 16 | Is_open int 17 | Account_name string 18 | Secret string 19 | } 20 | 21 | func (ur *UserSecret) TableName() string { 22 | return "user_secret" 23 | } 24 | -------------------------------------------------------------------------------- /pkg/api/service/dingtalk.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | dingtalk "github.com/bullteam/go-dingtalk/src" 5 | "github.com/spf13/viper" 6 | "strings" 7 | "zeus/pkg/api/domain/sync/dingdingtalk" 8 | "zeus/pkg/api/dto" 9 | ) 10 | 11 | type DingTalkService struct{} 12 | 13 | func (ds DingTalkService) SyncUsersAndDepartments() { 14 | departments, err := dingdingtalk.GetDepartments() 15 | if err != nil { 16 | return 17 | } 18 | ds.SyncRecursive(departments.(map[int][]dingtalk.Department), 0, 0) 19 | } 20 | 21 | func (ds DingTalkService) SyncRecursive(departments map[int][]dingtalk.Department, id int, pid int) { 22 | for _, d := range departments[id] { 23 | created := DeptService.Create(DeptService{}, dto.DeptCreateDto{ 24 | Name: d.Name, 25 | ParentId: pid, 26 | }) 27 | if _, ok := departments[d.Id]; ok { 28 | ds.SyncRecursive(departments, d.Id, created.Id) 29 | } 30 | users, err2 := dingdingtalk.GetUsers(d.Id) 31 | if err2 != nil || len(users.([]dingtalk.UDetailedList)) < 1 { 32 | continue 33 | } 34 | for _, u := range users.([]dingtalk.UDetailedList) { 35 | userName := u.Name 36 | if u.Email != "" { 37 | userName = strings.Split(u.Email, "@")[0] 38 | } 39 | _, _ = UserService.Create(UserService{}, dto.UserCreateDto{ 40 | Username: userName, 41 | Realname: u.Name, 42 | Mobile: u.Mobile, 43 | Email: u.Email, 44 | Title: u.Position, 45 | Status: 1, 46 | Sex: 0, 47 | DepartmentId: created.Id, 48 | Password: viper.GetString("dingtalk.defaultPwd"), 49 | }) 50 | } 51 | } 52 | } 53 | -------------------------------------------------------------------------------- /pkg/api/service/install.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "github.com/spf13/viper" 5 | "zeus/pkg/api/dto" 6 | ) 7 | 8 | type InstallService struct { 9 | } 10 | 11 | func (us InstallService) Install(dto dto.InstallDTO) bool { 12 | if viper.GetBool("security.install_lock") { 13 | return false 14 | } 15 | 16 | //base 17 | viper.Set("security.install_lock", true) 18 | viper.Set("base.siteName", dto.SiteName) 19 | viper.Set("base.port", dto.Port) 20 | viper.Set("base.baseUrl", dto.BaseUrl) 21 | viper.Set("base.logPath", dto.LogPath) 22 | viper.Set("base.isEnableCode", dto.IsEnableCode) 23 | viper.Set("base.isEnableAccess", dto.IsEnableAccess) 24 | 25 | //sql 26 | viper.Set("database.driver", dto.SqlType) 27 | viper.Set("database.sqlite.dsn", dto.DataPath) 28 | viper.Set("database.mysql.host", dto.SqlHost) 29 | viper.Set("database.mysql.user", dto.SqlUser) 30 | viper.Set("database.mysql.password", dto.SqlPassword) 31 | viper.Set("database.mysql.name", dto.SqlName) 32 | viper.Set("database.mysql.charset", dto.SqlCharset) 33 | viper.Set("database.mysql.ssl", dto.SqlSSL) 34 | 35 | //Email 36 | viper.Set("email.smtp.port", dto.Port) 37 | viper.Set("email.smtp.address", dto.SmtpAddress) 38 | viper.Set("email.smtp.password", dto.SmtpPassword) 39 | viper.Set("email.smtp.server", dto.SmtpServer) 40 | viper.Set("email.smtp.user", dto.SmtpUser) 41 | 42 | err := viper.WriteConfig() 43 | if err == nil { 44 | return true 45 | } 46 | return false 47 | } 48 | 49 | func (us InstallService) Islock() bool { 50 | return viper.GetBool("security.install_lock") 51 | } 52 | -------------------------------------------------------------------------------- /pkg/api/service/menu_perm_alias.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "zeus/pkg/api/dao" 5 | ) 6 | 7 | var menuPermAlias = dao.MenuPermAlias{} 8 | 9 | //MenuPermAlias 10 | type MenuPermAlias struct { 11 | } 12 | 13 | // GetByAlias - now just for `perm` middleware to automatically check alias record 14 | //func (MenuPermAlias) GetByAlias (alias string) model.MenuPermAlias { 15 | // return menuPermAlias.GetByAlias(alias) 16 | //} 17 | -------------------------------------------------------------------------------- /pkg/api/service/user_secret.go: -------------------------------------------------------------------------------- 1 | package service 2 | 3 | import ( 4 | "zeus/pkg/api/dao" 5 | "zeus/pkg/api/dto" 6 | "zeus/pkg/api/log" 7 | "zeus/pkg/api/model" 8 | ) 9 | 10 | var userSecretDao = dao.UserSecretDao{} 11 | 12 | // DomainService 13 | type UserSecretService struct { 14 | } 15 | 16 | // InfoOfId - get role info by id 17 | func (us UserSecretService) InfoOfId(dto dto.GeneralGetDto) model.UserSecret { 18 | return userSecretDao.Get(dto.Id) 19 | } 20 | 21 | // Create - create a new domain 22 | func (us UserSecretService) Create(dto dto.UserSecretCreateDto) model.UserSecret { 23 | userSecret := model.UserSecret{ 24 | User_id: dto.User_id, 25 | Account_name: dto.Account_name, 26 | Secret: dto.Secret, 27 | } 28 | c := userSecretDao.Create(&userSecret) 29 | if c.Error != nil { 30 | log.Error(c.Error.Error()) 31 | } 32 | return userSecret 33 | } 34 | -------------------------------------------------------------------------------- /pkg/api/utils/utils.go: -------------------------------------------------------------------------------- 1 | package utils 2 | 3 | import ( 4 | "math/rand" 5 | "reflect" 6 | "time" 7 | ) 8 | 9 | const charset = "abcdefghijklmnopqrstuvwxyz" + 10 | "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" + 11 | "@#$%^&*(~)" 12 | 13 | var seededRand = rand.New( 14 | rand.NewSource(time.Now().UnixNano())) 15 | 16 | func StringWithCharset(length int, charset string) string { 17 | b := make([]byte, length) 18 | for i := range b { 19 | b[i] = charset[seededRand.Intn(len(charset))] 20 | } 21 | return string(b) 22 | } 23 | 24 | func RandomPwd(length int) string { 25 | return StringWithCharset(length, charset) 26 | } 27 | func StringSliceRemove(s [][]string, i int) [][]string { 28 | s[i] = s[len(s)-1] 29 | return s[:len(s)-1] 30 | } 31 | func IsNilObject(object interface{}) bool { 32 | if object == nil { 33 | return true 34 | } 35 | 36 | value := reflect.ValueOf(object) 37 | kind := value.Kind() 38 | if kind >= reflect.Chan && kind <= reflect.Slice && value.IsNil() { 39 | return true 40 | } 41 | 42 | return false 43 | } 44 | -------------------------------------------------------------------------------- /pkg/webui/.babelrc: -------------------------------------------------------------------------------- 1 | { 2 | "presets": [ 3 | ["env", { 4 | "modules": "commonjs", 5 | "targets": { 6 | "browsers": ["> 1%", "last 2 versions", "not ie <= 8"] 7 | } 8 | }], 9 | "stage-2" 10 | ], 11 | "plugins": ["transform-vue-jsx", "transform-runtime"], 12 | "env": { 13 | "development":{ 14 | "plugins": ["dynamic-import-node"] 15 | } 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /pkg/webui/.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | insert_final_newline = false 14 | trim_trailing_whitespace = false 15 | -------------------------------------------------------------------------------- /pkg/webui/.eslintignore: -------------------------------------------------------------------------------- 1 | build/*.js 2 | config/*.js 3 | src/assets 4 | -------------------------------------------------------------------------------- /pkg/webui/.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | node_modules/ 3 | npm-debug.log* 4 | yarn-debug.log* 5 | yarn-error.log* 6 | **/*.log 7 | 8 | test/unit/coverage 9 | test/e2e/reports 10 | selenium-debug.log 11 | 12 | # Editor directories and files 13 | .idea 14 | .vscode 15 | *.suo 16 | *.ntvs* 17 | *.njsproj 18 | *.sln 19 | 20 | package-lock.json 21 | -------------------------------------------------------------------------------- /pkg/webui/.postcssrc.js: -------------------------------------------------------------------------------- 1 | // https://github.com/michael-ciniawsky/postcss-load-config 2 | 3 | module.exports = { 4 | "plugins": { 5 | "postcss-import": {}, 6 | "postcss-url": {}, 7 | // to edit target browsers: use "browserslist" field in package.json 8 | "autoprefixer": {} 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /pkg/webui/.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: stable 3 | script: npm run test 4 | notifications: 5 | email: false 6 | -------------------------------------------------------------------------------- /pkg/webui/build/vue-loader.conf.js: -------------------------------------------------------------------------------- 1 | 'use strict' 2 | 3 | module.exports = { 4 | //You can set the vue-loader configuration by yourself. 5 | } 6 | -------------------------------------------------------------------------------- /pkg/webui/config/dev.env.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | NODE_ENV: '"development"', 3 | ENV_CONFIG: '"dev"', 4 | 5 | // 以下是不同 api 接口配置 6 | // 主平台 7 | // 'ZEUS_ADMIN_URL': '"//api.auth.bullteam.local"' 8 | 'ZEUS_ADMIN_URL': '"//127.0.0.1:8082"' 9 | } 10 | -------------------------------------------------------------------------------- /pkg/webui/config/prev.env.js: -------------------------------------------------------------------------------- 1 | // 公共开发环境 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | ENV_CONFIG: '"prev"', 5 | 6 | // 以下是不同 api 接口配置 7 | // 主域名 8 | 'ZEUS_ADMIN_URL': '"//api.admin.bullteam.cn"' 9 | } 10 | -------------------------------------------------------------------------------- /pkg/webui/config/prod.env.js: -------------------------------------------------------------------------------- 1 | // 生成环境 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | ENV_CONFIG: '"prod"', 5 | 6 | // 以下是不同 api 接口配置 7 | // 主域名 8 | 'ZEUS_ADMIN_URL': '"//api.auth.bullteam.cn"' 9 | } 10 | -------------------------------------------------------------------------------- /pkg/webui/config/test.env.js: -------------------------------------------------------------------------------- 1 | // 测试环境 2 | module.exports = { 3 | NODE_ENV: '"production"', 4 | ENV_CONFIG: '"test"', 5 | 6 | // 以下是不同 api 接口配置 7 | // 主域名 8 | 'ZEUS_ADMIN_URL': '"//api.admin.bullteam.test"' 9 | } 10 | -------------------------------------------------------------------------------- /pkg/webui/config/work.env.js: -------------------------------------------------------------------------------- 1 | // 测试环境 2 | module.exports = { 3 | NODE_ENV: '"development"', 4 | ENV_CONFIG: '"work"', 5 | 6 | // 以下是不同 api 接口配置 7 | // 主域名 8 | // 'ZEUS_ADMIN_URL': '"//127.0.0.1:8082"' 9 | } 10 | -------------------------------------------------------------------------------- /pkg/webui/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bullteam/zeus-admin/203d4b03596412c9a58e553879066fc51f39c595/pkg/webui/favicon.ico -------------------------------------------------------------------------------- /pkg/webui/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 |
4 | 5 | 6 | 7 | 8 |