用户 cookie 验证随机失败

User cookie verification fails randomly

我正在使用两个结构来保存用户信息

// SecureDevice holds a user's device's infos
type SecureDevice struct {
    Name     string // Defined by the user
    DeviceIP string
    Token    struct {
        Token        string
        StartingDate time.Time // The token is supposed to last only a week before becoming invalid
    }
}

// GlobalUser is a struct defining all user's infos registered inside the server
type GlobalUser struct {
    Username          string
    Password          string
    Salt              string
    Mail              string
    ValidationToken   string // Used to validate the user's mail adress
    Lang              string
    ConversationsID   []int // The private messages the user has part in
    SecureDevicesList []SecureDevice
}

我正在使用一个函数来检查用户是否已登录

// IsLoggedIn checks if client's token is valid
func IsLoggedIn(r *http.Request) string {
    ips := strings.Split(r.Header.Get("X-Forwarded-For"), ", ")
    ip := ips[0]
    cookie, err := r.Cookie("auth")
    if err != nil {
        return "ERR$" + "not_connected"
    }
    cookieValue := strings.Split(cookie.Value, "$")
    println(cookie.Value)
    user := GetUser(cookieValue[0])
    userToken := cookieValue[1]
    if user.Username == "" {
        return "ERR$" + "error"
    }
    for _, SecureDevice := range user.SecureDevicesList {
        if SecureDevice.DeviceIP == ip && SecureDevice.Token.Token == userToken { // We make sure that the token provided is actually the user's token
            if time.Since(SecureDevice.Token.StartingDate)*time.Hour >= 168 { // If token is older than 1 week, we throw it away
                return "ERR$" + "error_token_expired"
            } else if time.Since(SecureDevice.Token.StartingDate)*time.Second >= 30 { // If it's age is between 1 hour and one week, we renew it
                db, err := scribble.New("./brony/db", nil)
                if err != nil {
                    return "ERR$" + "error_internal"
                }
                tokenBytes, err := GenerateRandomBytes(64) // Generates a salt
                if err != nil {
                    return "ERR$" + "error_internal"
                }
                token := base64.URLEncoding.EncodeToString(tokenBytes)
                SecureDevice.Token.Token = token
                SecureDevice.Token.StartingDate = time.Now()
                errr := db.Write("users", user.Username, user)
                if errr != nil {
                    return "ERR$" + "error_internal"
                }
                return "TOK$" + user.Username + "$" + SecureDevice.Token.Token
            } else if time.Since(SecureDevice.Token.StartingDate)*time.Hour <= 1 {
                return "NIL$"
            }
        } else if SecureDevice.DeviceIP == ip {
            return "ERR$" + "error_bad_token"
        }
    }
    return "ERR$" + "error_device_not_registered"
}

但几乎总是在我用

加载页面时
status := IsLoggedIn(r)
println(status)

它经常给我一个错误,因为我正在打印 "IsLoggedIn" 以了解问题出在哪里

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
NIL$

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
ERR$error_token_expired

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
NIL$

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
ERR$error_token_expired
test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
ERR$error_token_expired

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
ERR$error_token_expired

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
ERR$error_token_expired

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
ERR$error_token_expired

test$ppDXRggtztyA9OBbdZh1t1ESqRo2XvuOBt4xlDai9kVxwq-_3zlWyvgNgA7AZcSpasJ_YnXZvoG                                                                                                                                                             qlz1syF9X8g==
NIL$

起初我以为是我的令牌的续订代码有问题,但是虽然有问题并且未完成,但似乎并不是它的问题,因为在几次 f5 之后,它说 cookie 没问题。我真的不明白问题出在哪里,而且它开始变得非常烦人,因为我不能让它这样,至少可以说让用户每次都执行 f5 并希望当页面将刷新,它会奇迹般地工作。代码在 debian 服务器上运行

您的问题可能是您处理 time.Since return 比较值的方式。

time.Since 方法 return 类型 Duration 并在内部表示为类型 int64。值以纳秒为单位。

试试这个-

elapsedHours := int64(time.Since(SecureDevice.Token.StartingDate).Hours())
if elapsedHours >= 168 {
    //...
} else if elapsedHours >= 30 {
   //...
} else if elapsedHours <= 1 {
   //...
}