Ajax环境下表单防重复、外部提交实现方案记要
背景:
js lib: Ext 3.3.0,未使用 struts、Spring MVC;
所有的表单都由 Ext js 方法生成(即非传统 http form 形式, http 源代码中无 form 元素),后台 http request -> action 的处理机制是和 struts、Spring MVC 的实现相仿。
方案核心:
通过 token 机制来防止表单重复或外部提交(非常非常的寻常)。
方案实现:
如果用 struts 就简单了,加个<s:token/> 再配个 TokenInterceptor 就搞定了 (存在漏洞,详见底部)。
如果用 Spring MVC 就简单了,写个 TokenHandlerInterceptor extends HandlerInterceptorAdapter 再配置下也搞定了。
不用 struts、Spring MVC 其实也简单,参考 Spring MVC 在 http request -> action 的处理中加上拦截器机制,再参考 struts 实现 TokenInterceptor 就搞定了。
关于 token 值的提交方式:由于form非常规,无法往 form 里添加 token 元素,既然放不到 request body 里,那就放到 request header 里,放到 header 里其实相对来说更灵活些(另外似乎还能避免1个漏洞,详见底部)。
Ext request 加 header :
Ext.Ajax.defaultHeaders = { 'Req-Token': tokenValue };
注:header 的名称是不区分大小写的,根据实际测试情况,IE下通常会把 header 名称都变成小写,而 Firefox 和 Chrome 基本上不会改变,header 名称和我们代码里所写的名称是一致的。后台获取 header 值时需注意这个情况。
同样的,response 里也加个 header,将新的 token 值传给客户端。
不专门提供一个获取 token 值的 servlet 的原因:主要是怕该 servlet 压力过大。
另外,不能将 token值的提交和form提交分开,必须在同一个请求中同时提交,原因:分开提交无法防止外部提交等非法提交方式。
关于是否需要进行 token 校验:由于 TokenInterceptor 配上了,则默认会对所有 request 均校验,为了支持按需进行校验,自定义了@Token 注解,需要校验的action方法只要加上 @Token 即可(注解是个好东西)。
特别注意: