防止用户恶意刷新过滤器

2024-05-14 23:38

本文主要是介绍防止用户恶意刷新过滤器,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

防止用户恶意刷新过滤器
2012-08-15       0 个评论      
收藏     我要投稿
为了防止用户对网站页面刷新过于频繁,需要对这种恶意操作进行判断并且屏蔽.虽然公司要有这样的一个功能,但是我觉得太没有必要了.只要你服务器够好,你何必需要这样的功能呢?下面是全部代码(仅供大家参考,我觉得实际意义不是很大):
 
import java.io.IOException; 
import java.util.Map; 
import java.util.concurrent.ConcurrentHashMap; 
import java.util.concurrent.CopyOnWriteArrayList; 
 
import javax.servlet.Filter; 
import javax.servlet.FilterChain; 
import javax.servlet.FilterConfig; 
import javax.servlet.ServletException; 
import javax.servlet.ServletRequest; 
import javax.servlet.ServletResponse; 
import javax.servlet.http.HttpServletRequest; 
import javax.servlet.http.HttpServletResponse; 
 
import com.f139.frame.util.NetUtil; 
 
public class RefreshFilter implements Filter { 
 
    private static final Map<String, Integer> ipcount = new ConcurrentHashMap<String, Integer>(); 
 
    @Override 
    public void doFilter(ServletRequest request, ServletResponse response, 
            FilterChain chain) throws IOException, ServletException { 
 
        try { 
            filter((HttpServletRequest) request, 
                    (HttpServletResponse) response, chain); 
        } catch (InterruptedException e) { 
            e.printStackTrace(); 
        } 
    } 
 
    private void filter(HttpServletRequest request, 
            HttpServletResponse response, FilterChain chain) 
            throws IOException, ServletException, InterruptedException { 
        response.setCharacterEncoding("UTF-8"); 
        request.setCharacterEncoding("UTF-8"); 
        // 获得用户的IP地址,根据用户IP地址来判断此用户是否刷新过于频繁 
        String userIP = NetUtil.getIpAddr(request); 
        Cache cache = Cache.getInstance(); 
        cache.increment(userIP); 
        if (cache.isUpCount(userIP)) { 
            Integer count = ipcount.get(userIP); 
            if (count != null) { 
                ipcount.put(userIP, count + 1); 
                System.out.println(ipcount.get(userIP)); 
            } else { 
                count = 0; 
                ipcount.put(userIP, count + 1); 
            } 
            if (ipcount.get(userIP) > 3) { 
                response.getWriter().println("很抱歉,您操作过于频繁."); 
                //403页面 
                ((HttpServletResponse) response) 
                        .sendError(HttpServletResponse.SC_FORBIDDEN); 
                /**
                 * 在这里可以使用quartz工作调度对map进行定时的清理,时被禁止的用户可以重新访问本页面
                 */ 
                return; 
            } 
            response.getWriter().println("操作频繁,请3秒后再试"); 
            return; 
        } 
        chain.doFilter(request, response); 
    } 
 
    @Override 
    public void destroy() { 
 
    } 
 
    @Override 
    public void init(FilterConfig config) throws ServletException {  
 
    } 
 
    private static class Cache { 
 
        private static final ConcurrentHashMap<String, CopyOnWriteArrayList<Long>> map = new ConcurrentHashMap<String, CopyOnWriteArrayList<Long>>(); 
        // 用户闲置时间 
        private static final long EXPIRE_TIME = 1000 * 5L; 
        // 用户频繁刷新次数上限,第六次就禁止刷新 www.2cto.com
        private static final int MAX_COUNT = 5; 
 
        private static final Cache cache = new Cache(); 
 
        private Cache() { 
            new Thread(new ClearCacheThread()).start(); 
        } 
 
        public static Cache getInstance() { 
            return cache; 
        } 
 
        // 每次刷新页面的时候就在缓存中增加一个刷新时间点(标识刷新次数) 
        public void increment(String key) { 
            CopyOnWriteArrayList<Long> list = map.get(key); 
            if (list == null) { 
                map.put(key, new CopyOnWriteArrayList<Long>()); 
            } 
            map.get(key).add(new Long(System.currentTimeMillis())); 
        } 
 
        // 是否到达指定数量 
        public boolean isUpCount(String key) { 
            CopyOnWriteArrayList<Long> list = map.get(key); 
            if (list == null) { 
                return false; 
            } 
            return list.size() > MAX_COUNT; 
        } 
 
        // 清理过期数据线程 
        private static class ClearCacheThread implements Runnable { 
            @Override 
            public void run() { 
                while (true) { 
                    try { 
                        // 当页面禁止刷新时让线程睡眠0.6秒钟,防止用户在禁止时还不断刷新.3秒(需要清除5个记录)之后再刷新就可以了 
                        Thread.sleep(600); 
 
                        // 判断当前用户的刷新时间和当前的 系统时间间隔是否超过了闲置时间,如果超过则从缓存中清除记录(就不需要禁止刷新了) 
                        for (String key : map.keySet()) { 
                            CopyOnWriteArrayList<Long> list = map.get(key); 
                            for (Long date : list) { 
                                if (System.currentTimeMillis() - date > Cache.EXPIRE_TIME) { 
                                    System.out.println(list.remove(date)); 
                                } 
                            } 
                        } 
                    } catch (InterruptedException e) { 
                        e.printStackTrace(); 
                    } 
 
                } 
            } 
        } 
    } 
 

上面这段代码其实问题还是很多的,比如如果用户比较多的话,就会有很多的线程存在,线程过多服务器性能肯定会受影响.还有那个CopyOnWriteArrayList性能也不是很高,但是我试了很多的list只有CopyOnWriteArrayList可以实现上述功能,唉,CopyOnWriteArrayList的原理还不是很清楚,如果哪位同仁有高见欢迎拍砖.
 
其实实现这个功能最好的方法是用iptable防火墙来做,但是我没试过.希望有这个经验的可以分享一下.

这篇关于防止用户恶意刷新过滤器的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/990187

相关文章

ABAP怎么把传入的参数刷新到内表里面呢?

1.在执行相关的功能操作之前,优先执行这一段代码,把输入的数据更新入内表里面 DATA: lo_guid TYPE REF TO cl_gui_alv_grid.CALL FUNCTION 'GET_GLOBALS_FROM_SLVC_FULLSCR'IMPORTINGe_grid = lo_guid.CALL METHOD lo_guid->check_changed_data.CALL M

vue子路由回退后刷新页面方式

最近碰到一个小问题,页面中含有 <transition name="router-slid" mode="out-in"><router-view></router-view></transition> 作为子页面加载显示的地方。但是一般正常子路由通过 this.$router.go(-1) 返回到上一层原先的页面中。通过路由历史返回方式原本父页面想更新数据在created 跟mounted

警告,恶意域名疯狂外联,原因竟然是……

前言 &nbsp;&nbsp; 在某个风和日丽的下午,突然收到客户那边运维发过来的消息说我司的DTA设备在疯狂告警,说存在恶意域名外联,我急忙背上小背包前往客户现场,经过与客户协同排查,最终确定该事件为一起挖矿病毒引起的恶意域名外联事件。(因客户信息保密且为了保证文章逻辑完整性,部分截图为后期追加图) 事件分析 一看域名地址donate.v2.xmrig.com

Win10用户必看:最好用最稳定的版本在此,值得一试!

在Win10电脑操作中,用户可以根据的需要,下载安装不同的系统版本。现在,许多用户好奇Win10哪个版本最好用最稳定?接下来小编给大家推荐最好用最稳定的Win10版本,这些系统版本经过优化升级,相信会给大家带来最棒的操作体验感,且下载安装步骤非常简单。   推荐一:Windows10 22H2 X64 官方正式版   点击下载:https://www.xitongzhijia.net/wi

插入用户APC

每个_Kthread都有一个成员Alerted,默认为0,表示是否可以被APC唤醒。所以下面这段程序,即使插入了APC,但是t线程仍然不会执行。 让t线程执行APC函数的方法是使t线程变成可被唤醒状态,使用函数SleepEx(时间,是否可以唤醒线程),第二个参数为true,Alerted设置为1,即可被唤醒;在插入APC时,APC函数就会执行。 #include "stdafx.h"#inc

java NIO 缓存区之内核空间、用户空间和虚拟地址

IO是基于缓存区来做的,所谓的输入和输出就是从缓存区中移入和移出数据。以IO输入为例,首先是用户空间进程向内核请求某个磁盘空间数据,然后内核将磁盘数据读取到内核空间的buffer中,然后用户空间的进程再将内核空间buffer中的数据读取到自身的buffer中,然后进程就可以访问使用这些数据。     内核空间是指操作系统内核运行的空间,是为了保证操作系统内核的能够安全稳定地运行而为内核专

局部刷新ListView,实现点赞功能

今天看到一个需要实现一个点赞的功能。自己想没想明白,后来看了http://blog.csdn.net/nupt123456789/article/details/39432781 这篇博客,才有了思路。特意感谢 这是我要用的ListView的item。要给ListView设置单个刷新,实现点击事件。 1.布局  (不要问我为什么是绝对布局,,我开心) <?xml version

防止在 Qt 中触发信号

在 Qt 中工作时,有时我们需要暂时阻止某些信号的触发。以下是一个经典场景:我们有一个 QCheckBox 对象,当用户勾选或取消勾选时,需要调用一个函数,因此我们将这个函数连接到 stateChanged(int state) 信号。然而,在某些条件下,我们在代码中更改 QCheckBox 的状态,这会导致触发不需要的信号。那么如何在特定情况下防止信号触发呢? 使用 clicked 信号 如

金蝶盘点机金蝶PDA外购入库单校验防止收错货实现商品品种和数量校验

采购入库单校验 单据校验,是在电脑上已经存在这个单据,然后对商品实物跟单据进行核对,校验品种和数量。 传统的【采购入库单】校验方式是,供应商送货来,仓管员拿着纸质的【采购入库单】清点商品数量, 并一行行的记录商品数量,这个过程如果商品品种几十种,几百种,就很容核对错误,而且费时费力,搞得头晕眼花,工作强度比较大,对仓管员的责任心和细心程度要求比较高。 如果使用盘点机PDA进行【采购入库

React AntDesign Layout组件布局刷新页面错乱闪动

大家最近在使用React AntDesign Layout组件布局后刷新页面时,页面布局错乱闪动 经过组件属性的研究才发现,设置 hasSider 为 true 就能解决上面的问题,耽搁了半天的时间,接着踩坑接着加油!!! import { Layout, theme } from 'antd';import { Outlet } from "react-router-dom"impo