英文:
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:
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论