今天在处理这个功能时本能地想到,好像在配置文件中有印象过通过配置用户数量就可以实现 限制用户功能。但是找了半天没找到 ,后来想到 那是采用session时的一个maxSession参数,分离版使用JWT没有用到session也就没了。

后来我就好奇为什么JWT没有类似的参数配置...(其实是因为我懒,不想写哈哈哈)

那就实现一个吧,思路很简单,由于JWT的无状态特性,用户信息(token)都存在redis中,我们可以拿到redis中的在线用户数量,再与我们的系统最大限制数进行比对就可以了,达到最大就拦截请求。

限制登陆拦截器


/**
 * 最大用户登录数限制
 *  
 * @author jiangfy
 */
@Component
public class MaxOnlineUsersInterceptor implements HandlerInterceptor {
    // 最大在线用户数量
    private int maxOnlineUsers;

    @Resource
    private RedisCache redisCache;
    @Resource
    private ISysUserOnlineService userOnlineService;
    @Resource
    ISysConfigService configService;




    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
          //我这边是把最大用户数量的配置放在了若依自带的sys_config配置表中,你也可以自定义在配置文件中都可以。
        maxOnlineUsers = Integer.parseInt(configService.selectConfigByKey("sys.user.loginNum"));

        // 检查当前在线用户数量是否已经达到最大限制
        Long loginUserNum = getLoginUserNum();
        if (loginUserNum >= maxOnlineUsers) {
            // 当前在线用户数量超过最大限制
            Map<String, Object> responseData = new HashMap<>();
            // 这边是因为有特定的返回格式所以处理下
            responseData.put("code", HttpServletResponse.SC_INTERNAL_SERVER_ERROR);
            responseData.put("msg", "当前系统用户数量过多,请稍后再试!");

            ObjectMapper objectMapper = new ObjectMapper();
            String json = objectMapper.writeValueAsString(responseData);

            //这里是请求响应状态status,跟响应结果code不一样
            response.setStatus(HttpServletResponse.SC_OK);
            response.setContentType("application/json;charset=utf-8");
            response.getWriter().write(json);
            return false;
        }

        return true;
    }

    // 获取当前在线用户数量
    private Long getLoginUserNum() {
        Collection<String> keys = redisCache.keys(Constants.LOGIN_TOKEN_KEY + "*");
        List<SysUserOnline> userOnlineList = new ArrayList<SysUserOnline>();
        for (String key : keys) {
            LoginUser user = redisCache.getCacheObject(key);
            user.setExpireTime(redisCache.getKeyExpire(key));
            userOnlineList.add(userOnlineService.loginUserToUserOnline(user));
        }
        Collections.reverse(userOnlineList);
        userOnlineList.removeAll(Collections.singleton(null));
        long total = new PageInfo(userOnlineList).getTotal();
        return total;
    }

}

注册拦截器


/**
 * @Author Jiangfy
 * @Description 防止超过系统最大登陆人数拦截器
 **/
@Configuration
public class LoginConfig implements WebMvcConfigurer {

    @Autowired
    private MaxOnlineUsersInterceptor maxOnlineUsersInterceptor;
    /**
     * 添加过滤器
     *
     * @param registry
     */
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        //这里只对登录方法进行拦截其余不处理
        registry.addInterceptor(maxOnlineUsersInterceptor).addPathPatterns("/login");
    }

}

最近写拦截器太多,感觉什么都能用拦截器处理啧啧

就这样吧,还挺好用

Logo

快速构建 Web 应用程序

更多推荐