diff --git a/SECURITY.md b/SECURITY.md new file mode 100644 index 0000000000000000000000000000000000000000..db76aea0b420eaa41320c87a0cc1bd2e5bf83e79 --- /dev/null +++ b/SECURITY.md @@ -0,0 +1,5 @@ +# Security Policy + +## Reporting a Vulnerability + +Please report security issues to qimiaojiangjizhao@gmail.com diff --git a/server/README.md b/server/README.md index 2305e4942728d75540d9fb18d939407766c18e8a..9a34870bc3cc643de07e140b36602c8de442644f 100644 --- a/server/README.md +++ b/server/README.md @@ -1,44 +1,54 @@ +## server项目结构 + +```shell +├── api +│   └── v1 +├── config +├── core +├── docs +├── global +├── initialize +│   └── internal +├── middleware +├── model +│   ├── request +│   └── response +├── packfile +├── resource +│   ├── excel +│   ├── page +│   └── template +├── router +├── service +├── source +└── utils + ├── timer + └── upload +``` + +| 文件夹 | 说明 | 描述 | +| ------------ | ----------------------- | --------------------------- | +| `api` | api层 | api层 | +| `--v1` | v1版本接口 | v1版本接口 | +| `config` | 配置包 | config.yaml对应的配置结构体 | +| `core` | 核心文件 | 核心组件(zap, viper, server)的初始化 | +| `docs` | swagger文档目录 | swagger文档目录 | +| `global` | 全局对象 | 全局对象 | +| `initialize` | 初始化 | router,redis,gorm,validator, timer的初始化 | +| `--internal` | 初始化内部函数 | gorm 的 longger 自定义,在此文件夹的函数只能由 `initialize` 层进行调用 | +| `middleware` | 中间件层 | 用于存放 `gin` 中间件代码 | +| `model` | 模型层 | 模型对应数据表 | +| `--request` | 入参结构体 | 接收前端发送到后端的数据。 | +| `--response` | 出参结构体 | 返回给前端的数据结构体 | +| `packfile` | 静态文件打包 | 静态文件打包 | +| `resource` | 静态资源文件夹 | 负责存放静态文件 | +| `--excel` | excel导入导出默认路径 | excel导入导出默认路径 | +| `--page` | 表单生成器 | 表单生成器 打包后的dist | +| `--template` | 模板 | 模板文件夹,存放的是代码生成器的模板 | +| `router` | 路由层 | 路由层 | +| `service` | service层 | 存放业务逻辑问题 | +| `source` | source层 | 存放初始化数据的函数 | +| `utils` | 工具包 | 工具函数封装 | +| `--timer` | timer | 定时器接口封装 | +| `--upload` | oss | oss接口封装 | -整理代码结构 -``` lua -web -├── api/v1 -- 主要API -| ├── sys_initdb.go -- ico -| └── sys_user.go -- -├── config -- 配置文件 设定操作的结构体 -| ├── auto_code.go -- ico captcha.go -| ├── ... -- ico captcha.go -| └── zap.go -- core -├── core -- 主要结构代码 -| ├── server_other.go -- ico captcha.go -| ├── ... -- ico captcha.go -| └── zap.go -- -├── docs -- 文档系统 -| ├── docs.go -- ico captcha.go -| ├── swagger.json -- json -| └── swagger.yaml -- yaml -├── global -- global -├── initialize -- initialize -├── middleware -- 中间键 -├── model -- global -│ ├── request -- 所有请求model结构体 -| | ├── common.go -| | ├── ... -| | └── sys_user.go -- yaml -| ├── response -- 返回数据 -| | ├── common.go -| | ├── ... -| | └── sys_user.go -- yaml -├── packfile -- 文件写入 -├── resource -- 资源文件 -├── router -- 路由 -├── service -- service层 -├── source -- 文件目录操作 -├── utils -├── config.yaml -- -├── Dockerfile -- docker配置 -├── go.mod -- mod 配置 -├── go.sum -- sum -├── latest_log -- vue-cli 配置 -└── main.go -- package.json -``` \ No newline at end of file diff --git a/server/config.yaml b/server/config.yaml index 9d969a7d1783d717825d1b2d9cfe55c108b25edd..716b007f37c53d1e743ce6c7a4c725da4671c663 100644 --- a/server/config.yaml +++ b/server/config.yaml @@ -104,6 +104,7 @@ aliyun-oss: access-key-secret: 'yourAccessKeySecret' bucket-name: 'yourBucketName' bucket-url: 'yourBucketUrl' + base-path: 'yourBasePath' # tencent cos configuration tencent-cos: diff --git a/server/config/gorm.go b/server/config/gorm.go index 2524b190eea7bb31f388f0e4b5f9e1776304c8fa..ae6c73843ceed7b8b9f16157945663c09f425c33 100644 --- a/server/config/gorm.go +++ b/server/config/gorm.go @@ -8,8 +8,8 @@ type Mysql struct { Password string `mapstructure:"password" json:"password" yaml:"password"` // 数据库密码 MaxIdleConns int `mapstructure:"max-idle-conns" json:"maxIdleConns" yaml:"max-idle-conns"` // 空闲中的最大连接数 MaxOpenConns int `mapstructure:"max-open-conns" json:"maxOpenConns" yaml:"max-open-conns"` // 打开到数据库的最大连接数 - LogMode bool `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` // 是否开启Gorm全局日志 - LogZap string `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"` + LogMode string `mapstructure:"log-mode" json:"logMode" yaml:"log-mode"` // 是否开启Gorm全局日志 + LogZap bool `mapstructure:"log-zap" json:"logZap" yaml:"log-zap"` // 是否通过zap写入日志文件 } func (m *Mysql) Dsn() string { diff --git a/server/config/oss.go b/server/config/oss.go index a78420afa006dac6de00769d3431660aff5450b7..37957ddf0aad8de5716bf47478e812d376ef7b17 100644 --- a/server/config/oss.go +++ b/server/config/oss.go @@ -20,6 +20,7 @@ type AliyunOSS struct { AccessKeySecret string `mapstructure:"access-key-secret" json:"accessKeySecret" yaml:"access-key-secret"` BucketName string `mapstructure:"bucket-name" json:"bucketName" yaml:"bucket-name"` BucketUrl string `mapstructure:"bucket-url" json:"bucketUrl" yaml:"bucket-url"` + BasePath string `mapstructure:"base-path" json:"basePath" yaml:"base-path"` } type TencentCOS struct { Bucket string `mapstructure:"bucket" json:"bucket" yaml:"bucket"` diff --git a/server/core/server.go b/server/core/server.go index 5351a2bfab1f2b428009b1ca5976aa2a6c7ecceb..9839a5ac3152429904f425e42ea3ee6bd2affbc1 100644 --- a/server/core/server.go +++ b/server/core/server.go @@ -29,7 +29,7 @@ func RunWindowsServer() { fmt.Printf(` 欢迎使用 Gin-Vue-Admin - 当前版本:V2.4.2 + 当前版本:V2.4.3 加群方式:微信号:shouzi_1994 QQ群:622360840 默认自动化文档地址:http://127.0.0.1%s/swagger/index.html 默认前端文件运行地址:http://127.0.0.1:8080 diff --git a/server/initialize/gorm.go b/server/initialize/gorm.go index 0ac364c94ee3d7c0acd7716ac67e9829baf58243..c3d997c864129ee7f649e3a5c35e012e921c6e6e 100644 --- a/server/initialize/gorm.go +++ b/server/initialize/gorm.go @@ -78,7 +78,7 @@ func GormMysql() *gorm.DB { DontSupportRenameColumn: true, // 用 `change` 重命名列,MySQL 8 之前的数据库和 MariaDB 不支持重命名列 SkipInitializeWithVersion: false, // 根据版本自动配置 } - if db, err := gorm.Open(mysql.New(mysqlConfig), gormConfig(m.LogMode)); err != nil { + if db, err := gorm.Open(mysql.New(mysqlConfig), gormConfig()); err != nil { //global.GVA_LOG.Error("MySQL启动异常", zap.Any("err", err)) //os.Exit(0) //return nil @@ -97,9 +97,9 @@ func GormMysql() *gorm.DB { //@param: mod bool //@return: *gorm.Config -func gormConfig(mod bool) *gorm.Config { - var config = &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true} - switch global.GVA_CONFIG.Mysql.LogZap { +func gormConfig() *gorm.Config { + config := &gorm.Config{DisableForeignKeyConstraintWhenMigrating: true} + switch global.GVA_CONFIG.Mysql.LogMode { case "silent", "Silent": config.Logger = internal.Default.LogMode(logger.Silent) case "error", "Error": @@ -108,14 +108,8 @@ func gormConfig(mod bool) *gorm.Config { config.Logger = internal.Default.LogMode(logger.Warn) case "info", "Info": config.Logger = internal.Default.LogMode(logger.Info) - case "zap", "Zap": - config.Logger = internal.Default.LogMode(logger.Info) default: - if mod { - config.Logger = internal.Default.LogMode(logger.Info) - break - } - config.Logger = internal.Default.LogMode(logger.Silent) + config.Logger = internal.Default.LogMode(logger.Info) } return config } diff --git a/server/initialize/internal/logger.go b/server/initialize/internal/logger.go index e44f563c52f69aaba789217fd77c97ad8b50c120..c7fe925489a717e48d14cbd8e0e4a1c6362746d1 100644 --- a/server/initialize/internal/logger.go +++ b/server/initialize/internal/logger.go @@ -4,7 +4,6 @@ import ( "context" "fmt" "gin-vue-admin/global" - "go.uber.org/zap" "gorm.io/gorm/logger" "gorm.io/gorm/utils" "io/ioutil" @@ -13,11 +12,6 @@ import ( "time" ) -// writer log writer interface -type writer interface { - Printf(string, ...interface{}) -} - type config struct { SlowThreshold time.Duration Colorful bool @@ -34,27 +28,27 @@ var ( Recorder = traceRecorder{Interface: Default, BeginAt: time.Now()} ) -func New(writer writer, config config) logger.Interface { +func New(writer logger.Writer, config config) logger.Interface { var ( infoStr = "%s\n[info] " warnStr = "%s\n[warn] " errStr = "%s\n[error] " - traceStr = "%s\n[%.3fms] [rows:%v] %s" - traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s" - traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s" + traceStr = "%s\n[%.3fms] [rows:%v] %s\n" + traceWarnStr = "%s %s\n[%.3fms] [rows:%v] %s\n" + traceErrStr = "%s %s\n[%.3fms] [rows:%v] %s\n" ) if config.Colorful { infoStr = logger.Green + "%s\n" + logger.Reset + logger.Green + "[info] " + logger.Reset warnStr = logger.BlueBold + "%s\n" + logger.Reset + logger.Magenta + "[warn] " + logger.Reset errStr = logger.Magenta + "%s\n" + logger.Reset + logger.Red + "[error] " + logger.Reset - traceStr = logger.Green + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s" - traceWarnStr = logger.Green + "%s " + logger.Yellow + "%s\n" + logger.Reset + logger.RedBold + "[%.3fms] " + logger.Yellow + "[rows:%v]" + logger.Magenta + " %s" + logger.Reset - traceErrStr = logger.RedBold + "%s " + logger.MagentaBold + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s" + traceStr = logger.Green + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s\n" + traceWarnStr = logger.Green + "%s " + logger.Yellow + "%s\n" + logger.Reset + logger.RedBold + "[%.3fms] " + logger.Yellow + "[rows:%v]" + logger.Magenta + " %s\n" + logger.Reset + traceErrStr = logger.RedBold + "%s " + logger.MagentaBold + "%s\n" + logger.Reset + logger.Yellow + "[%.3fms] " + logger.BlueBold + "[rows:%v]" + logger.Reset + " %s\n" } - return &customLogger{ - writer: writer, + return &_logger{ + Writer: writer, config: config, infoStr: infoStr, warnStr: warnStr, @@ -65,43 +59,43 @@ func New(writer writer, config config) logger.Interface { } } -type customLogger struct { - writer +type _logger struct { config + logger.Writer infoStr, warnStr, errStr string traceStr, traceErrStr, traceWarnStr string } // LogMode log mode -func (c *customLogger) LogMode(level logger.LogLevel) logger.Interface { +func (c *_logger) LogMode(level logger.LogLevel) logger.Interface { newLogger := *c newLogger.LogLevel = level return &newLogger } // Info print info -func (c *customLogger) Info(ctx context.Context, message string, data ...interface{}) { +func (c *_logger) Info(ctx context.Context, message string, data ...interface{}) { if c.LogLevel >= logger.Info { c.Printf(c.infoStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...) } } // Warn print warn messages -func (c *customLogger) Warn(ctx context.Context, message string, data ...interface{}) { +func (c *_logger) Warn(ctx context.Context, message string, data ...interface{}) { if c.LogLevel >= logger.Warn { c.Printf(c.warnStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...) } } // Error print error messages -func (c *customLogger) Error(ctx context.Context, message string, data ...interface{}) { +func (c *_logger) Error(ctx context.Context, message string, data ...interface{}) { if c.LogLevel >= logger.Error { c.Printf(c.errStr+message, append([]interface{}{utils.FileWithLineNum()}, data...)...) } } // Trace print sql message -func (c *customLogger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { +func (c *_logger) Trace(ctx context.Context, begin time.Time, fc func() (string, int64), err error) { if c.LogLevel > 0 { elapsed := time.Since(begin) switch { @@ -131,35 +125,11 @@ func (c *customLogger) Trace(ctx context.Context, begin time.Time, fc func() (st } } -func (c *customLogger) Printf(message string, data ...interface{}) { - if global.GVA_CONFIG.Mysql.LogZap != "" { - switch len(data) { - case 0: - global.GVA_LOG.Info(message) - case 1: - global.GVA_LOG.Info("gorm", zap.Any("src", data[0])) - case 2: - global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1])) - case 3: - global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2])) - case 4: - global.GVA_LOG.Info("gorm", zap.Any("src", data[0]), zap.Any("duration", data[1]), zap.Any("rows", data[2]), zap.Any("sql", data[3])) - } - return - } - switch len(data) { - case 0: - c.writer.Printf(message, "") - case 1: - c.writer.Printf(message, data[0]) - case 2: - c.writer.Printf(message, data[0], data[1]) - case 3: - c.writer.Printf(message, data[0], data[1], data[2]) - case 4: - c.writer.Printf(message, data[0], data[1], data[2], data[3]) - case 5: - c.writer.Printf(message, data[0], data[1], data[2], data[3], data[4]) +func (c *_logger) Printf(message string, data ...interface{}) { + if global.GVA_CONFIG.Mysql.LogZap { + global.GVA_LOG.Info(fmt.Sprintf(message, data...)) + } else { + c.Writer.Printf(message, data...) } } diff --git a/server/initialize/timer.go b/server/initialize/timer.go index 6fa2791372e4d74ede099adf0b1e1147abde1e5b..ecc41c8d58441119774190e7d127c66b6638f675 100644 --- a/server/initialize/timer.go +++ b/server/initialize/timer.go @@ -10,7 +10,6 @@ import ( func Timer() { if global.GVA_CONFIG.Timer.Start { for _, detail := range global.GVA_CONFIG.Timer.Detail { - fmt.Println(detail) go func(detail config.Detail) { global.GVA_Timer.AddTaskByFunc("ClearDB", global.GVA_CONFIG.Timer.Spec, func() { err := utils.ClearTable(global.GVA_DB, detail.TableName, detail.CompareField, detail.Interval) diff --git a/server/service/sys_base_menu.go b/server/service/sys_base_menu.go index f6f60bd034d84b1cb831e37d060c32f104742063..3e6378a753963ca22057ed2c5921ce31ed1a0a33 100644 --- a/server/service/sys_base_menu.go +++ b/server/service/sys_base_menu.go @@ -40,6 +40,7 @@ func UpdateBaseMenu(menu model.SysBaseMenu) (err error) { var oldMenu model.SysBaseMenu upDateMap := make(map[string]interface{}) upDateMap["keep_alive"] = menu.KeepAlive + upDateMap["close_tab"] = menu.CloseTab upDateMap["default_menu"] = menu.DefaultMenu upDateMap["parent_id"] = menu.ParentId upDateMap["path"] = menu.Path diff --git a/server/source/authority_menu.go b/server/source/authority_menu.go index 24cecdd54aef4f45dac697d3676b460830e2e5a2..ddd9a1731dad501f84e98ab701418fd7192ecc81 100644 --- a/server/source/authority_menu.go +++ b/server/source/authority_menu.go @@ -17,7 +17,7 @@ func (a *authorityMenu) Init() error { color.Danger.Println("\n[Mysql] --> authority_menu 视图已存在!") return nil } - if err := global.GVA_DB.Exec("CREATE ALGORITHM = UNDEFINED SQL SECURITY DEFINER VIEW `authority_menu` AS select `sys_base_menus`.`id` AS `id`,`sys_base_menus`.`created_at` AS `created_at`, `sys_base_menus`.`updated_at` AS `updated_at`, `sys_base_menus`.`deleted_at` AS `deleted_at`, `sys_base_menus`.`menu_level` AS `menu_level`,`sys_base_menus`.`parent_id` AS `parent_id`,`sys_base_menus`.`path` AS `path`,`sys_base_menus`.`name` AS `name`,`sys_base_menus`.`hidden` AS `hidden`,`sys_base_menus`.`component` AS `component`, `sys_base_menus`.`title` AS `title`,`sys_base_menus`.`icon` AS `icon`,`sys_base_menus`.`sort` AS `sort`,`sys_authority_menus`.`sys_authority_authority_id` AS `authority_id`,`sys_authority_menus`.`sys_base_menu_id` AS `menu_id`,`sys_base_menus`.`keep_alive` AS `keep_alive`,`sys_base_menus`.`default_menu` AS `default_menu` from (`sys_authority_menus` join `sys_base_menus` on ((`sys_authority_menus`.`sys_base_menu_id` = `sys_base_menus`.`id`)))").Error; err != nil { + if err := global.GVA_DB.Exec("CREATE ALGORITHM = UNDEFINED SQL SECURITY DEFINER VIEW `authority_menu` AS select `sys_base_menus`.`id` AS `id`,`sys_base_menus`.`created_at` AS `created_at`, `sys_base_menus`.`updated_at` AS `updated_at`, `sys_base_menus`.`deleted_at` AS `deleted_at`, `sys_base_menus`.`menu_level` AS `menu_level`,`sys_base_menus`.`parent_id` AS `parent_id`,`sys_base_menus`.`path` AS `path`,`sys_base_menus`.`name` AS `name`,`sys_base_menus`.`hidden` AS `hidden`,`sys_base_menus`.`component` AS `component`, `sys_base_menus`.`title` AS `title`,`sys_base_menus`.`icon` AS `icon`,`sys_base_menus`.`sort` AS `sort`,`sys_authority_menus`.`sys_authority_authority_id` AS `authority_id`,`sys_authority_menus`.`sys_base_menu_id` AS `menu_id`,`sys_base_menus`.`keep_alive` AS `keep_alive`,`sys_base_menus`.`close_tab` AS `close_tab`,`sys_base_menus`.`default_menu` AS `default_menu` from (`sys_authority_menus` join `sys_base_menus` on ((`sys_authority_menus`.`sys_base_menu_id` = `sys_base_menus`.`id`)))").Error; err != nil { return err } color.Info.Println("\n[Mysql] --> authority_menu 视图创建成功!") diff --git a/server/utils/upload/aliyun_oss.go b/server/utils/upload/aliyun_oss.go index fcba9700860075a3a272510119f786dfe9c8d543..beb7b2bc656eb5e114eec561438cbb41a640b788 100644 --- a/server/utils/upload/aliyun_oss.go +++ b/server/utils/upload/aliyun_oss.go @@ -6,7 +6,6 @@ import ( "github.com/aliyun/aliyun-oss-go-sdk/oss" "go.uber.org/zap" "mime/multipart" - "path/filepath" "time" ) @@ -27,7 +26,8 @@ func (*AliyunOSS) UploadFile(file *multipart.FileHeader) (string, string, error) } defer f.Close() // 创建文件 defer 关闭 // 上传阿里云路径 文件名格式 自己可以改 建议保证唯一性 - yunFileTmpPath := filepath.Join("uploads", time.Now().Format("2006-01-02")) + "/" + file.Filename + //yunFileTmpPath := filepath.Join("uploads", time.Now().Format("2006-01-02")) + "/" + file.Filename + yunFileTmpPath := global.GVA_CONFIG.AliyunOSS.BasePath + "/" + "uploads" + "/" + time.Now().Format("2006-01-02") + "/" + file.Filename // 上传文件流。 err = bucket.PutObject(yunFileTmpPath, f) diff --git a/web/README.md b/web/README.md index ad0c9d58824a37ae60c4dbd035054b5786f8f1ad..bd6807479d17637bec836d9e10c2d7df547683cb 100644 --- a/web/README.md +++ b/web/README.md @@ -38,6 +38,10 @@ web │ ├── api -- 所有请求 │ ├── assets -- 主题 字体等静态资源 | ├── components -- components组件 +| ├── core -- gva抽离的一些前端资源 +| | ├── config.js -- 配置文件 +| | └── element_lazy.js -- elementt按需引入文件 +| | └── gin-vue-admin.js -- gva前端控制库 | ├── directive -- 公用方法 | ├── mixins -- 公用方法 | ├── router -- 路由权限 @@ -57,15 +61,20 @@ web | | ├── example --上传案例 | | ├── iconList -- icon列表 | | ├── init -- 初始化数据 +| | | ├── index -- 新版本 +| | | ├── init -- 旧版本 | | ├── layout -- layout约束页面 | | | ├── aside -- | | | ├── bottomInfo -- bottomInfo | | | ├── screenfull -- 全屏设置 +| | | ├── setting -- 系统设置 | | | └── index.vue -- base 约束 -| | ├── login --结算单管理 -| | ├── person --结算单管理 +| | ├── login --登录 +| | ├── person --个人中心 | | ├── superAdmin -- 超级管理员操作 -| | └── home.vue -- page 入口页面 +| | ├── system -- 系统检测页面 +| | ├── systemTools -- 系统配置相关页面 +| | └── routerHolder.vue -- page 入口页面 │ ├── App.vue -- 入口页面 │ ├── main.js -- 入口文件 加载组件 初始化等 │ └── permission.js -- 跳转 diff --git a/web/src/components/upload/image.vue b/web/src/components/upload/image.vue index 3db8f8e42b2a7349755d5661fa337ae5c5bbd3cc..c0acc2580182046d378bdda3ca22a010125cb185 100644 --- a/web/src/components/upload/image.vue +++ b/web/src/components/upload/image.vue @@ -1,10 +1,3 @@ -