登录
首页 >  Golang >  Go问答

使用 gorilla 会话时未保存 golang 中的会话变量

来源:Golang技术栈

时间:2023-04-26 15:30:20 371浏览 收藏

本篇文章给大家分享《使用 gorilla 会话时未保存 golang 中的会话变量》,覆盖了Golang的常见基础知识,其实一个语言的全部知识点一篇文章是不可能说完的,但希望通过这些问题,让读者对自己的掌握程度有一定的认识(B 数),从而弥补自己的不足,更好的掌握它。

问题内容

使用 gorilla 会话 Web 工具包时,不会跨请求维护会话变量。当我启动服务器并键入 localhost:8100/ 时,页面被定向到 login.html,因为会话值不存在。登录后,我在商店中设置会话变量,页面被重定向到 home.html。但是,当我打开一个新选项卡并键入 localhost:8100/ 时,该页面应该使用已存储的会话变量定向到 home.html,但该页面改为重定向到 login.html。以下是代码。

    package main

import (
    "crypto/md5"
    "encoding/hex"
    "fmt"
    "github.com/gocql/gocql"
    "github.com/gorilla/mux"
    "github.com/gorilla/sessions"
    "net/http"
    "time"
)

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

var router = mux.NewRouter()

func init() {

    store.Options = &sessions.Options{
        Domain:   "localhost",
        Path:     "/",
        MaxAge:   3600 * 1, // 1 hour
        HttpOnly: true,
    }
}
func main() {
    //session handling
    router.HandleFunc("/", SessionHandler)
    router.HandleFunc("/signIn", SignInHandler)
    router.HandleFunc("/signUp", SignUpHandler)
    router.HandleFunc("/logOut", LogOutHandler)
    http.Handle("/", router)
    http.ListenAndServe(":8100", nil)
}

//handler for signIn
func SignInHandler(res http.ResponseWriter, req *http.Request) {

    email := req.FormValue("email")
    password := req.FormValue("password")

    //Generate hash of password
    hasher := md5.New()
    hasher.Write([]byte(password))
    encrypted_password := hex.EncodeToString(hasher.Sum(nil))

    //cassandra connection
    cluster := gocql.NewCluster("localhost")
    cluster.Keyspace = "gbuy"
    cluster.DefaultPort = 9042
    cluster.Consistency = gocql.Quorum
    session, _ := cluster.CreateSession()
    defer session.Close()

    //select query
    var firstname string
    stmt := "SELECT firstname FROM USER WHERE email= '" + email + "' and password ='" + encrypted_password + "';"
    err := session.Query(stmt).Scan(&firstname)
    if err != nil {
        fmt.Fprintf(res, "failed")
    } else {
        if firstname == "" {
            fmt.Fprintf(res, "failed")
        } else {
            fmt.Fprintf(res, firstname)
        }
    }

    //store in session variable
    sessionNew, _ := store.Get(req, "loginSession")

    // Set some session values.
    sessionNew.Values["email"] = email
    sessionNew.Values["name"] = firstname

    // Save it.
    sessionNew.Save(req, res)
    //store.Save(req,res,sessionNew)

    fmt.Println("Session after logging:")
    fmt.Println(sessionNew)

}

//handler for signUp
func SignUpHandler(res http.ResponseWriter, req *http.Request) {

    fName := req.FormValue("fName")
    lName := req.FormValue("lName")
    email := req.FormValue("email")
    password := req.FormValue("passwd")
    birthdate := req.FormValue("date")
    city := req.FormValue("city")
    gender := req.FormValue("gender")

    //Get current timestamp and format it.
    sysdate := time.Now().Format("2006-01-02 15:04:05-0700")

    //Generate hash of password
    hasher := md5.New()
    hasher.Write([]byte(password))
    encrypted_password := hex.EncodeToString(hasher.Sum(nil))

    //cassandra connection
    cluster := gocql.NewCluster("localhost")
    cluster.Keyspace = "gbuy"
    cluster.DefaultPort = 9042
    cluster.Consistency = gocql.Quorum
    session, _ := cluster.CreateSession()
    defer session.Close()

    //Insert the data into the Table
    stmt := "INSERT INTO USER (email,firstname,lastname,birthdate,city,gender,password,creation_date) VALUES ('" + email + "','" + fName + "','" + lName + "','" + birthdate + "','" + city + "','" + gender + "','" + encrypted_password + "','" + sysdate + "');"
    fmt.Println(stmt)
    err := session.Query(stmt).Exec()
    if err != nil {
        fmt.Fprintf(res, "failed")
    } else {
        fmt.Fprintf(res, fName)
    }
}

//handler for logOut
func LogOutHandler(res http.ResponseWriter, req *http.Request) {
    sessionOld, err := store.Get(req, "loginSession")

    fmt.Println("Session in logout")
    fmt.Println(sessionOld)
    if err = sessionOld.Save(req, res); err != nil {
        fmt.Println("Error saving session: %v", err)
    }
}

//handler for Session
func SessionHandler(res http.ResponseWriter, req *http.Request) {

    router.PathPrefix("/").Handler(http.FileServer(http.Dir("../static/")))
    session, _ := store.Get(req, "loginSession")

    fmt.Println("Session in SessionHandler")
    fmt.Println(session)


    if val, ok := session.Values["email"].(string); ok {
        // if val is a string
        switch val {
        case "": {
            http.Redirect(res, req, "html/login.html", http.StatusFound) }
        default:
            http.Redirect(res, req, "html/home.html", http.StatusFound)
        }
    } else {
        // if val is not a string type
        http.Redirect(res, req, "html/login.html", http.StatusFound)
    }
}

有人可以告诉我我做错了什么。提前致谢。

正确答案

首先: 你永远不应该使用 md5 来散列密码。[阅读这篇文章](http://www.codinghorror.com/blog/2012/04/speed- hashing.html)了解原因,然后使用 Go 的bcrypt 包。您还应该[参数化您的 SQL 查询](http://www.codinghorror.com/blog/2005/04/give-me-parameterized-sql-or- give-me-death.html),否则您可能会 遭受灾难性 的SQL 注入攻击。

无论如何:这里有几个问题需要解决:

  • 您的会话没有“坚持”是因为您将其设置Path/loginSession- 因此当用户访问任何其他路径(即/)时,会话对该范围无效。

您应该在程序初始化时设置会话存储并在那里设置选项:

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

func init() {

   store.Options = &sessions.Options{
    Domain:   "localhost",
    Path:     "/",
    MaxAge:   3600 * 8, // 8 hours
    HttpOnly: true,
}

您可能会设置更具体的路径的原因是,如果登录的用户始终位于子路由中,例如/accounts. 在你的情况下,这不是正在发生的事情。

我应该补充一点,Web Inspector 中的 Chrome 的“资源”选项卡(资源 > Cookie)对于调试此类问题非常有用,因为您可以看到 cookie 过期、路径和其他设置。

  • 你也在检查session.Values["email"] == nil,这是行不通的。Go 中的空字符串只是"",因为session.Values是 a map[string]interface{},所以您需要将值输入到字符串中:

IE

if val, ok := session.Values["email"].(string); ok {
      // if val is a string
      switch val {
             case "":
                 http.Redirect(res, req, "html/login.html", http.StatusFound)
             default:
                 http.Redirect(res, req, "html/home.html", http.StatusFound)
      }
    } else {
        // if val is not a string type
        http.Redirect(res, req, "html/login.html", http.StatusFound)
    }

我们处理“不是字符串”的情况,所以如果会话不是我们所期望的(客户端修改了它,或者我们的程序的旧版本使用了不同的类型),我们会明确说明程序应该做什么。

  • 保存会话时,您没有检查错误。

    sessionNew.Save(req, res)
    

... 应该:

    err := sessionNew.Save(req, res)
    if err != nil {
            // handle the error case
    }
  • SessionHandler 您应该在提供静态文件之前 获取/验证会话(但是,您正在以一种非常迂回的方式进行操作):

    func SessionHandler(res http.ResponseWriter, req *http.Request) {
    session, err := store.Get(req, "loginSession")
    if err != nil {
        // Handle the error
    }
    
    if session.Values["email"] == nil {
        http.Redirect(res, req, "html/login.html", http.StatusFound)
    } else {
       http.Redirect(res, req, "html/home.html", http.StatusFound)
    }
    // This shouldn't be here - router isn't scoped in this function! You should set this in your main() and wrap it with a function that checks for a valid session.
    router.PathPrefix("/").Handler(http.FileServer(http.Dir("../static/")))
    

    }

本篇关于《使用 gorilla 会话时未保存 golang 中的会话变量》的介绍就到此结束啦,但是学无止境,想要了解学习更多关于Golang的相关知识,请关注golang学习网公众号!

声明:本文转载于:Golang技术栈 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>