Golang Go语言中如何使用 gorilla/sessions 实现多点登陆

发布于 1周前 作者 htzhanglong 来自 Go语言

Golang Go语言中如何使用 gorilla/sessions 实现多点登陆
比如一个账户可以从四个地方登陆

我的解决办法是设置一个全局变量 var mapSessionStore=make(map[string][]*sessions.Session)

如果用户 A 第一次登陆成功,则把新创建的 session 添加至 mapSessionStore[“用户 A”]。以此类推。同时启动一个协程,对于 mapSessionStore 存储的每个 session,循环执行 session.IsNew,以此检测是否过期或者销毁,并进行相应的处理。

但是 session.IsNew 不能检测 session 是否过期。似乎这个解决办法不可行。

非常期待你的帮助。


更多关于Golang Go语言中如何使用 gorilla/sessions 实现多点登陆的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html

11 回复

将一次 request - response 当成一次 session 不可以解决吗?想不通为何一定要整个长 session

更多关于Golang Go语言中如何使用 gorilla/sessions 实现多点登陆的实战系列教程也可以访问 https://www.itying.com/category-94-b0.html


非常感谢你的提醒,晚安。

你好,可以再解释一下吗?

你要做的其实是 http 的身份鉴定和令牌有效期。

大致流程是在登录或注册成功后,服务端签发一个令牌返回给客户端,令牌常见存放在 cookie 中。客户端在下次请求时携带令牌,服务端验证令牌来判别此次请求的有效性,若令牌有效,说明此次请求的用户就是其声明的身份。反之不能证明身份的就不能通过。

其中的核心就是令牌,令牌中包含两部分信息,数据和签名,由服务端负责签发和验证。

举一个最小化的例子. ID 为 10000 的用户登录成功了,服务端对 ID 进行数字签名。服务端将 ID + 签名结果 拼接起来组成字符串令牌放到 cookie 中返回给客户端。客户端下次请求时将令牌带上,服务端校验令牌格式和数字签名的有效性。签名的目的是防止伪造和篡改,比如数据部分被改成 10001,这个在服务端就不能通过验证。目前比较推荐的签名算法是 ed25519。

如果你需要限制令牌的有效期,原理也是一样的,将用户 ID 和截止时间一起签名返回给客户端。下次验证是否已过截止时间就可以了。

为了美观和统一, 可以将数据部分 base64 编码后再和签名拼接,用 . 号分隔。

不嫌烦的话 jwt 可以做到这个事,虽然它定义的标准很糟糕。

若要考虑修改密码后吊销所有令牌,在设计上又稍微复杂一点。


非常感谢你的详细的回复,尤其是关于令牌解释的部分,清晰地简述用户认证流程,令人印象深刻。

可能我对我的需求解释地不是很清楚。比如,在同一时刻,用户 A,在浏览器 1、2、3、4 登录在线。此时,用户 A 无法在浏览器 5 成功登录(因为最多允许 4 个)。如果用户 A 在浏览器 3 注销登录,那么用户 A 则可以在浏览器 5 成功登录。

但是对于用户注销登录状态,我不太确定令牌的方式是否可以实现。

非常感谢你的帮助,借助 dgrijalva/jwt-go,基本实现了需求。以下是我的解决方案。如果你有空的话,并且愿意提出一些意见,那将是非常期待的。

首先定义一个结构体,存储用户的 token 信息

type TokenManager struct {
Lock sync.Mutex

//map[user] map[token]user
Token map[string]map[string]string
}

然后定义一个该结构体的方法,删除已经过期的 token

func (manager *TokenManager) DeleteTokenNotValid() {
//删除过期的 Token


return
}

定义一个全局的 TokenManager 结构体变量
var TokenStore=TokenManager{}

主函数

func main() {
//开启协程,删除已经过期的 token
go func() {
for true {
TokenStore.DeleteTokenNotValid()
}
}()

//业务处理函数

}

登录处理函数

func login(c echo.Context) error {
//如果请求携带有效的 token,则跳转至首页


//如果用户的 token 数量大于等于 4,则禁止登录


//创建用户的 token,并保存至 TokenStore.Token[user]

}

注销处理函数

func logout(c echo.Context) error {
//删除请求携带的有效 token

}

在上面的身份鉴定的基础上,另外使用一次性口令。

登录或注册成功后,服务端签发身份令牌和生成并保存新口令,然后将身份令牌和口令同时返回客户端,客户端将身份令牌和口令保存。下一次请求时,客户端携带口令和身份令牌,服务端做两个验证,一是请求的口令是否与已存在的匹配,二是身份令牌是否有效。两者都有效才通过。都验证通过后,返回时,生成新的口令返回给客户端(不需要更新身份令牌),服务端和客户端都需要更新保存新口令,下次请求同理。登出时删掉服务端对应的口令和客户端信息即可。

当第五个客户端登录时,服务端检测当前用户已有四个令牌了,拒绝登录。
当用户拷贝 http headers 试图突破限制时,第五个客户端接收了新的口令,原客户端的口令就会失效,所以还是四个客户端

可以使用随机数做口令,因为是一次性的,具有排他性,所以不需要考虑重放攻击。但是有可能和自己已存在的口令冲突,可以用时间戳+随机数做口令,不需要加密或签名

我不确定 jwt 是否考虑了客户端拷贝 token 来实现更多客户端同时使用

更正:
当第五个客户端登录时,服务端检测当前用户已有四个令牌了,拒绝登录。
当第五个客户端登录时,服务端检测当前用户已有四个口令了,拒绝登录。

令牌 -> 口令


我简单地试了一下,在已有四个客户端登录的情况下,复制任一有效的 jwt token,写入第五个客户端的 request header,的确可以登录。这时,已经有五个客户端处于在线状态。

我仔细地分析了一下,使用令牌和一次性口令,这个想法非常巧妙。似乎类似于 websocket 的心跳检测。

再次感谢你的帮助!

在Go语言中,使用gorilla/sessions库来实现多点登录(即允许同一用户在不同设备上同时登录)是一个常见的需求。以下是如何实现这一功能的简要步骤:

  1. 安装依赖: 首先,确保你已经安装了gorilla/sessions库。你可以通过以下命令安装它:

    go get github.com/gorilla/sessions
    
  2. 配置会话存储: 使用sessions.NewCookieStoresessions.NewFilesystemStore等函数来创建一个会话存储实例。例如,使用cookie存储:

    import (
        "github.com/gorilla/sessions"
    )
    
    store := sessions.NewCookieStore([]byte("your-secret-key"))
    
  3. 处理会话: 在每个请求中,通过store.Get获取或创建会话,并在会话中存储用户信息(如用户ID)。注意,不要存储敏感信息在cookie中,除非使用安全的cookie设置。

  4. 实现多点登录逻辑: 在服务器端,维护一个数据结构(如Redis或数据库中的表)来跟踪每个用户的活跃会话。当用户登录时,在数据结构中添加一个新条目。当用户注销或会话过期时,删除相应的条目。

  5. 会话管理: 确保实现适当的会话过期和失效策略,以防止会话劫持和会话固定攻击。

通过上述步骤,你可以使用gorilla/sessions在Go语言中实现多点登录功能。重要的是,要仔细设计和管理会话,以确保系统的安全性和用户体验。

回到顶部