如何使用 map 在 cookie 中传递多个值

How to pass multiple values in cookie with map

在 cookie 中传递多个值时卡住了。我找不到更好的方法来管理会话和 cookie。尝试使用 github.com/gorilla/securecookie 这个包。

loginMain.go

package main

import (
    "database/sql"
    "log"
    "net/http"
    "shambhavi/packages/loginPkg"   
    _ "github.com/go-sql-driver/mysql"
    "github.com/gorilla/mux"
)

var router = mux.NewRouter()
var db *sql.DB

func connectDb() *sql.DB {
    db, dberr := sql.Open("mysql", "root:root@tcp(127.0.0.1:8889)/shambhavi_db")
    if dberr != nil {
        log.Println(dberr)
    }
    return db
}
func login(w http.ResponseWriter, r *http.Request) {
    var db *sql.DB = connectDb()
    loginPkg.LoginOperation(w, r, db)

}

func main() {
    http.HandleFunc("/demo", login)
    http.Handle("/", router)
    err := http.ListenAndServe(port, nil) // setting listening port
if err != nil {
    log.Fatal("ListenAndServe: ", err)
}
}  

LoginPkg.go

package loginPkg

import (
    "database/sql"
    "encoding/json"
    "fmt"
    "net/http"
    "shambhavi/packages/sessionPkg"

    _ "github.com/go-sql-driver/mysql"
)

var retMap = make(map[string]string)

func ErrorHandler(err error) {
    if err != nil {
        panic(err)
    }
}

func LoginOperation(w http.ResponseWriter, r *http.Request, db *sql.DB) {
    fmt.Println("In LoginOperation ")
    r.ParseForm()
    if len(r.Form["username"][0]) == 0 && len(r.Form["password"][0]) == 0 {
        fmt.Fprintf(w, "Something is blank !!!")
    } else {
        var lvl string
        var uFullName string
        err := db.QueryRow("SELECT lvl_flag FROM admin_instance WHERE user_name = ? AND passwd = ?", r.FormValue("username"), r.FormValue("password")).Scan(&lvl)

        er := db.QueryRow("SELECT emp_name FROM emp_detail WHERE emp_uname = ?", r.FormValue("username")).Scan(&uFullName)
        ErrorHandler(er)
        retMap["msg"] = "Login successfully"
        retMap["err"] = "Not Login"
        retMap["lvl"] = lvl
        retMap["fullName"] = uFullName
        b, _ := json.Marshal(retMap)
        if err != nil {
            fmt.Println(err)
            fmt.Fprintf(w, "%s", b)

        } else {
            if lvl == "1" || lvl == "2" || lvl == "3" {
                sessionPkg.SetSession(w, r, r.FormValue("username"), retMap) // Passing map to the fun, retMap
                fmt.Fprintf(w, "%s", b)
                usrnm := sessionPkg.GetUserName(r)
                fmt.Println("From session variable", usrnm)
            } else {
                fmt.Println("Chukala ....")
                fmt.Fprintf(w, "%s", b)
            }   
        }
    }
    defer db.Close()
}

问题出在以下文件....

sessionHandler.go

package sessionPkg

import (
    "fmt"
    "net/http"
    "time"

    "github.com/gorilla/securecookie"
)

var cookieHandler = securecookie.New(
    securecookie.GenerateRandomKey(64),
    securecookie.GenerateRandomKey(32))


func SetSession(w http.ResponseWriter, r *http.Request, username string, retMap map[string]string) {

    sessionData := map[string]string{
        "userName": username,
        "lvl":      retMap["lvl"],
        "fullName": retMap["fullName"],
    }

    expiration := time.Now().Add(365 * 24 * time.Hour)

    //if encoded, err := cookieHandler.Encode("session", sessionData); err == nil {
    cookie := http.Cookie{
        Name:    "session",
        Value:   sessionData["userName"], //Here i want map or something else that can accept multiple values
        Expires: expiration,
        //MaxAge: 3600,
    }

    http.SetCookie(w, &cookie)
    //}
}

func GetUserName(request *http.Request) (userName string) {
    //fmt.Println(request.Cookie("session"))
    cookieValue := make(map[string]string)
    if cookie, err := request.Cookie("session"); err == nil {

        fmt.Println("cookieValue = ", cookie.Value)
        //if err = cookieHandler.Decode("session", cookie.Value, &cookieValue); err == nil {
        //fmt.Println(cookie)
        cookieValue["userName"] = cookie.Value
        //fmt.Println(cookieValue["userName"])
        //}
        /*else {
            fmt.Println("Error ", err)
        }*/
    }
    return cookieValue["userName"]
}

/*func GetFullName(request *http.Request) (fullName string) {
    fmt.Println("In GetFullName")
    cookieValue := make(map[string]string)
    if cookie2, err := request.Cookie("session"); err == nil {

        fmt.Println("cookieValue = ", cookie2.Value)
        //if err = cookieHandler.Decode("session", cookie.Value, &cookieValue); err == nil {
        fmt.Println(cookie2)
        cookieValue["fullName"] = cookie2.Value
        fmt.Println(cookieValue["fullName"])
        //}
    }
    return cookieValue["fullName"]
}*/

func ClearSession(response http.ResponseWriter) {
    cookie := &http.Cookie{
        Name:   "session",
        Value:  "",
        Path:   "/",
        MaxAge: -1,
    }
    http.SetCookie(response, cookie)
}

代码中注释指出的问题。我想像 PHP 那样使用会话。建议更好的方法来保护 cookie 和维护会话。也给点解释吧。

已编辑:解释 cookieHandler.Encode()cookieHandler.Decode()。它没有解码传递给它的数据。

  • var retMap = make(map[string]string) 是一张全局地图,您既可以读取也可以写入,这是不安全的:当您同时拥有多个用户时,您将覆盖该地图的内容。

  • 您根本没有使用 securecookie 包来对您的 cookie 值进行编码 - 事实上,根本不清楚您在哪里使用它。

    cookie := http.Cookie{
        Name:    "session",
        // This should be encoded.
        Value:   sessionData["userName"], //Here i want map or something else that can accept multiple values
        Expires: expiration,
        //MaxAge: 3600,
    }
    
  • 包太多:您有一个 loginpackage、一个 sessionpackage 和一个 package main。包应该满足 'theme' - auth 包可能更有意义,或者甚至只是一个 package main 直到你更熟悉 Go。

  • 您没有对密码进行哈希处理 - 将明文密码存储在数据库中并使用 r.FormValue("password") 的值进行查找是极其不安全的。阅读本文以了解如何在 Go 中安全地散列密码:Golang/App Engine - securely hashing a user's password

  • 您应该使用 gorilla/sessions 包而不是较低级别的 securecookie 包。

修改文档中的gorilla/sessions示例:

package main

import (
    "net/http"
    "github.com/gorilla/sessions"
)

// Use the CookieStore
var store = sessions.NewCookieStore([]byte("something-very-secret"))

func LoginOperation(w http.ResponseWriter, r *http.Request) {
    // Your existing DB code - shorter to make the example here clearer
    err := db.QueryRow("SELECT lvl_flag FROM admin_instance WHERE user_name = ? AND passwd = ?", r.FormValue("username"), r.FormValue("password")).Scan(&lvl)

    // Don't use a global map - create a new one
    userDetails := make(map[string]string)
    userDetails["msg"] = "Login successfully"
    userDetails["err"] = "Not Login"
    userDetails["lvl"] = lvl
    userDetails["fullName"] = uFullName

    // Get a session (existing/new)
    session, err := store.Get(r, "session-name")
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    // Set some session values.
    session.Values["userDetails"] = userDetails
    // Save it before we write to the response/return from the handler.
    session.Save(r, w)
}

稍后,如果您想检索详细信息:

func RequireAuth(w http.ResponseWriter, r *http.Request) {
    // Get a session (existing/new)
    session, err := store.Get(r, "session-name")
    if err != nil {
        http.Error(w, err.Error(), 500)
        return
    }

    // Type assert our userDetails map out of the session's map[string]interface{}
    userDetails, ok := session.Values["userDetails"].(map[string]string)
    if !ok {
        // User does not have an existing session - treat them as not logged in and/or re-direct them to your login page.
        http.Error(w, http.StatusCode(401), 401)
        return
    }


    // Check the user details - e.g. if userDetails["lvl"] == "ACTIVE" { ... }
    // TODO
    }