我制作了自己的身份验证(和单 session 身份验证)方法,将 session 保存到 redis,方法是:
- 我检查一下,浏览器是否有来 self 的服务器的 cookie,如果没有,则创建并保存在浏览器中
- 检查cookie id是否存在于redis中,如果存在,则下一步,如果不存在则重定向到登录
- 以cookie id为key查看redis的值是多少,value为username,如果username存在,则通过username查看redis中获取的值,如果username有cookie id值,则比较cookie id是否与当前浏览器相同id,如果不是,则重定向到登录
代码
请求前:
func (hs BeforeRequest) ServeHTTP(w http.ResponseWriter, r *http.Request) {
if !strings.Contains(r.RequestURI, "/login") && !strings.Contains(r.RequestURI, "/logout") {
// Check is user has `guid` cookie
Guid, err := r.Cookie("guid")
// if cookie not available, set cookie and redirect to login
if err != nil {
// Set the cookie
expiration := time.Now().Add(365 * 24 * time.Hour)
cookie := http.Cookie{Name: "guid", Value: helper.GenerateGuid(), Expires:expiration}
http.SetCookie(w, &cookie)
// Redirect to login
http.Redirect(w, r, "/login", 301)
return
} else {
// Return username that used by user (by it's Guid)
_, err := redisdb.Get(Guid.Value).Result()
if err != redis.Nil {
// Get active Guid by username, return active Guid
UsedFor, err := redisdb.Get(IsHasRedis).Result()
if err != redis.Nil && err == nil {
if UsedFor != Guid.Value {
fmt.Println("this account used in another session")
http.Redirect(w, r, "/login", 301)
return
}
} else {
// definitely not logged in
http.Redirect(w, r, "/login", 301)
return
}
} else {
// definitely not logged in
http.Redirect(w, r, "/login", 301)
return
}
}
}
// handle the request.
hs[0].ServeHTTP(w, r)
}
登录:
func LoginExecute(w http.ResponseWriter, r *http.Request, ps httprouter.Params) {
err := r.ParseForm() // Must be called before writing response
if err != nil {
fmt.Println(err)
} else {
if processRequest(r) {
Username, Password := r.Form["username"], r.Form["password"]
if len(Username) > 0 && len(Password) > 0 {
if len(Username[0]) <= 20 && len(Password[0]) <= 50 {
User := structs.Users{}
database, err := helper.DataDatabase()
if err != nil {
http.Error(w, "Couldn't Connect to Database", 500)
return
}
err = database.C("users").Find(bson.M{"username": Username[0]}).One(&User)
if err == nil {
CompareError := bcrypt.CompareHashAndPassword([]byte(User.Password), []byte(Password[0]))
if CompareError == nil {
Guid, err := r.Cookie("guid")
if err == nil {
redisdb.Set(Guid.Value, Username[0], 6 * time.Hour)
redisdb.Set(Username[0], Guid.Value, 6 * time.Hour)
http.Redirect(w, r, "/", 301)
} else {
http.Redirect(w, r, "/login?err=disabled-cookie", 301)
}
} else {
http.Redirect(w, r, "/login?err=password", 301)
}
} else {
http.Redirect(w, r, "/login?err=username", 301)
}
}
}
} else {
// recaptcha failed
http.Redirect(w, r, "/login?err=username", 301)
}
}
}
问题是,这个auth方法不稳定,idk为什么但是在用户成功登录之后:
- 访问/blog 重定向到登录
- 访问/博客(打开开发者工具)工作
- 访问/设置工作
- 几分钟/几小时后访问/settings 重定向到/login
- 我登录,成功,访问/settings,再次重定向到/login
是的,只是不稳定
注意:
- 我使用“github.com/julienschmidt/httprouter”进行路由
- “github.com/go-redis/redis”用于 redis
最佳答案
301 响应状态表示 Moved Permanently,允许浏览器无限期地缓存响应。使用 302 Found 代替重定向,或者根本不重定向(您可以立即提供登录页面)。
打开开发者工具很可能会禁用缓存,使其正常工作。
关于go - net/http auth 方法不稳定,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/55159586/