Session令牌防止表单重复提交

1.针对的表单重复提交一般场景

  1. 客户端浏览器F5刷新
  2. 重复点击提交按钮

2.效果

总体效果就是,第一次输入内容,可以正常提交,之后,F5以及重复点击提交按钮都是无效的.但是,在输入新内容之后,也可以正常提交.


3.Session令牌

session令牌(token)

只是一个一次性的通行证性质的字符串.
甚至可以使用一个字符去表示这个令牌,但是令牌在短时间内不允许出现重复.

生成

可以使用 系统时间+随机数—–>成摘—–>字符串(最终结果) 的形式


4.流程

流程已很明白,可以参考7帮助理解
这里写图片描述


5.token的生成

使用了加密工具,任何文本获取的摘要长度都是一样的

package utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;
import java.util.Random;

public class TokenUtils {

    /**
     *@Author: zsb
     *@Description: 获取一个令牌
     *@params:
     *@Date: 2018/6/13
    */
    public static String getToken(){
        //获得一个未加密的文本
        String tokenStr = System.currentTimeMillis() + new Random().nextInt(999999) + "";
        String result = null;
        try {
            //使用md5加密
            MessageDigest messageDigest = MessageDigest.getInstance("md5");
            //更新摘要
            messageDigest.update(tokenStr.getBytes());
            //计算摘要
            byte token[] = messageDigest.digest();
            //将字节数据转换为字符串,base64就是一个字节转字符串的工具
            result = Base64.getEncoder().encodeToString(token);
        } catch (NoSuchAlgorithmException e) {
            e.printStackTrace();
        }
        return result;
    }


}

6.Servlet中service方法代码

//数据获取请求数据---------------------------------------------------------------------------
//
//token数据及表单提交处理---------------------------------------------------------------------
        //如果session里没有token,则生成一个,通常是第一次访问时需要,
        //此后session内都会保存着一个token,每次表单成功提交,session里的token也会更新
        String sessionToken = (String)req.getSession().getAttribute("token");

        if(sessionToken == null){

            String token = TokenUtils.getToken();  //获得一个token
            //将令牌传入session,jsp页面中通过el表达式获取session域中的token
            req.getSession().setAttribute("token",token);

        } else {
            //获取表单提交的token,注意,在F5刷新时,也只会获取前一次成功提交的token,因此不怕F5
            String  jspToken= req.getParameter("token");  
            System.out.println("获得的隐藏域中token值: " + jspToken);
            System.out.println("Session域中的token值: " + sessionToken);

            if(jspToken != null){  //只需验证jsp获得的token不为null即可
                if(sessionToken.equals(sessionToken)){     //若两个token相同,则令牌验证通过
                    System.out.println("令牌验证通过");
                    //就算令牌通过,空内容的提交也是不允许的,这是第二道防表单重复提交屏障
                    if(StringUtils.strNotEmptyNotNull(name) && StringUtils.strNotEmptyNotNull(content)){
                        //数据库操作
                        System.out.println("数据库操作中");
                        //更新令牌,流程图里写删除,这里因为可以覆盖所以就不需要删除了,直接重新生成覆盖旧的token值
                        String token = TokenUtils.getToken(); //获得一个令牌
                        req.getSession().setAttribute("token",token);
                    }
                } else{
                    System.out.println("当前jspToken: "+ jspToken + 
                                       "当前SessionToken: " + sessionToken +
                                       "请不要重复提交表单");
                }
            }

        }

7.过程描述以及实现原理讲述

1.当我们第一次进入这个含有表单的页面的时候,会自动获取一个token,并将token存储在session中,因为一般还有其他页面数据获取操作,所以需要使用转发.页面转发完成后,jsp页面的隐藏域中会自动获取这个token,这时候我们向表单里填入数据,然后提交,可以正常提交.提交完成后,session里的token被更新,最后再次转发到了这个jsp页面
2.我们点击F5,对页面进行刷新,发现不会重复提交,这是因为,我们一直使用的是转发,request里jsp隐藏域的token其实还是上一次的数据,而session中的token在上一次成功提交后就已经被更新了,并且每次验证的时候,获取的都是session里最新的token,因此二者不会相等,令牌验证失败,也就不会进行提交操作.这一点需要注意
3.当我们再点提交按钮时,由于这是一次新的请求,因此会把最新的jsp会把最新的session里的token带入请求信息里,同样,后台servlet里也是最新的token,因此,这个时候可以通过令牌验证,但是,由于每次提交后,表单内容被清空,但是我们不允许空内容的表单,因此这个时候表单提交不会生效
4.当我们输入新内容后,再点击提交,同样可以提交.令牌验证与3相同,而且有了内容,因此可以进行提交操作,提交后,session的token被更新,同样,jsp的token也会被更新,但是,我们获取的是request里的表单的token,这个因为是转发的关系,request里的token是上一次的内容.

关键点:F5刷新的时候,request里的token是上一次成功提交的token

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 3
    评论
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值