Golang基于会话的身份验证

huangapple go评论89阅读模式
英文:

Golang session based authentication

问题

我正在尝试在golang中对用户进行身份验证(使用电子邮件和密码),但是在会话方面遇到了一些问题。似乎我无法从**/login/页面获取会话值到/**(主页)页面。

用户注册

hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(r.Form["passwordSignup"][0]), bcrypt.DefaultCost)

err = c.Insert(&model.UserModel{
Email: r.Form["emailSignup"][0],
Password: string(hashedPassword),
CreatedAt: time.Now(),
})

// TODO:会话管理是否应该在这里进行?
// 如果你愿意,你可以使用gorilla sessions

http.SetCookie(w, cookie)
http.Redirect(w, r, "/", 301) // 转到主页(只有经过身份验证的用户才能访问)

登录

if r.Form["emailLogin"][0] == result.Email
&& bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(r.Form["passwordLogin"][0])) == nil {

// TODO:在这里处理会话

http.Redirect(w, r, "/", 301) // 转到主页
} else {
http.Redirect(w, r, "/login/", 301)
}

我也查看了以下链接:
http://shadynasty.biz/blog/2012/09/05/auth-and-sessions/
https://www.youtube.com/watch?v=p0tGnjW_xxI

英文:

I am trying to authenticate a user (using email and password) in golang but I am having some problems with sessions. It seems like I cant retrieve the session value from /login/ to / (home) page.

User Registration

hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(r.Form["passwordSignup"][0]), bcrypt.DefaultCost)

err = c.Insert(&model.UserModel{
  Email:     r.Form["emailSignup"][0],
  Password:  string(hashedPassword),
  CreatedAt: time.Now(),
})

// TODO : should session management be made in here ???
// you can use gorilla sessions if you want as far it works

http.SetCookie(w, cookie)
http.Redirect(w, r, "/", 301) // goes to the homepage(only accessed by authenticated users)

Login

if r.Form["emailLogin"][0] == result.Email 
&& bcrypt.CompareHashAndPassword([]byte(result.Password), []byte(r.Form["passwordLogin"][0])) == nil {

  // TODO : Handling the session in here

  http.Redirect(w, r, "/", 301) // goes to the home page
} else {
  http.Redirect(w, r, "/login/", 301)
}

I checked this links too :
http://shadynasty.biz/blog/2012/09/05/auth-and-sessions/
https://www.youtube.com/watch?v=p0tGnjW_xxI

答案1

得分: 5

重要的是,你应该检查所有的错误 - 例如:

- hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(r.Form["passwordSignup"][0]), bcrypt.DefaultCost)
# 检查我们的错误,尤其是像密码哈希这样重要的事情
+ hashedPassword, err := bcrypt.GenerateFromPassword([]byte(r.Form["passwordSignup"][0]), bcrypt.DefaultCost)
if err != nil {
    http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
    return
}

你的相关 cookie 代码缺失了很多,但这是它应该看起来的样子:

cookie := &http.Cookie{
        Name: "my_app",
        Value: val, // 一些编码后的值
        Path: "/", // 否则默认为 /login,如果你在 /login 创建它的话(标准的 cookie 行为)
        MaxAge: 86400, // 一天
}

http.SetCookie(w, cookie)

或者,如果你使用 gorilla/sessions(我推荐使用,因为它可以正确验证 cookie),你可以这样做:

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

session.Options.Path = "/"
session.Values["user"] = user

err = session.Save(r, w)
if err != nil {
    http.Error(w, err.Error(), 500)
    return
}

http.Redirect(w, r, "/", 301)
英文:

Importantly, you should check all of your errors - e.g.:

- hashedPassword, _ := bcrypt.GenerateFromPassword([]byte(r.Form["passwordSignup"][0]), bcrypt.DefaultCost)
# Check our error, especially for something as important as password hashing
+ hashedPassword, err := bcrypt.GenerateFromPassword([]byte(r.Form["passwordSignup"][0]), bcrypt.DefaultCost)
if err != nil {
    http.Error(w, http.StatusText(http.StatusBadRequest), http.StatusBadRequest)
    return
}

A lot of your relevant cookie code is missing, but here's what it should look like:

cookie := &http.Cookie{
        Name: "my_app",
        Value: val, // Some encoded value
        Path: "/", // Otherwise it defaults to the /login if you create this on /login (standard cookie behaviour)
        MaxAge: 86400, // One day
}

http.SetCookie(w, cookie)

Alternatively, if you use gorilla/sessions (which I recommend because it correctly authenticates cookies), you would do the following:

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

session.Options.Path = "/"
session.Values["user"] = user

err := session.Save(r, w)
if err != nil {
    http.Error(w, err.Error(), 500)
    return
}

http.Redirect(w, r, "/", 301)

答案2

得分: 0

如果你正在寻找一个简单的会话管理解决方案,可以使用Redis或Memcache作为会话存储,我建议使用Jeff(免责声明:我是它的作者)。

在验证用户身份后,你只需像这样添加他们的会话:

func (s Server) Login(w http.ResponseWriter, r *http.Request) {
    user = Authenticate(r)
    if user != nil {
        // Key must be unique to one user among all users
        err := s.jeff.Set(r.Context(), w, user.Email)
        // 处理错误
    }
    // 完成登录
}

在使用Jeff中间件包装后,后续的请求将自动进行身份验证。该库的设计初衷是简单易用,并作为现有库的替代品。

请查看自述文件以获取更多关于使用和功能的详细信息:

https://github.com/abraithwaite/jeff#usage

英文:

If you're looking for a simple session management solution which uses Redis or Memcache as your session store, I suggest using Jeff (disclaimer: I wrote it).

After authenticating a user, you simply add their session like so:

func (s Server) Login(w http.ResponseWriter, r *http.Request) {
    user = Authenticate(r)
    if user != nil {
        // Key must be unique to one user among all users
        err := s.jeff.Set(r.Context(), w, user.Email)
        // handle error
    }
    // finish login
}

Subsequent requests will automatically be authenticated once wrapped with the Jeff middleware. The library was built with simplicity in mind and was built as an alternative to the existing libraries out there.

See the readme for more details on usage and features:

https://github.com/abraithwaite/jeff#usage

huangapple
  • 本文由 发表于 2016年2月7日 18:22:54
  • 转载请务必保留本文链接:https://go.coder-hub.com/35252253.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定