[Mall] spike projects - using a mathematical CAPTCHA to limit the current

Spike adapter addresses hidden to prevent a malicious user interfaces through frequent calls to the requested operation, but were unable to prevent the robot, brush vote frequently malicious software can still click the button to request a brush spike address of the interface

High concurrency scenarios, in that moment just beginning to spike, the number of concurrent usher in the biggest, reducing the amount of concurrency same point of time, the diversion is also a reduction in the amount of concurrent database and measures the system pressure (to make the 1s 100,000 requests for the 10s in the transition to 100,000 requests)

How this blog recorded using a mathematical CAPTCHA to limit the current, limiting clipping other operations can refer to:

[Project] spike mall - traffic clipping should be how do

Realization of ideas:

Before clicking spike, you must first enter the verification code to the user's request dispersion. Specific implementation is similar to the rear end generated codes 1 + 2-3, the results calculated to deposit Redis, then verification picture sent to the client after the client requests a verification code before the address value spike requesting authentication, the rear end to the cache and verifying the same value whether the value entered by the user, verify that the generated address to the distal spike will dynamically by

step:

  • Added in the commodity detail page verification picture tab, specify id, then add the verification code input box input components, and initialize their properties is not visible, because the beginning of this code and input box is not visible (only spike will start visible), you can click to refresh the picture, so the definition refreshVCode function to refresh picture

refreshVCode function code is as follows:

function refreshVerifyCode() {
    $("#verifyCodeImg").attr("src", "/miaosha/verifyCode?goodsId=" + $("#goodsId").val() + "&timestamp=" + new Date().getTime());
}

Note: The definition of oncilck operating in the picture, when clicked, will request a picture verification code interfaces, but the browser will cache, plus timestamp so this parameter, the browser will really send a request, or go inside to get the cache 

  • Analyzing spike branch being added inside the countdown display method of codes and code logic verification code input box, spike start time, provided it is visible and designated attr () method of the src dynamically assigned, sends a request to the back end, dynamically generated images ; Note that after the end of the spike, and the need to set it to invisible

  • The request for the parameter passing goodsId, then generating a mathematical formula based on the user id and codes goodsId, and then codes this image with a response output stream to the front end

Image generating codes rear interface code:

@RequestMapping(value = "/verifyCode", method = RequestMethod.GET)
@ResponseBody
public Result<String> getMiaoshaVerifyCod(HttpServletResponse response,MiaoshaUser user,
                                          @RequestParam("goodsId") long goodsId) {
    if (user == null) {
        return Result.error(CodeMsg.SESSION_ERROR);
    }
    try {
        BufferedImage image = miaoshaService.createVerifyCode(user, goodsId);
        OutputStream out = response.getOutputStream();
        ImageIO.write(image, "JPEG", out);
        out.flush();
        out.close();
        return null;
    } catch (Exception e) {
        e.printStackTrace();
        return Result.error(CodeMsg.MIAOSHA_FAIL);
    }
}

图片是利用BufferedImage类生成的,指定高度与宽度,利用Graphics做画笔,填充颜色,画出边界线等操作,然后利用drawString方法将验证码随机拼接成字符串写在生成的图片上,还要把计算出字符串的值存在redis里面

createMiaoshaVertifyCode方法代码:

/**
 * 生成验证码
 */
public BufferedImage createVerifyCode(MiaoshaUser user, long goodsId) {
    if (user == null || goodsId <= 0) {
        return null;
    }
    int width = 80;
    int height = 32;
    //create the image
    BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
    Graphics g = image.getGraphics();
    //set the background color
    g.setColor(new Color(0xDCDCDC));
    g.fillRect(0, 0, width, height);
    //draw the border
    g.setColor(Color.black);
    g.drawRect(0, 0, width - 1, height - 1);
    //create a random instance to generate the codes
    Random rdm = new Random();
    //make some confusion
    for (int i = 0; i < 50; i++) {
        int x = rdm.nextInt(width);
        int y = rdm.nextInt(height);
        g.drawOval(x, y, 0, 0);
    }
    //generate a random code
    String verifyCode = generateVerifyCode(rdm);
    g.setColor(new Color(0, 100, 0));
    g.setFont(new Font("Candara", Font.BOLD, 24));
    g.drawString(verifyCode, 8, 24);
    g.dispose();
    //把验证码存到redis中
    int rnd = calc(verifyCode);
    redisService.set(MiaoshaKey.getMiaoshaVerifyCode, user.getId() + "," + goodsId, rnd);
    //输出图片
    return image;
}

对于数学公式的生成,是使用generateVerifyCode方法实现的,生成3个0到9之间的随机数,然后在生成一个字符数组,用于存放 + - * (加减乘)三个数学运算符,随机选中两个字符,然后将其进行拼接成一个字符串,数+运算符+数+运算符+数,返回这个字符串,generateVerifyCode方法代码如下:

private static char[] ops = new char[]{'+', '-', '*'};

/**
 * 生成加减乘的算式
 * + - *
 */
private String generateVerifyCode(Random rdm) {
    int num1 = rdm.nextInt(10);
    int num2 = rdm.nextInt(10);
    int num3 = rdm.nextInt(10);
    char op1 = ops[rdm.nextInt(3)];
    char op2 = ops[rdm.nextInt(3)];
    String exp = "" + num1 + op1 + num2 + op2 + num3;
    return exp;
}
  • 利用scriptEngine类,调用JavaScript的eval() 方法,计算这个字符串公式的值,并将这个值保存到redis里面去(用户下次发送请求的时候,直接去缓存里面取出并验证即可);注意eval()方法计算得到的是double类型的值,但我们需要的是int类型的值,所以需要强转

calc方法代码如下:

/**
 * 将算式进行计算
 */
private static int calc(String exp) {
    try {
        ScriptEngineManager manager = new ScriptEngineManager();
        ScriptEngine engine = manager.getEngineByName("JavaScript");
        return (Integer) engine.eval(exp);
    } catch (Exception e) {
        e.printStackTrace();
        return 0;
    }
}
  • 前端得到这个验证码图片显示该验证码,然后用户需要输入验证码将这个验证码作为参数,与获取秒杀地址请求一起传输给后端(校验的操作在获取秒杀地址之前),后端接收到参数后进行验证码比对,从缓存中取出该验证码进行校验;如果不通过,不生成秒杀接口地址,直接返回验证码错误信息

后端验证逻辑:

checkVerifyCode方法代码:

/**
 * 校验数字公式的验证码结果
 * @param user
 * @param goodsId
 * @param verifyCode
 * @return
 */
public boolean checkVerifyCode(MiaoshaUser user, long goodsId, int verifyCode) {
    if (user == null || goodsId <= 0) {
        return false;
    }
    Integer codeOld = redisService.get(MiaoshaKey.getMiaoshaVerifyCode, user.getId() + "," + goodsId, Integer.class);
    if (codeOld == null || codeOld - verifyCode != 0) {
        return false;
    }
    //删除缓存里的数据
    redisService.delete(MiaoshaKey.getMiaoshaVerifyCode, user.getId() + "," + goodsId);
    return true;
}
发布了133 篇原创文章 · 获赞 94 · 访问量 3万+

Guess you like

Origin blog.csdn.net/weixin_42687829/article/details/104515151