mirror of https://github.com/ouqiang/gocron
增加用户登录验证
parent
6c99197078
commit
ba5b0cd6ad
11
cmd/web.go
11
cmd/web.go
|
@ -32,7 +32,7 @@ var CmdWeb = cli.Command{
|
|||
},
|
||||
cli.StringFlag{
|
||||
Name: "env,e",
|
||||
Value: "dev",
|
||||
Value: "prod",
|
||||
Usage: "runtime environment, dev|test|prod",
|
||||
},
|
||||
cli.StringFlag{
|
||||
|
@ -75,13 +75,18 @@ func parsePort(ctx *cli.Context) int {
|
|||
}
|
||||
|
||||
func setEnvironment(ctx *cli.Context) {
|
||||
var env string = ""
|
||||
var env string = "prod"
|
||||
if ctx.IsSet("env") {
|
||||
env = ctx.String("env")
|
||||
}
|
||||
|
||||
if env == "prod" {
|
||||
switch env {
|
||||
case "prod":
|
||||
macaron.Env = macaron.PROD
|
||||
case "test":
|
||||
macaron.Env = macaron.TEST
|
||||
case "dev":
|
||||
macaron.Env = macaron.DEV
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -3,7 +3,6 @@ package models
|
|||
import (
|
||||
"time"
|
||||
"github.com/go-xorm/xorm"
|
||||
"github.com/ouqiang/gocron/modules/logger"
|
||||
)
|
||||
|
||||
type TaskType int8
|
||||
|
|
|
@ -4,6 +4,5 @@ import "gopkg.in/macaron.v1"
|
|||
|
||||
// 首页
|
||||
func Home(ctx *macaron.Context) {
|
||||
ctx.Data["Title"] = "首页"
|
||||
ctx.HTML(200, "home/index")
|
||||
ctx.Redirect("/task")
|
||||
}
|
||||
|
|
|
@ -14,6 +14,8 @@ import (
|
|||
"strings"
|
||||
"github.com/ouqiang/gocron/modules/app"
|
||||
"github.com/ouqiang/gocron/modules/logger"
|
||||
"github.com/ouqiang/gocron/routers/user"
|
||||
"github.com/go-macaron/gzip"
|
||||
)
|
||||
|
||||
// 静态文件目录
|
||||
|
@ -23,28 +25,6 @@ const StaticDir = "public"
|
|||
func Register(m *macaron.Macaron) {
|
||||
// 所有GET方法,自动注册HEAD方法
|
||||
m.SetAutoHead(true)
|
||||
// 404错误
|
||||
m.NotFound(func(ctx *macaron.Context) {
|
||||
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
||||
ctx.Data["Title"] = "404 - NOT FOUND"
|
||||
ctx.HTML(404, "error/404")
|
||||
} else {
|
||||
json := utils.JsonResponse{}
|
||||
ctx.Resp.Write([]byte(json.Failure(utils.NotFound, "您访问的地址不存在")))
|
||||
}
|
||||
})
|
||||
// 50x错误
|
||||
m.InternalServerError(func(ctx *macaron.Context) {
|
||||
logger.Debug("500错误")
|
||||
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
||||
ctx.Data["Title"] = "500 - INTERNAL SERVER ERROR"
|
||||
ctx.HTML(500, "error/500")
|
||||
} else {
|
||||
json := utils.JsonResponse{}
|
||||
ctx.Resp.Write([]byte(json.Failure(utils.ServerError, "网站暂时无法访问,请稍后再试")))
|
||||
}
|
||||
})
|
||||
|
||||
// 首页
|
||||
m.Get("/", Home)
|
||||
// 系统安装
|
||||
|
@ -55,7 +35,9 @@ func Register(m *macaron.Macaron) {
|
|||
|
||||
// 用户
|
||||
m.Group("/user", func() {
|
||||
|
||||
m.Get("/login", user.Login)
|
||||
m.Post("/login", user.ValidateLogin)
|
||||
m.Get("/logout", user.Logout)
|
||||
})
|
||||
|
||||
// 任务
|
||||
|
@ -81,12 +63,35 @@ func Register(m *macaron.Macaron) {
|
|||
m.Get("", host.Index)
|
||||
m.Post("/remove/:id", host.Remove)
|
||||
})
|
||||
|
||||
// 404错误
|
||||
m.NotFound(func(ctx *macaron.Context) {
|
||||
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
||||
ctx.Data["Title"] = "404 - NOT FOUND"
|
||||
ctx.HTML(404, "error/404")
|
||||
} else {
|
||||
json := utils.JsonResponse{}
|
||||
ctx.Resp.Write([]byte(json.Failure(utils.NotFound, "您访问的地址不存在")))
|
||||
}
|
||||
})
|
||||
// 50x错误
|
||||
m.InternalServerError(func(ctx *macaron.Context) {
|
||||
logger.Debug("500错误")
|
||||
if isGetRequest(ctx) && !isAjaxRequest(ctx) {
|
||||
ctx.Data["Title"] = "500 - INTERNAL SERVER ERROR"
|
||||
ctx.HTML(500, "error/500")
|
||||
} else {
|
||||
json := utils.JsonResponse{}
|
||||
ctx.Resp.Write([]byte(json.Failure(utils.ServerError, "网站暂时无法访问,请稍后再试")))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 中间件注册
|
||||
func RegisterMiddleware(m *macaron.Macaron) {
|
||||
m.Use(macaron.Logger())
|
||||
m.Use(macaron.Recovery())
|
||||
m.Use(gzip.Gziper())
|
||||
m.Use(macaron.Static(StaticDir))
|
||||
m.Use(macaron.Renderer(macaron.RenderOptions{
|
||||
Directory: "templates",
|
||||
|
@ -103,8 +108,14 @@ func RegisterMiddleware(m *macaron.Macaron) {
|
|||
m.Use(session.Sessioner())
|
||||
m.Use(csrf.Csrfer())
|
||||
m.Use(toolbox.Toolboxer(m))
|
||||
checkAppInstall(m)
|
||||
userAuth(m)
|
||||
setShareData(m)
|
||||
}
|
||||
|
||||
|
||||
// 系统未安装,重定向到安装页面
|
||||
func checkAppInstall(m *macaron.Macaron) {
|
||||
m.Use(func(ctx *macaron.Context) {
|
||||
installUrl := "/install"
|
||||
if strings.HasPrefix(ctx.Req.URL.Path, installUrl) {
|
||||
|
@ -114,8 +125,32 @@ func RegisterMiddleware(m *macaron.Macaron) {
|
|||
ctx.Redirect(installUrl)
|
||||
}
|
||||
})
|
||||
// 设置模板共享变量
|
||||
m.Use(func(ctx *macaron.Context) {
|
||||
}
|
||||
|
||||
// 用户认证
|
||||
func userAuth(m *macaron.Macaron) {
|
||||
m.Use(func(ctx *macaron.Context, sess session.Store) {
|
||||
if user.IsLogin(sess) {
|
||||
return
|
||||
}
|
||||
uri := ctx.Req.URL.Path
|
||||
found := false
|
||||
excludePaths := []string{"/install", "/user/login"}
|
||||
for _, path := range excludePaths {
|
||||
if strings.HasPrefix(uri, path) {
|
||||
found = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if !found {
|
||||
ctx.Redirect("/user/login")
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// 设置共享数据
|
||||
func setShareData(m *macaron.Macaron) {
|
||||
m.Use(func(ctx *macaron.Context, sess session.Store) {
|
||||
ctx.Data["URI"] = ctx.Req.URL.Path
|
||||
urlPath := strings.TrimPrefix(ctx.Req.URL.Path, "/")
|
||||
paths := strings.Split(urlPath, "/")
|
||||
|
@ -127,6 +162,7 @@ func RegisterMiddleware(m *macaron.Macaron) {
|
|||
if len(paths) > 1 {
|
||||
ctx.Data["Action"] = paths[1]
|
||||
}
|
||||
ctx.Data["LoginUsername"] = user.Username(sess)
|
||||
})
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,66 @@
|
|||
package user
|
||||
|
||||
import (
|
||||
"gopkg.in/macaron.v1"
|
||||
"github.com/ouqiang/gocron/modules/utils"
|
||||
"github.com/ouqiang/gocron/models"
|
||||
"github.com/go-macaron/session"
|
||||
"github.com/ouqiang/gocron/modules/logger"
|
||||
"time"
|
||||
)
|
||||
|
||||
// @author qiang.ou<qingqianludao@gmail.com>
|
||||
// @date 2017/4/23-14:16
|
||||
|
||||
func Login(ctx *macaron.Context) {
|
||||
ctx.Data["Title"] = "用户登录"
|
||||
ctx.HTML(200, "user/login")
|
||||
}
|
||||
|
||||
func ValidateLogin(ctx *macaron.Context, sess session.Store) string {
|
||||
username := ctx.QueryTrim("username")
|
||||
password := ctx.QueryTrim("password")
|
||||
json := utils.JsonResponse{}
|
||||
if username == "" || password == "" {
|
||||
return json.CommonFailure("用户名、密码不能为空")
|
||||
}
|
||||
|
||||
userModel := new (models.User)
|
||||
if !userModel.Match(username, password) {
|
||||
return json.CommonFailure("用户名或密码错误")
|
||||
}
|
||||
|
||||
sess.Set("username", username)
|
||||
|
||||
return json.Success("登录成功", nil)
|
||||
}
|
||||
|
||||
func Logout(ctx *macaron.Context, sess session.Store) {
|
||||
if IsLogin(sess) {
|
||||
err := sess.Delete("username")
|
||||
if err != nil {
|
||||
logger.Error("用户退出登录失败", err)
|
||||
}
|
||||
}
|
||||
|
||||
ctx.SetSecureCookie("MacaronSession", "", 0, "/", "", nil, nil, time.Now().AddDate(-1, 0, 0))
|
||||
Login(ctx)
|
||||
}
|
||||
|
||||
func Username(sess session.Store) string {
|
||||
username,ok := sess.Get("username").(string)
|
||||
if ok {
|
||||
return username
|
||||
}
|
||||
|
||||
return ""
|
||||
}
|
||||
|
||||
func IsLogin(sess session.Store) bool {
|
||||
username,ok := sess.Get("username").(string)
|
||||
if ok && username != "" {
|
||||
return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
|
@ -36,16 +36,14 @@
|
|||
</div>
|
||||
<div class="user">
|
||||
<div class="ui inline labeled icon top right pointing dropdown">
|
||||
{{{if not .Logined}}}
|
||||
<img class="ui avatar image" src="/resource/images/gopher-avatar.png">
|
||||
{{{if not .LoginUsername}}}
|
||||
你好
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<a class="item" href="/user/login"><i class="sign in icon"></i>登录</a>
|
||||
</div>
|
||||
{{{else}}}
|
||||
<img class="ui avatar image" src="/resource/images/gopher-avatar.png">
|
||||
你好,{{{.Username}}}
|
||||
你好,{{{.LoginUsername}}}
|
||||
<i class="dropdown icon"></i>
|
||||
<div class="menu">
|
||||
<a class="item" href="/user/logout"><i class="sign out icon"></i>退出</a>
|
||||
|
@ -59,7 +57,6 @@
|
|||
<div class="ui teal inverted menu">
|
||||
<div class="bigcontainer">
|
||||
<div class="right menu">
|
||||
<a class="item {{{if eq .Controller ""}}}active{{{end}}}" href="/"><i class="home icon"></i>首页</a>
|
||||
<a class="item {{{if eq .Controller "task"}}}active{{{end}}}" href="/task"><i class="tasks icon"></i>任务</a>
|
||||
<a class="item {{{if eq .Controller "host"}}}active{{{end}}}" href="/host"><i class="linux icon"></i>主机</a>
|
||||
<a class="item {{{if eq .Controller "user"}}}active{{{end}}}" href="/user"><i class="user icon"></i>账户</a>
|
||||
|
|
|
@ -50,8 +50,9 @@
|
|||
</div>
|
||||
</div>
|
||||
</form>
|
||||
<div class="task-list">
|
||||
{{{range $i, $v := .Tasks}}}
|
||||
<div class="ui device two column middle aligned vertical grid list segment">
|
||||
<div class="ui device two column middle aligned vertical grid segment">
|
||||
<div class="column verborder">
|
||||
<div class="ui info segment">
|
||||
<h5 class="ui header">{{{.Task.Name}}} {{{if eq .Status 1}}}<i class="large checkmark blue icon"></i> {{{else}}} <i class="large red minus icon"></i> {{{end}}}
|
||||
|
@ -69,7 +70,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="center aligned column">
|
||||
<div class="ui buttons">
|
||||
<div class="ui buttons operation">
|
||||
<a class="ui purple button" href="/task/edit/{{{.Id}}}">编辑</a>
|
||||
{{{if eq .Status 1}}}
|
||||
<button class="ui primary button" @click="changeStatus({{{.Id}}},{{{.Status}}})">暂停</button>
|
||||
|
@ -83,6 +84,7 @@
|
|||
</div>
|
||||
</div>
|
||||
{{{end}}}
|
||||
</div>
|
||||
{{{ template "common/pagination" .}}}
|
||||
</div>
|
||||
</div>
|
||||
|
@ -93,7 +95,7 @@
|
|||
|
||||
var vue = new Vue(
|
||||
{
|
||||
el: '.ui.list',
|
||||
el: '.task-list',
|
||||
methods: {
|
||||
changeStatus: function (id ,status) {
|
||||
var url = '';
|
||||
|
|
|
@ -1,4 +1,55 @@
|
|||
{{{ template "common/header" . }}}
|
||||
<div class="ui small modal">
|
||||
<div class="header">用户登录</div>
|
||||
<div class="content">
|
||||
<form class="ui form">
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<input class="small input" type="text" name="username" placeholder="用户名或邮箱">
|
||||
</div>
|
||||
</div>
|
||||
<div class="two fields">
|
||||
<div class="field">
|
||||
<input type="password" name="password" placeholder="密码">
|
||||
</div>
|
||||
</div>
|
||||
<button class="ui button primary button" >登录</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<script type="text/javascript">
|
||||
$('.ui.modal').modal('setting', 'closable', false).modal('show');
|
||||
$('.ui.form').form(
|
||||
{
|
||||
onSuccess: function(event, fields) {
|
||||
util.post('/user/login', fields, function(code, message) {
|
||||
location.href = "/"
|
||||
});
|
||||
|
||||
return false;
|
||||
},
|
||||
fields: {
|
||||
username: {
|
||||
identifier : 'username',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入用户名'
|
||||
}
|
||||
]
|
||||
},
|
||||
Password: {
|
||||
identifier : 'password',
|
||||
rules: [
|
||||
{
|
||||
type : 'empty',
|
||||
prompt : '请输入密码'
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
inline : true
|
||||
});
|
||||
</script>
|
||||
{{{ template "common/footer" . }}}
|
Loading…
Reference in New Issue