Sa-Token 超时时间设置问题

6,674 阅读3分钟

问题描述

使用过程中关于timeout和activity-timeout的设置碰到一点问题。

  • 会话突然失效
  • redis中无效token永不删除
  • 失效的token不能及时删除

官网:Token有效期详解 - Sa-Token

期望场景

用户在超时时间内,有操作时自动续期,超时后自动清除会话,基本和sa-token的临时有效期行为一致,不需要长期有效期到期时,强制退出,不允许并发登录。
第一反应是使用如下配置:

# token有效期,单位s 默认30天, -1代表永不过期
timeout: -1
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
activity-timeout: 5
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: false

问题现象

超时重新登录后,原token并没有清除,还保留在redis中,并且无失效日期。

image.png
如果timeout=-1,所有的失效会话的token虽然都不能用了,但是会永远存在redis中

如果给timeout设置一个值,虽然能解决redis中无效数据的问题,但是会碰到会话突然失效的问题,如使用如下配置:

# token有效期,单位s 默认30天, -1代表永不过期
timeout: 10
# token临时有效期 (指定时间内无操作就视为token过期) 单位: 秒
activity-timeout: 5
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: false

登录后一直操作,虽然临时有效期会自动续期,但是长期有效期到期时,即使上一秒还在操作,下一秒也会强制清除会话,这样用户体验就会很差

解决思路

使用timeout设置会话有效期,禁用临时有效期,手动为长期有效期续期。

image.png

具体配置和代码

# token有效期,单位s 默认30天, -1代表永不过期
timeout: 2592000
# token临时有效期 ,永不过期
activity-timeout: -1
# 是否允许同一账号并发登录 (为true时允许一起登录, 为false时新登录挤掉旧登录)
is-concurrent: false
autoRenew: false

注册拦截器的时候,每次校验都增加长期有效期的期限

@Value("${sa-token.timeout}")
private long tokenTimeout;

 @Override
    public void addInterceptors(InterceptorRegistry registry) {
        log.info("排除路径:{}",excludePathList);
        registry.addInterceptor(new SaInterceptor(handle -> {
                    StpUtil.checkLogin();
                    //续约长期有效期,避免redis中大量无效的token
                    StpUtil.renewTimeout(tokenTimeout);
                }))
                .addPathPatterns("/**")
                .excludePathPatterns(excludePathList);
    }    

新的问题

因为不允许并发登录,用户重复登录的时候,会生成新的token,旧的token会失效。场景中设置的token有效期是30天,虽然到旧的无效token到期后会自动删除,但是要等30天才会删除

解决办法

使用监听器监听replac事件,token被顶替的时候,直接注销token。

@Component
public class DgbSaTokenListener extends SaTokenListenerForSimple {
    /**
     * 被顶下线时,删除对应的token
     * @param loginType 账号类别
     * @param loginId 账号id
     * @param tokenValue token值
     */
    @Override
    public void doReplaced(String loginType, Object loginId, String tokenValue) {
        log.info("token被顶替,注销token");
        StpUtil.logoutByTokenValue(tokenValue);
    }
}

总结

  • 避免使用timeout=-1的配置,会导致无效token永不删除
  • 禁用临时有效期,为timeout设置实际的值,保证无效token到期会删除
  • 校验登录时,手动为timeout续期,避免会话突然失效
  • 在监听器中监听replaced事件,及时清除无效的token

感谢

sa-token是一个功能很完备的鉴权框架,使用也很简单,感谢作者提供这么好用的框架。