文档章节

面试题:限制用户登录(请求)频率,如限制用户在1分钟之内最多登录10次

l
 lzg14
发布于 2015/08/07 16:02
字数 587
阅读 2489
收藏 17

基本思路:通过一个队列保存最近10次的登录记录,下一次登录请求来时,通过与队列中的第一条进行比较,如果在1分钟之内则拒绝请求,否则移除队首元素,将新的登录记录加到队尾。

package cn.com.learn;

import java.util.LinkedList;
import java.util.Random;

import static java.lang.Thread.sleep;

/**
 * 模拟同一用户快速多次登录(请求),通过(UserLoginLimiter)限制
 * Created by Jason li on 2015/8/6.
 */
public class UserLoginTimeController {

    public static void main(String[] args) {

        //限制器,限制在1秒之内最多登录10次
        UserLoginLimiter limiter = new UserLoginLimiter(1000, 10);

        Random r = new Random();
        int allowCount = 0;
        int denyCount = 0;

        //模拟100次登录请求
        for (int i = 0; i < 100; i++) {
            LoginRecord loginRecord = new LoginRecord("123.456.789.10", System.currentTimeMillis(), "Jason.Li");
            try {
                sleep(r.nextInt(50)); //两次登录之间间隔的毫秒数
            } catch (InterruptedException e) {
                e.printStackTrace();
            }

            if (limiter.check(loginRecord)) {
                System.out.println(loginRecord + "允许登录!");
                allowCount ++;
            } else {
                System.out.println(loginRecord + "禁止登录!");
                denyCount ++;
            }
        }
        System.out.println("允许数量:" + allowCount );
        System.out.println("拒绝数量:" + denyCount );
    }


}

/**
 * 用户登录记录限制类
 * 限制在一定时长(thresholdInMillisecond)内最多登录(maxLoginTimes)次
 */
class UserLoginLimiter {

    private int maxLoginTimes; //一定时间(thresholdInMillisecond值)内的最多登录次数
    private int thresholdInMillisecond; //时长
    private LinkedList<LoginRecord> loginRecordList; //最近的登录队列


    /**
     * 检查登录记录,
     * 对在(thresholdInMillisecond)时长内超过(maxloginTimes)次的登录记录返回false,否则返回true;
     * @param curLR
     * @return
     */
    public boolean check(LoginRecord curLR) {

        //检查设置的值,对0及负数表示不限制登录
        if (maxLoginTimes <= 0 || thresholdInMillisecond <= 0) return true;

        //队列长度未到maxLoginTimes的不用限制
        if (loginRecordList.size() < maxLoginTimes) {
            loginRecordList.addLast(curLR);
            return true;
        }

        //队列长度达到maxLoginTimes的,清理和当前记录比较超过thresholdInMillisecond值的记录
        LoginRecord firstLR = loginRecordList.getFirst();
        while (loginRecordList.size() > 0 && firstLR.getTime() + thresholdInMillisecond < curLR.getTime()) {
            loginRecordList.removeFirst();
            if (loginRecordList.size() > 0) {
                firstLR = loginRecordList.getFirst();
            } else {
                break;
            }
        }

        //检查队列是否有空间添加新的记录
        if (loginRecordList.size() < maxLoginTimes) {
            loginRecordList.addLast(curLR);
            return true;
        } else {
            return false; //队列中的记录与当前登录记录发生在thresholdInMillisecond内,拒绝
        }
    }
    private UserLoginLimiter() {}

    public UserLoginLimiter(int thresholdInMillisecond, int maxLoginTimes) {
        this.thresholdInMillisecond = thresholdInMillisecond;
        this.maxLoginTimes = maxLoginTimes;
        loginRecordList = new LinkedList<LoginRecord>();
    }
}

/**
 * 用户登录记录类
 */
class LoginRecord {
    private String ip;
    private long time;
    private String username;

    public LoginRecord(String ip, long time, String username) {
        this.ip = ip;
        this.time = time;
        this.username = username;
    }

    public String getIp() {
        return ip;
    }

    public long getTime() {
        return time;
    }

    public String getUsername() {
        return username;
    }

    @Override
    public String toString() {
        return "LoginRecord{" +
                "ip='" + ip + '\'' +
                ", time=" + time +
                ", username='" + username + '\'' +
                '}';
    }
}


© 著作权归作者所有

l
粉丝 8
博文 30
码字总数 12886
作品 0
朝阳
私信 提问
加载中

评论(4)

冷静一下
能不能做个拦截器对ip访问频率限制
j
johnxue2013
你这个在并发环境下 并不是线程安全的 貌似没意义
l
lzg14 博主

引用来自“Barret_Guo”的评论

一般是限制IP吧,限制用户有什么用??
他们做的是轻应用,所有请求都来自微信,ip相同。估计是想对某些恶意微信用户进行限制。
Barret_Guo
Barret_Guo
一般是限制IP吧,限制用户有什么用??
用redis实现API访问频率的限制

一般对外开放的API需要限制访问频率,主要有两方面目的: 1. 防止短时间内请求过多对接口压力大影响到其正常使用, 例如单用户一分钟之内只能访问多少次。 2. 限制测试用户使用接口的单日访问次...

aibati2008
2016/06/16
1K
0
状态码约定

(大萝卜 12月14日保存) 0——未知错误/未预料到的错误/冷门到没有分配错误代码的错误 1——成功 详细的错误代码: 一、公共部分 1000——Token错误 1001——非法操作 1002——非法数据 1003...

loliw
2014/12/21
3
0
用Python绕过“登录3次错误,等待一分钟”的限制

  PS:本文仅作技术分享,禁止用于非法用途   *本文原创作者:yearnwang,本文属FreeBuf原创奖励计划,未经许可禁止转载   在院子里面看到了一个没人用的路由器(ws860s),看起来像个...

FreeBuf
2018/08/06
0
0
centos6.5离线安装ftp服务

1、查看是否安装vsftp rpm -qa | grep vsftpd 如果出现vsftpd-2.0.5-21.el5,说明已经安装 vsftp 2、下载vsftpd: ftp://rpmfind.net/linux/centos/6.7/os/x8664/Packages/vsftpd-2.2.2-14.e......

zqz0125
2015/08/27
4.4K
0
LINUX下面安装VSFTPD

yum -y install vsftpd 相关的文件 rpm -q vsftpd vsftpd-2.2.2-11.el64.1.x8664rpm -ql vsftpd/etc/logrotate.d/vsftpd 日志轮巡/etc/pam.d/vsftpd 验证机制/etc/rc.d/init.d/vsftpd 服务启......

陈映亮
2016/07/26
12
0

没有更多内容

加载失败,请刷新页面

加载更多

Spring使用ThreadPoolTaskExecutor自定义线程池及实现异步调用

多线程一直是工作或面试过程中的高频知识点,今天给大家分享一下使用 ThreadPoolTaskExecutor 来自定义线程池和实现异步调用多线程。 一、ThreadPoolTaskExecutor 本文采用 Executors 的工厂...

CREATE_17
今天
5
0
CSS盒子模型

CSS盒子模型 组成: content --> padding --> border --> margin 像现实生活中的快递: 物品 --> 填充物 --> 包装盒 --> 盒子与盒子之间的间距 content :width、height组成的 内容区域 padd......

studywin
今天
7
0
修复Win10下开始菜单、设置等系统软件无法打开的问题

因为各种各样的原因导致系统文件丢失、损坏、被修改,而造成win10的开始菜单、设置等系统软件无法打开的情况,可以尝试如下方法解决 此方法只在部分情况下有效,但值得一试 用Windows键+R打开...

locbytes
昨天
8
0
jquery 添加和删除节点

本文转载于:专业的前端网站➺jquery 添加和删除节点 // 增加一个三和一节点function addPanel() { // var newPanel = $('.my-panel').clone(true) var newPanel = $(".triple-panel-con......

前端老手
昨天
8
0
一、Django基础

一、web框架分类和wsgiref模块使用介绍 web框架的本质 socket服务端 与 浏览器的通信 socket服务端功能划分: 负责与浏览器收发消息(socket通信) --> wsgiref/uWsgi/gunicorn... 根据用户访问...

ZeroBit
昨天
10
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部