SaToken监听器插件:过期注销事件监听

本插件作为官方监听器功能的补充.

默认监听器只能在用户调用 logout() 方法且未下线时触发注销事件,

SaToken 框架不会因为(全局或临时)过期而自动触发注销事件.

本插件就是为了解决此问题.

插件源码:

public class WatchDogPlugin {
    private static Map<String, LoginObj> map = new HashMap<>(); // token->登录信息
    private static Integer timeInterval = 1;
    private static Thread refreshThread;

    public static void start() {
        if (refreshThread == null) {
            // 新注册监听器(与开发者监听器共存)
            SaTokenEventCenter.registerListener(new SaTokenListener() {
                @Override
                public void doLogin(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
                    saveLoginInfo(loginType, loginId, tokenValue, loginModel);
                }

                @Override
                public void doLogout(String loginType, Object loginId, String tokenValue) {
                    invalidToken(loginType, loginId, tokenValue);
                }

                @Override
                public void doKickout(String loginType, Object loginId, String tokenValue) {

                }

                @Override
                public void doReplaced(String loginType, Object loginId, String tokenValue) {

                }

                @Override
                public void doDisable(String loginType, Object loginId, String service, int level, long disableTime) {

                }

                @Override
                public void doUntieDisable(String loginType, Object loginId, String service) {

                }

                @Override
                public void doCreateSession(String id) {

                }

                @Override
                public void doLogoutSession(String id) {

                }

                @Override
                public void doRenewTimeout(String tokenValue, Object loginId, long timeout) {

                }
            });
            // 增加循环线程
            resetRefreshThread();
        }
    }

    /**
     * 登录后保存信息
     * @param loginType
     * @param loginId
     * @param tokenValue
     * @param loginModel
     */
    public static void saveLoginInfo(String loginType, Object loginId, String tokenValue, SaLoginModel loginModel) {
        LoginObj obj = new LoginObj(loginType, loginId, loginModel.getDeviceOrDefault(), tokenValue);
        map.put(tokenValue, obj);
    }


    /**
     * 循环查看当前已登录用户状态
     */
    private static void resetRefreshThread() {
        refreshThread = new Thread(() -> {
            while (true){
                try{Thread.sleep(timeInterval*1000);}catch (Exception ignored) {}
                List<String> list = new ArrayList<>();
                try {
                    map.forEach((k, v) -> {
                        String token = v.getToken();
                        StpLogic stpLogic = SaManager.getStpLogic(v.getLoginType());
                        String loginId = stpLogic.getLoginIdNotHandle(token);
                        if(!stpLogic.isValidLoginId(loginId)) {
                            // 全局过期
                            SaTokenEventCenter.doLogout(v.getLoginType(), v.getLoginId(), token);
                            list.add(token);
                        } else {
                            long t = stpLogic.getTokenActivityTimeoutByToken(token);
                            if (t!=-1 && t<=0) {
                                // 临时过期
                                stpLogic.logout(v.getLoginId(), v.getDevice());
                                list.add(token);
                            }
                        }
                    });
                }catch (ConcurrentModificationException ignored){}
                list.forEach(token -> {
                    map.remove(token);
                });
            }
        });
        refreshThread.start();
    }

    /**
     * 单位: 秒
     * t大于等于 1
     * @param t
     */
    public static void setTimeInterval(Integer t) {
        if(t<1) {
            t = 1;
        }
        timeInterval = t;
    }

    /**
     * 返回定时器间隔, 单位秒
     * @return
     */
    public static Integer getTimeInterval() {
        return timeInterval;
    }

    /**
     * 事件已触发则删除临时数据
     *
     * @param loginType
     * @param loginId
     * @param token
     */
    public static void invalidToken(String loginType, Object loginId, String token) {
        /**
         * 正常logout()方法会被动触发
         * 全局过期主动触发
         * 临时过期间接触发
         */
        if (map.containsKey(token)) {
            map.remove(token);
        }
    }

}

此外还需要一个当前用户对象 LoginObj , 用于注销事件参数(@Data注解需要开启Lombok)

@Data
public class LoginObj {
    private String loginType;
    private Object loginId;
    private String device;
    private String token;

    public LoginObj(){}
    public LoginObj(String loginType, Object loginId,String device, String token) {
        this.loginType = loginType;
        this.loginId = loginId;
        this.device = device;
        this.token = token;
    }
    
}

此时插件已经制作完成, 接下来在项目启动时开启插件就完成了

// 插件启动
WatchDogPlugin.start();

// 设置循环时间: 默认1秒检查一次(可以不设置)
WatchDogPlugin.setTimeInterval(1);

此时开发者再按照官方文档实现侦听器后即可做到过期自动触发注销事件

需要注意的时, 本插件非常消耗性能, 这也是官方框架不支持此功能的主要原因

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值