增加用户登录验证

pull/21/merge
ouqiang 2017-04-23 17:00:47 +08:00
parent 6c99197078
commit ba5b0cd6ad
8 changed files with 226 additions and 71 deletions

View File

@ -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
}
}

View File

@ -3,7 +3,6 @@ package models
import (
"time"
"github.com/go-xorm/xorm"
"github.com/ouqiang/gocron/modules/logger"
)
type TaskType int8

View File

@ -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")
}

View File

@ -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)
})
}

66
routers/user/user.go Normal file
View File

@ -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
}

View File

@ -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>

View File

@ -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 = '';

View File

@ -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" . }}}