26

golang实现SSO(单点登录)

 3 years ago
source link: https://studygolang.com/articles/31375
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.

单点登录是一个我们平常经常能见到的功能,就是一个账号同一时间只能在一台设备上登录,后登录的设备会挤掉先登录的设备,比如我们的手机qq,如果在自己手机上登录了自己的qq账号,然后另一部手机上接着登录自己的qq,那么自己手机上的qq就会下线。

实现单点登录

实现单点登录的思路很简单,就是一个账号对应的token同一时间只有一个生效,也就是说每次用户登录除了生成一个token保存起来,还要删除掉之前的token。

  1. 用户登录,服务器生成token保存至redis(设置有效时间),并将token返回给前端,用户之后的每次请求需要携带token。
  2. 在拦截器中校验请求头中的token,判断token是否有效,每一次有效的请求都刷新token的有效时间。
  3. 同一个账号再次被登录时,删除之前的token,并生成新的token重复1操作。

步骤看起来都很简单,但有一个问题需要注意,每一次校验token是需要去redis中查询的,也就是说设置的key应该为token,value为userId(或者其它唯一标识),那么这个时候如何在登录时做到删除当前的token呢?如果只是有一个token-id的对应关系好像确实没办法获取到该账号当前token,所以还需要一个id-token的对应关系,可以直接通过id拿到token。

这里附上我实现token操作部分的代码,拦截器部分可以有很多种实现方式,我是用的echo框架的中间件来实现,如果需要的话评论区说一声我贴上来。

CreateToken(key string, expiration time.Duration) string :创建token,我在创建token的时候就会去判断是否存在旧的token然后删除。

ValidToken(token string) (id int) :验证token是否有效,0为失效。

DelToken(token string) :删除redis中的token信息。

/**
 * @Author lanni
 * @Description 创建token
 * @Date 2020/6/18 15:50
 * @Param key:登陆凭证(id),expiration:过期时间
 * @return token:令牌
 **/
func CreateToken(key string, expiration time.Duration) string {
   //生成token,这里生成token可以自己选择一个算法来生成,只要是长度足够的随机字符串就ok
   token := jwt.GenerateToken(key)
   //redis记录该账号登录状态
   client := redis.Open()
   defer client.Close()
   client.Set(token, key, expiration)
   //获取原token
   oldToken := client.Get(key)
   //如果原token不为空则删除
   if oldToken != "" {
      client.Del(oldToken)
   }
   //保存或更新该账号的当前登录token,用于单点登录
   client.Set(key, token, expiration)
   return token
}

/**
 * @Author lanni
 * @Description 验证token是否过期
 * @Date 2020/6/18 16:03
 * @Param
 * @return 返回token对应的id,查询为空时返回0
 **/
func ValidToken(token string) (id int) {
   //查询
   client = redis.Open()
   defer client.Close()
   id, err := strconv.Atoi(client.Get(token))
   if id != 0 && err == nil {
      return
   }
   return 0
}

/**
 * @Author lanni
 * @Description 删除sso中的token信息
 * @Date 2020/7/9 15:32
 * @Param
 * @return
 **/
func DelToken(token string) {
   client := redis.Open()
   defer client.Close()
   //获取原token对应的id
   id := client.Get(token)
   //token时限设置为1s
   client.Set(token, id, time.Second)
   client.Set(id, token, time.Second)
}

有疑问加站长微信联系

iiUfA3j.png!mobile

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK