请教如何使用 gorilla/sessions 实现多点登陆 - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
现在注册
已注册用户请  登录
The Go Programming Language
http://golang.org/
Go Playground
Go Projects
Revel Web Framework
dt2vba
V2EX    Go 编程语言

请教如何使用 gorilla/sessions 实现多点登陆

  •  
  •   dt2vba 2019 年 6 月 6 日 3995 次点击
    这是一个创建于 2411 天前的主题,其中的信息可能已经有所发展或是发生改变。
    比如一个账户可以从四个地方登陆

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

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

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

    非常期待你的帮助。
    10 条回复    2019-06-08 07:42:03 +08:00
    jedrek
        1
    jedrek  
       2019 年 6 月 7 日   1
    将一次 request - response 当成一次 session 不可以解决吗?想不通为何一定要整个长 session
    dt2vba
        2
    dt2vba  
    OP
       2019 年 6 月 7 日
    @jedrek 非常感谢你的提醒,晚安。
    dt2vba
        3
    dt2vba  
    OP
       2019 年 6 月 7 日
    @jedrek 你好,可以再解释一下吗?
    jedrek
        4
    jedrek  
       2019 年 6 月 7 日   1
    你要做的其实是 http 的身份鉴定和令牌有效期。

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

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

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

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

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

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

    若要考虑修改密码后吊销所有令牌,在设计上又稍微复杂一点。
    dt2vba
        5
    dt2vba  
    OP
       2019 年 6 月 7 日
    @jedrek
    非常感谢你的详细的回复,尤其是关于令牌解释的部分,清晰地简述用户认证流程,令人印象深刻。

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

    但是对于用户注销登录状态,我不太确定令牌的方式是否可以实现。
    dt2vba
        6
    dt2vba  
    OP
       2019 年 6 月 7 日
    @jedrek 非常感谢你的帮助,借助 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
    ...
    }
    jedrek
        7
    jedrek  
       2019 年 6 月 7 日   1
    在上面的身份鉴定的基础上,另外使用一次性口令。

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

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

    可以使用随机数做口令,因为是一次性的,具有排他性,所以不需要考虑重放攻击。但是有可能和自己已存在的口令冲突,可以用时间戳+随机数做口令,不需要加密或签名
    jedrek
        8
    jedrek  
       2019 年 6 月 7 日   1
    我不确定 jwt 是否考虑了客户端拷贝 token 来实现更多客户端同时使用
    jedrek
        9
    jedrek  
       2019 年 6 月 7 日   1
    更正:
    当第五个客户端登录时,服务端检测当前用户已有四个令牌了,拒绝登录。
    当第五个客户端登录时,服务端检测当前用户已有四个口令了,拒绝登录。

    令牌 -> 口令
    dt2vba
        10
    dt2vba  
    OP
       2019 年 6 月 8 日 via Android
    @jedrek
    我简单地试了一下,在已有四个客户端登录的情况下,复制任一有效的 jwt token,写入第五个客户端的 request header,的确可以登录。这时,已经有五个客户端处于在线状态。

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

    再次感谢你的帮助!
    关于     帮助文档     自助推广系统     博客     API     FAQ     Solana     918 人在线   最高记录 6679       Select Language
    创意工作者们的社区
    World is powered by solitude
    VERSION: 3.9.8.5 25ms UTC 19:10 PVG 03:10 LAX 11:10 JFK 14:10
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86