论坛首页 Java企业应用论坛

如何防止用户恶意的F5刷新操作的问题?

浏览 20071 次
精华帖 (0) :: 良好帖 (0) :: 新手帖 (0) :: 隐藏帖 (0)
作者 正文
   发表时间:2007-02-25  
背景:
  问题是这样的,系统持久层采用ibatis架构,系统有几个比较复杂的报表,耗费时间稍微长,不过在3秒以内.
   但是在报表页面按 F5 10秒钟则会出现statement timeout 的异常,因此有了如何防止用户恶意刷新的想法.

初步想法
   在内存中维护一个类似集合的东西,记录url,userid和访问时间,该集合的数据量维护在一个合理的范围,采用先进先出原则,根据访问时间、url和userid判断用户访问某个url的频繁程度,利用Interceptor从而在用户访问service之前拒绝用户访问!

   谁能提供一个更好的想法?    


   发表时间:2007-02-25  
1放一个cache放到这个方法中有没有用?
2在application中放一个存userid的map
当一个service运行时
同一个id只能跳过逻辑代码

Map userMap = applictaion.getAtrriblet("userMap");
if userMap==null{
appliction.setAtrriblet("userMap",new HashTable());
}else if userMap.get(userid)==null{
userMap.add(userid,new Integer(9);
}else if userMap.get(userid).equles(new Integer(9)){
return getforward("islock");
}else {
//return getforword("");//内存中有可以试试用缓存数据
}
//TODO 报表

//ok
userMap.set(userid,new Integer(0));

return getforward("ok");


0 请登录后投票
   发表时间:2007-02-25  
抛出异常的爱 写道
1放一个cache放到这个方法中有没有用?
2在application中放一个存userid的map
当一个service运行时
同一个id只能跳过逻辑代码

Map userMap = applictaion.getAtrriblet("userMap");
if userMap==null{
appliction.setAtrriblet("userMap",new HashTable());
}else if userMap.get(userid)==null{
userMap.add(userid,new Integer(9);
}else if userMap.get(userid).equles(new Integer(9)){
return getforward("islock");
}else {
//return getforword("");//内存中有可以试试用缓存数据
}
//TODO 报表

//ok
userMap.set(userid,new Integer(0));

return getforward("ok");




1放一个cache放到这个方法中有没有用?
把报表数据cache一下?不大好,因为毕竟报表数据要时实的。

对于第二种,不是很理解,应该有个时间的概念在里面吧。

下面是我的简单的代码实现,我用Spring MVC因此采用Interceptor拦截。

Interceptor 代码

public class SignonInterceptor extends HandlerInterceptorAdapter {
	Map _CACHE = new HashMap();

	public boolean preHandle(HttpServletRequest request,
			HttpServletResponse response, Object handler) throws Exception {
		Integer userid = new Integer(1); //真实的Userid
		String url = request.getRequestURL().toString();
		UserVisitRecord uvr = (UserVisitRecord) _CACHE.get(userid);
		if (uvr == null) {
			_CACHE.put(userid, new UserVisitRecord(url));
		} else {
			if (!uvr.isValidateVisite(url)) {
				//lock redirect to error page
			}
		}
		return true;
	}
}


UserVisitRecord 代码

public class UserVisitRecord {
	private static final int _interval = 1000;//1秒钟
	private String url;
	private long time1 = 0;// early
	private long time2 = 0;// late

	public UserVisitRecord(String url) {
		this.url = url;
	}

	private void init(String url) {
		this.url = url;
		this.time1 = 0;
		this.time2 = 0;
	}

	private void sequence(long currenttime) {
		time2 = time1;
		time1 = currenttime;
	}

	private boolean isValidateInterval(long currenttime) {
		if (currenttime - time2 > _interval)
			return true;
		return false;
	}

	public boolean isValidateVisite(String currenturl) {
		long currenttime = new Date().getTime();
		if (!currenturl.equals(url)) {
			init(currenturl);
			return true;
		}
		if (!isValidateInterval(currenttime)) {
			init(currenturl);
			return false;
		}
		sequence(currenttime);
		return true;
	}
}


原理是如果同一个用户在一秒钟内连续三次访问同一个URL超过3次则认为是恶意的。
不知道这样是否有问题?

0 请登录后投票
   发表时间:2007-02-25  
是要在每个报表前加
标置
结束时把标置变成0

可以重构成一个盒子用方法调用
不要次次都写
0 请登录后投票
   发表时间:2007-02-25  
恩,这种方法合理,也比较科学,对于同一个用户来说相当于使用synchronized了!

目前打算对几个复杂的耗时长的报表用楼上的方法,然后加我的拦截方法对所有URL拦截.

另外发现一个新的疑惑,为什么request.getRequestURL()的返回值被设计成StringBuffer而不是String?

这个问题无关紧要,纯粹是专牛角。
0 请登录后投票
   发表时间:2007-02-25  
说到synchronized突然产生了一个想法,controller的代码写成如下这样大家看如何?

public ModuleAndView handleReport(....)
{
    synchronized(session.getAttribute("user"))
    {
        //产生报表
    }
}
0 请登录后投票
   发表时间:2007-02-25  
jamesby 写道

1放一个cache放到这个方法中有没有用?
把报表数据cache一下?不大好,因为毕竟报表数据要时实的。

为什么不好? 数据更新了就invalidate cache.  除非你的数据是每时每刻都在更新, 那么在user session里面放个refresh buffer delay, 比如5秒内的重复请求一律无视
0 请登录后投票
   发表时间:2007-02-26  
lordhong 写道
jamesby 写道

1放一个cache放到这个方法中有没有用?
把报表数据cache一下?不大好,因为毕竟报表数据要时实的。

为什么不好? 数据更新了就invalidate cache.  除非你的数据是每时每刻都在更新, 那么在user session里面放个refresh buffer delay, 比如5秒内的重复请求一律无视
我一个报表涉及到10几个表左右,这样的cache似乎不妥.invalidate率太高.

抛出异常的爱的方法很可行.

0 请登录后投票
   发表时间:2007-02-26  
如果采用Interceptor拦截,pre设置标志,post释放标志,不更合理,而且是可插拔式的!
0 请登录后投票
   发表时间:2007-02-26  
jamesby 写道
如果采用Interceptor拦截,pre设置标志,post释放标志,不更合理,而且是可插拔式的!

你用的方式比我的偶合小
不过我的方法是我用过了的。。。(一年之前系统中没有spring,我也没有spring的思考方式。)

放cache主要是为了再刷时不用再去作大表查寻了。。。
(存在内存中的不止一组查寻结果集。。。。)

BufferString是String的父类当有变化时时减少资源浪费
(如果是String那么url+"/xxx.do?"+"zzz=yyy"+"&aaa=bbb"+"&cccc=dddd")
0 请登录后投票
论坛首页 Java企业应用版

跳转论坛:
Global site tag (gtag.js) - Google Analytics