Jelajahi Sumber

Worked on login remember cookie, and redirect after login

Torkel Ödegaard 11 tahun lalu
induk
melakukan
257519490a

+ 1 - 1
grafana

@@ -1 +1 @@
-Subproject commit 11b74baf7920bcd4e39b5e77bfb49e6b08752dc2
+Subproject commit 4572747bd60c688f7cc2cbf8a2303b9c95ad7b9d

+ 75 - 4
pkg/api/login.go

@@ -1,21 +1,72 @@
 package api
 
 import (
+	"net/url"
+
 	"github.com/torkelo/grafana-pro/pkg/api/dtos"
 	"github.com/torkelo/grafana-pro/pkg/bus"
 	"github.com/torkelo/grafana-pro/pkg/log"
 	"github.com/torkelo/grafana-pro/pkg/middleware"
 	m "github.com/torkelo/grafana-pro/pkg/models"
+	"github.com/torkelo/grafana-pro/pkg/setting"
 	"github.com/torkelo/grafana-pro/pkg/util"
 )
 
+const (
+	VIEW_INDEX = "index"
+)
+
 func LoginView(c *middleware.Context) {
 	if err := setIndexViewData(c); err != nil {
 		c.Handle(500, "Failed to get settings", err)
 		return
 	}
 
-	c.HTML(200, "index")
+	// Check auto-login.
+	uname := c.GetCookie(setting.CookieUserName)
+	if len(uname) == 0 {
+		c.HTML(200, VIEW_INDEX)
+		return
+	}
+
+	isSucceed := false
+	defer func() {
+		if !isSucceed {
+			log.Trace("auto-login cookie cleared: %s", uname)
+			c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/")
+			c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/")
+			return
+		}
+	}()
+
+	userQuery := m.GetUserByLoginQuery{LoginOrEmail: uname}
+	if err := bus.Dispatch(&userQuery); err != nil {
+		if err != m.ErrUserNotFound {
+			c.Handle(500, "GetUserByLoginQuery", err)
+		} else {
+			c.HTML(200, VIEW_INDEX)
+		}
+		return
+	}
+
+	user := userQuery.Result
+
+	if val, _ := c.GetSuperSecureCookie(
+		util.EncodeMd5(user.Rands+user.Password), setting.CookieRememberName); val != user.Login {
+		c.HTML(200, VIEW_INDEX)
+		return
+	}
+
+	isSucceed = true
+	loginUserWithUser(user, c)
+
+	if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 {
+		c.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/")
+		c.Redirect(redirectTo)
+		return
+	}
+
+	c.Redirect(setting.AppSubUrl + "/")
 }
 
 func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) {
@@ -36,9 +87,27 @@ func LoginPost(c *middleware.Context, cmd dtos.LoginCommand) {
 		return
 	}
 
+	// default to true here for now
+	cmd.Remember = true
+
+	if cmd.Remember {
+		days := 86400 * setting.LogInRememberDays
+		c.SetCookie(setting.CookieUserName, user.Login, days, setting.AppSubUrl+"/")
+		c.SetSuperSecureCookie(util.EncodeMd5(user.Rands+user.Password), setting.CookieRememberName, user.Login, days, setting.AppSubUrl+"/")
+	}
+
 	loginUserWithUser(user, c)
 
-	c.JsonOK("User logged in")
+	result := map[string]interface{}{
+		"message": "Logged in",
+	}
+
+	if redirectTo, _ := url.QueryUnescape(c.GetCookie("redirect_to")); len(redirectTo) > 0 {
+		result["redirectUrl"] = redirectTo
+		c.SetCookie("redirect_to", "", -1, setting.AppSubUrl+"/")
+	}
+
+	c.JSON(200, result)
 }
 
 func loginUserWithUser(user *m.User, c *middleware.Context) {
@@ -50,6 +119,8 @@ func loginUserWithUser(user *m.User, c *middleware.Context) {
 }
 
 func LogoutPost(c *middleware.Context) {
-	c.Session.Delete("userId")
-	c.JSON(200, util.DynMap{"status": "logged out"})
+	c.SetCookie(setting.CookieUserName, "", -1, setting.AppSubUrl+"/")
+	c.SetCookie(setting.CookieRememberName, "", -1, setting.AppSubUrl+"/")
+	c.Session.Destory(c.Context)
+	c.JsonOK("logged out")
 }

+ 1 - 0
pkg/api/signup.go

@@ -12,6 +12,7 @@ func SignUp(c *middleware.Context, cmd m.CreateUserCommand) {
 
 	cmd.Login = cmd.Email
 	cmd.Salt = util.GetRandomString(10)
+	cmd.Rands = util.GetRandomString(10)
 	cmd.Password = util.EncodePassword(cmd.Password, cmd.Salt)
 
 	if err := bus.Dispatch(&cmd); err != nil {

+ 5 - 0
pkg/middleware/auth.go

@@ -1,10 +1,12 @@
 package middleware
 
 import (
+	"net/url"
 	"strings"
 
 	"github.com/Unknwon/macaron"
 
+	"github.com/torkelo/grafana-pro/pkg/log"
 	m "github.com/torkelo/grafana-pro/pkg/models"
 	"github.com/torkelo/grafana-pro/pkg/setting"
 )
@@ -45,6 +47,7 @@ func getApiKey(c *Context) string {
 func authDenied(c *Context) {
 	if c.IsApiRequest() {
 		c.JsonApiErr(401, "Access denied", nil)
+		return
 	}
 
 	c.Redirect(setting.AppSubUrl + "/login")
@@ -69,6 +72,8 @@ func Auth(options *AuthOptions) macaron.Handler {
 	return func(c *Context) {
 
 		if !c.IsSignedIn && options.ReqSignedIn {
+			log.Info("AppSubUrl: %v", setting.AppSubUrl)
+			c.SetCookie("redirect_to", url.QueryEscape(setting.AppSubUrl+c.Req.RequestURI), 0, setting.AppSubUrl+"/")
 			authDenied(c)
 			return
 		}

+ 2 - 0
pkg/models/user.go

@@ -17,6 +17,7 @@ type User struct {
 	Login    string
 	Password string
 	Salt     string
+	Rands    string
 	Company  string
 
 	IsAdmin   bool
@@ -36,6 +37,7 @@ type CreateUserCommand struct {
 	Company  string `json:"compay"`
 	Password string `json:"password" binding:"Required"`
 	Salt     string `json:"-"`
+	Rands    string `json:"-"`
 	IsAdmin  bool   `json:"-"`
 
 	Result User `json:"-"`

+ 3 - 0
pkg/services/sqlstore/migrations.go

@@ -50,6 +50,9 @@ func addUserMigrations(mg *Migrator) {
 		Table("user").Columns("login").Unique())
 	mg.AddMigration("add unique index user.email", new(AddIndexMigration).
 		Table("user").Columns("email").Unique())
+
+	mg.AddMigration("add column user.rands", new(AddColumnMigration).
+		Table("user").Column(&Column{Name: "rands", Type: DB_NVarchar, Length: 255, Nullable: true}))
 }
 
 func addAccountMigrations(mg *Migrator) {

+ 1 - 0
pkg/services/sqlstore/sqlstore.go

@@ -41,6 +41,7 @@ func EnsureAdminUser() {
 		cmd.Login = setting.AdminUser
 		cmd.Email = setting.AdminUser + "@localhost"
 		cmd.Salt = util.GetRandomString(10)
+		cmd.Rands = util.GetRandomString(10)
 		cmd.Password = util.EncodePassword(setting.AdminPassword, cmd.Salt)
 		cmd.IsAdmin = true
 

+ 1 - 0
pkg/services/sqlstore/user.go

@@ -43,6 +43,7 @@ func CreateUser(cmd *m.CreateUserCommand) error {
 			Login:     cmd.Login,
 			Company:   cmd.Company,
 			Salt:      cmd.Salt,
+			Rands:     cmd.Rands,
 			IsAdmin:   cmd.IsAdmin,
 			AccountId: account.Id,
 			Created:   time.Now(),

+ 9 - 0
pkg/util/encoding.go

@@ -2,8 +2,10 @@ package util
 
 import (
 	"crypto/hmac"
+	"crypto/md5"
 	"crypto/rand"
 	"crypto/sha256"
+	"encoding/hex"
 	"fmt"
 	"hash"
 )
@@ -28,6 +30,13 @@ func EncodePassword(password string, salt string) string {
 	return fmt.Sprintf("%x", newPasswd)
 }
 
+// Encode string to md5 hex value.
+func EncodeMd5(str string) string {
+	m := md5.New()
+	m.Write([]byte(str))
+	return hex.EncodeToString(m.Sum(nil))
+}
+
 // http://code.google.com/p/go/source/browse/pbkdf2/pbkdf2.go?repo=crypto
 func PBKDF2(password, salt []byte, iter, keyLen int, h func() hash.Hash) []byte {
 	prf := hmac.New(h, password)