新增HTTP中间件-限制客户端IP访问

pull/21/merge
ouqiang 2017-05-04 14:02:50 +08:00
parent 90322c1230
commit d3d7350fc7
12 changed files with 81 additions and 84 deletions

View File

@ -11,6 +11,7 @@ import (
"github.com/ouqiang/gocron/modules/logger"
"github.com/ouqiang/gocron/service"
"github.com/ouqiang/gocron/models"
"github.com/ouqiang/gocron/modules/setting"
)
// web服务器默认端口
@ -56,6 +57,13 @@ func initModule() {
if !app.Installed {
return
}
config, err := setting.Read(app.AppConfig)
if err != nil {
logger.Fatal("读取应用配置失败", err)
}
app.Setting = config
models.Db = models.CreateDb()
// 初始化定时任务

View File

@ -9,7 +9,6 @@ import (
"strings"
"time"
"github.com/ouqiang/gocron/modules/logger"
"github.com/ouqiang/gocron/modules/setting"
"github.com/ouqiang/gocron/modules/app"
)
@ -124,23 +123,15 @@ func keepDbAlived(engine *xorm.Engine) {
// 获取数据库配置
func getDbConfig() map[string]string {
config, err := setting.Read(app.AppConfig)
if err != nil {
logger.Fatal("获取应用配置失败", err)
}
section := config.Section("db")
if err != nil {
logger.Fatal("获取DB配置失败", err)
}
var db map[string]string = make(map[string]string)
db["user"] = section.Key("user").String()
db["password"] = section.Key("password").String()
db["host"] = section.Key("host").String()
db["port"] = section.Key("port").String()
db["database"] = section.Key("database").String()
db["charset"] = section.Key("charset").String()
db["prefix"] = section.Key("prefix").String()
db["engine"] = section.Key("engine").String()
db["user"] = app.Setting.Key("db.user").String()
db["password"] = app.Setting.Key("db.password").String()
db["host"] = app.Setting.Key("db.host").String()
db["port"] = app.Setting.Key("db.port").String()
db["database"] = app.Setting.Key("db.database").String()
db["charset"] = app.Setting.Key("db.charset").String()
db["prefix"] = app.Setting.Key("db.prefix").String()
db["engine"] = app.Setting.Key("db.engine").String()
return db
}

View File

@ -6,6 +6,7 @@ import (
"github.com/ouqiang/gocron/modules/logger"
"runtime"
"github.com/ouqiang/gocron/modules/utils"
"gopkg.in/ini.v1"
)
var (
@ -15,6 +16,7 @@ var (
DataDir string // 存放session等
AppConfig string // 应用配置文件
Installed bool // 应用是否安装过
Setting *ini.Section // 应用配置
)
func InitEnv() {
@ -47,7 +49,7 @@ func IsInstalled() bool {
func CreateInstallLock() error {
_, err := os.Create(ConfDir + "/install.lock")
if err != nil {
logger.Error("创建安装锁文件失败")
logger.Error("创建安装锁文件conf/install.lock失败")
}
return err

View File

@ -62,7 +62,6 @@ func request(req *http.Request, timeout int) ResponseWrapper {
}
func setRequestHeader(req *http.Request) {
req.Header.Set("Connection", "keep-alive")
req.Header.Set("Accept-Language", "zh-CN,zh;q=0.8,en;q=0.6")
req.Header.Set("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/57.0.2987.133 Safari/537.36 golang/gocron")
}

View File

@ -5,39 +5,41 @@ import (
"gopkg.in/ini.v1"
)
// 读取配置
func Read(filename string) (config *ini.File, err error) {
config, err = ini.Load(filename)
if err != nil {
return
}
const DefaultSection = "default"
return
// 读取配置
func Read(filename string) (*ini.Section,error) {
config, err := ini.Load(filename)
if err != nil {
return nil, err
}
section := config.Section(DefaultSection)
return section, nil
}
// 写入配置
func Write(config map[string]map[string]string, filename string) error {
func Write(config map[string]string, filename string) error {
if len(config) == 0 {
return errors.New("参数不能为空")
}
file := ini.Empty()
for sectionName, items := range config {
if sectionName == "" {
return errors.New("节名称不能为空")
section, err := file.NewSection(DefaultSection)
if err != nil {
return err
}
for key, value := range config {
if key == "" {
continue
}
section, err := file.NewSection(sectionName)
_, err = section.NewKey(key, value)
if err != nil {
return err
}
for key, value := range items {
_, err = section.NewKey(key, value)
if err != nil {
return err
}
}
}
err := file.SaveTo(filename)
err = file.SaveTo(filename)
return err
}

View File

@ -89,7 +89,7 @@ func Exec(sshConfig SSHConfig, cmd string) (output string, err error) {
// 后台运行
if sshConfig.ExecTimeout < 0 {
go session.CombinedOutput(cmd)
time.Sleep(5 * time.Second)
time.Sleep(3 * time.Second)
return "", nil
}
// 不限制超时

View File

@ -91,8 +91,9 @@ func ReplaceStrings(s string, old []string, replace []string) string {
}
func InStringSlice(slice []string, element string) bool {
element = strings.TrimSpace(element)
for _, v := range slice {
if v == element {
if strings.TrimSpace(v) == element{
return true
}
}

View File

@ -7,8 +7,6 @@ import (
"github.com/ouqiang/gocron/modules/utils"
"gopkg.in/macaron.v1"
"strconv"
"github.com/ouqiang/gocron/modules/logger"
"github.com/go-macaron/binding"
"fmt"
"github.com/ouqiang/gocron/service"
)
@ -29,10 +27,6 @@ type InstallForm struct {
AdminEmail string `binding:"Required;Email;MaxSize(50)"`
}
func(f InstallForm) Error(ctx *macaron.Context, errs binding.Errors) {
logger.Error(errs)
}
func Create(ctx *macaron.Context) {
if app.Installed {
ctx.Redirect("/")
@ -61,6 +55,12 @@ func Store(ctx *macaron.Context, form InstallForm) string {
return json.CommonFailure("数据库配置写入文件失败", err)
}
appConfig, err := setting.Read(app.AppConfig)
if err != nil {
return json.CommonFailure("读取应用配置失败", err)
}
app.Setting = appConfig
models.Db = models.CreateDb()
// 创建数据库表
migration := new(models.Migration)
@ -89,19 +89,18 @@ func Store(ctx *macaron.Context, form InstallForm) string {
return json.Success("安装成功", nil)
}
// 数据库配置写入文件
// 配置写入文件
func writeConfig(form InstallForm) error {
dbConfig := map[string]map[string]string{
"db": map[string]string{
"engine": form.DbType,
"host": form.DbHost,
"port": strconv.Itoa(form.DbPort),
"user": form.DbUsername,
"password": form.DbPassword,
"database": form.DbName,
"prefix": form.DbTablePrefix,
"charset": "utf8",
},
dbConfig := map[string]string{
"db.engine": form.DbType,
"db.host": form.DbHost,
"db.port": strconv.Itoa(form.DbPort),
"db.user": form.DbUsername,
"db.password": form.DbPassword,
"db.database": form.DbName,
"db.prefix": form.DbTablePrefix,
"db.charset": "utf8",
"allow_ips" : "",
}
return setting.Write(dbConfig, app.AppConfig)

View File

@ -142,6 +142,7 @@ func RegisterMiddleware(m *macaron.Macaron) {
m.Use(csrf.Csrfer())
m.Use(toolbox.Toolboxer(m))
checkAppInstall(m)
ipAuth(m)
userAuth(m)
setShareData(m)
}
@ -159,6 +160,20 @@ func checkAppInstall(m *macaron.Macaron) {
})
}
// IP验证, 通过反向代理访问gocron需设置Header X-Real-IP才能获取到客户端真实IP
func ipAuth(m *macaron.Macaron) {
m.Use(func(ctx *macaron.Context) {
allowIpsStr := app.Setting.Key("allow_ips").String()
if allowIpsStr == "" {
return
}
clientIp := ctx.RemoteAddr()
if !utils.InStringSlice(allowIps, clientIp) {
ctx.Status(403)
}
})
}
// 用户认证
func userAuth(m *macaron.Macaron) {
m.Use(func(ctx *macaron.Context, sess session.Store) {
@ -167,7 +182,7 @@ func userAuth(m *macaron.Macaron) {
}
uri := ctx.Req.URL.Path
found := false
excludePaths := []string{"/install", "/user/login", "/"}
excludePaths := []string{"/install", "/user/login", "/api"}
for _, path := range excludePaths {
if strings.HasPrefix(uri, path) {
found = true
@ -199,14 +214,6 @@ func setShareData(m *macaron.Macaron) {
})
}
// 管理员认证
func adminAuth(ctx *macaron.Context, sess session.Store) {
if !user.IsAdmin(sess) {
ctx.Data["Title"] = "无权限访问此页面"
ctx.HTML(403, "error/no_permission")
}
}
func isAjaxRequest(ctx *macaron.Context) bool {
req := ctx.Req.Header.Get("X-Requested-With")
if req == "XMLHttpRequest" {

View File

@ -57,7 +57,7 @@ func (task *Task) Initialize() {
taskModel := new(models.Task)
taskList, err := taskModel.ActiveList()
if err != nil {
logger.Error("获取任务列表错误-", err.Error())
logger.Error("定时任务初始化#获取任务列表错误-", err.Error())
return
}
if len(taskList) == 0 {

View File

@ -1,12 +0,0 @@
{{{ template "common/header" . }}}
<script>
swal({
title: "403 - FORBIDDEN",
text: "您无权限访问此页面",
type: "warning"
},
function(){
location.href = "/"
});
</script>
{{{ template "common/footer" . }}}

View File

@ -66,13 +66,13 @@
<textarea rows="5" name="command">{{{.Task.Command}}}</textarea>
</div>
</div>
<div class="three fields">
<div class="six fields">
<div class="field">
<label>()</label>
<input type="text" name="timeout" value="{{{.Task.Timeout}}}">
</div>
</div>
<div class="two fields">
<div class="six fields">
<div class="field">
<label></label>
<input type="text" name="retry_times" value="{{{.Task.RetryTimes}}}">
@ -143,7 +143,7 @@
</div>
</div>
{{else}}
<a class="ui blue button" href="/manage/mail/edit"></a><br><br>
<a class="ui blue button" href="/manage/mail/edit" target="_blank"></a><br><br>
{{/each}}
</script>
@ -156,7 +156,7 @@
</div>
</div>
{{else}}
<a class="ui blue button" href="/manage/slack/edit">Slack</a>
<a class="ui blue button" href="/manage/slack/edit" target="_blank">Slack</a>
{{/each}}
</script>