关于公司一个防止重复下载的问题

情况是这样的,现在公司的网站有一个更新产品的功能,就是用户输入激活码,然后我们会判断数据库中的记录以及他的下载权限,有的话则给处对应的下载链接,用户点链接(现在给出的是实际地址)就可以去下载一个更新文件,然后是对更新是有控制的,分为1次性下载,一段时间内可任意下载,以及永久任意下载。但是现在问题在于拥有1次性和一段时间下载权限的用户,他们可以记录下载地址,那么以后不用输入激活码不用经过判断就可以直接下载更新,就会破坏更新的规则,今天突然想到这个,所以对下载做了如下处理:

生成下载链接的时候,随机生成一个字符串,设置到session中(叫做token)同时往页面上传递同一个值(用tok表示),并将真实下载地址加密,下载的链接改成download.jsp?加密地址&tok

 

EncryptUtil eu = new EncryptUtil();//使用默认密钥加密
String enurl = eu.encrypt(forDown.getLink());//加密URL
String token = StringUtil.getInstance().getString(7);//生成令牌
request.getSession().setAttribute("tok",token);//设置令牌
sb.append("right|"+forDown.getName()+"|"+enurl+"|"+token);
//这里是用ajax返回到页面上,页面上截取字符串生成链接
response.getWriter().print(sb.toString());

生成URL

var info = data.split('|');
$('#showlink').empty().append('<span>'+info[1]+'</span><a href="download.jsp?url='+info[2]+'&t='+info[3]+'">点击这里下载更新包</a>');

在download.jsp上判断session中的token和request来的tok是否相同,相同则将加密地址解密还原,并随机生成另一个字符串,设置到session中,覆盖token,然后服务器跳转,跳往真实下载地址。这样的话用户复制地址不论粘贴到哪,只要下载过后就都会因为token和tok对不上号而下载不了了。

String url = request.getParameter("url");
EncryptUtil eu = new EncryptUtil();//加密解密类
String rUrl = eu.decrypt(url);//解密成下载的真实url
String tok = request.getParameter("t");//获取页面上的令牌
String token = (String)session.getAttribute("tok");//获取session中的令牌
String newToken = StringUtil.getInstance().getString(7);//生成令牌
if(tok.equals(token)){
        session.setAttribute("tok",newToken);//设置令牌
        request.getRequestDispatcher(rUrl).forward(request,response);
}else{
        response.sendRedirect("index.jsp");
}

 

但是我不太确定这样做是不是很安全,首先习惯用工具下载文件的用户来说这个链接是没法用工具下了,而且对于一次下载的用户来说,如果半路取消则再也不能下载了(因为生成链接后下载次数就清空了),所以目前的问题总结如下:

1、我对限制下载的处理是否安全?

2、可不可以提供一些其他的建议或者思路在这样防止重复下载的场合?

3、对于一次性下载的用户,是否可以用输出流提供下载,判断输出流完成后再清空次数?(有别的思路也请多多指教啦)

突然发现一个悲催的问题,昨天是在本地测的,实际上文件放在下载服务器上……那给流下载岂不是我们的主机要去读下载服务器上的文件再提供给客户下载?会不会变慢?

会不会变慢,要看网络了。
不需要你去读下载服务器。

你即然可以给出下载服务器的链接,那下载服务器也应该存在一个web服务。
也可以用流的试式请求,但现在不知道你们能不能改下载服务器上的实现。
如果不能的话,现在说的都白费了。

1、可以在控件用户数据下载的那张表里加一个字段,可以跟据字段来判断用户可以下载次数,在加一个字段判断用户是否已经下载过

2、资源是放在你们的服务器上的,下载也是一个流,并且文件也有大小的,你可以判断一下用户下的流和文件大小进行对比,如果相等,也是就说用户正常完成了下载,对于一次性下载的用户来说,下次就不可能在下载了

3、对于你上面的代码没有看出什么太明显的漏洞出来,你可以多找几个测试场景测试一下,多测测总是好的

计次的用户要在代码输出流中做判断,也就是流完成的地方,判断是否下载完成,完成的话做记录。
计时的用户这个当然好办了,生成一个可逆的字符串,里面记录允许开始下载的时间。当用户要下载的时候,反向简析成开始时间,和当前时间做判断即可。
算法要简单啊,要不很耗费CPU的,祝你好运了。

你的代码暂时没有想出问题

我的建议是不要给出实际的链接,改用流的方式下载。

他有请求,到你后做判断,可不可以让他下载。这样来做。

无论是这个做法,还是你说出问题的做法,

都 有一个问题不可避免,就是网络中断

即请求通过了,你是不是要给他计数一次,然后让它下载。
如果他出现异外,没有下载完成,估计是再请求也没有用了。

处理好这个问题,再用我说的那个办法,我觉得能好一点。

to:khan
问一下,能判断流是否完成吗?用什么方法?

我遇到的情况是这样的,下载时,将流写入response,

这里,客户端就会了下载对话框,

它是点取消,还是下载超时,还是说拔网线,下载中断。
这些都是测试时用的手断,

在服务端能得到这样的状态吗?如果能得到,那就太好了。

2G的试过,4G的没试过

文件大的话可以用文件分割的方法下载啊

同意LS的意见

下载服务器上的实现。

我的理解是这样,

访问的是http://urla/xxxxxxxxxx
验证通过后,
会在页面上出现。
down

这样的下载链接,即然是URLB,那么就是向B服务器发送下载请求,而不是在当前的WEB服务器上下载。

不知道我理解的对不对。

能对你有用就好。
:D
我也很高兴