Golang Go语言中如何使用 gorilla/sessions 实现多点登陆
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
将一次 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
库来实现多点登录(即允许同一用户在不同设备上同时登录)是一个常见的需求。以下是如何实现这一功能的简要步骤:
-
安装依赖: 首先,确保你已经安装了
gorilla/sessions
库。你可以通过以下命令安装它:go get github.com/gorilla/sessions
-
配置会话存储: 使用
sessions.NewCookieStore
或sessions.NewFilesystemStore
等函数来创建一个会话存储实例。例如,使用cookie存储:import ( "github.com/gorilla/sessions" ) store := sessions.NewCookieStore([]byte("your-secret-key"))
-
处理会话: 在每个请求中,通过
store.Get
获取或创建会话,并在会话中存储用户信息(如用户ID)。注意,不要存储敏感信息在cookie中,除非使用安全的cookie设置。 -
实现多点登录逻辑: 在服务器端,维护一个数据结构(如Redis或数据库中的表)来跟踪每个用户的活跃会话。当用户登录时,在数据结构中添加一个新条目。当用户注销或会话过期时,删除相应的条目。
-
会话管理: 确保实现适当的会话过期和失效策略,以防止会话劫持和会话固定攻击。
通过上述步骤,你可以使用gorilla/sessions
在Go语言中实现多点登录功能。重要的是,要仔细设计和管理会话,以确保系统的安全性和用户体验。