This is the ninth day of my participation in the First Challenge 2022. For details: First Challenge 2022.

In the last post I dealt briefly with oversold and limiting processing:

# SpringBoot Development Bank kills backend systems

The complete project code is synced to GitHub->github.com/yt-King/sec…

Next, the following interface should be hidden. Otherwise, if the interface is directly exposed, it will be finished if some hangers press F12 and get it directly. Therefore, the interface of panic buying should be protected.

Snap up the interface to hide (interface salt) specific practices:

  • Every time you click the seckill button, you will first obtain a seckill verification value from the server (determine whether the interface has reached the seckill time and other operations).
  • Redis uses the cache user ID and item ID as keys, and the validation Value is Value
  • When the user requests a split-kill item, the split-kill validation value is added to get a temporary order data
  • Verify the temporary order payment and write the order to the database

According to the requirements of the competition topic, the purchase will be successful only after the user completes the payment, so I split the original order interface into two methods, namely createTempOrder and createRealOrder. The first method is used to generate temporary orders and return them to the user (without writing into the database) when the user clicks on the order. Call the second method to write the order into the database after the user makes a successful payment (click the “confirm payment” button) to indicate that the purchase is successful. After splitting the ordering interface, it is necessary to ensure that the user goes through all the interfaces according to the process when buying, and from obtaining verification -> obtaining temporary order -> placing a real order, Therefore, when obtaining the verification value, the program will salt the user ID and commodity ID (to prevent the encryption is too simple to be directly guessed), carry out MD5 encryption twice and store it in Redis, and return the value after the first encryption.

Above, I write access to verify the value of the interface, verify the values get started after the second step is to obtain a temporary order, at the time of this step will be introduced to verify the value (the encrypted value) for the first time in the first operation with encryption (for verification value) of the second operation, in order to gain the real validation value (that is, the value of the stored in the redis), This value is then returned as the order number when the order is generated. (One advantage of using the true validation value as the order number is that this value corresponds to one user + one item. In general, the second kill item is limited to one purchase. That is to say, according to the uniqueness of the order number (the database sets this field not to be repeated), each user can be guaranteed to purchase the same item.)

Reasons for encrypting twice: If only for an encrypted in the first step after return redis is stored in the final validation values, if someone take interface to can directly and then skip the second step, the first step to verify values for the third step direct payment orders can be authenticated, but if is twice the MD5 encryption must be through the three interfaces in turn.

The current stage of the buying process is roughly as follows:

Interfaces hide later also need to some important restricting access number, such as the above three interfaces are related to order, to prevent malicious attacks result in collapse, so need to limit access to the interface number, often can make access to a user id number, also can make access to the IP number statistics, I used statistical IP here and saved it in Redis with an expiration time of 10 minutes.

/** * * @param request * @return int * @author yt * @date 2022/1/17 18:40 */ public int addIpCount(HttpServletRequest request) throws Exception { String ipAddress = IpUtil.getIpAddr(request); String limitKey = CacheKey.LIMIT_KEY.getKey() + "_" + ipAddress; String limitNum = (String) ipCountRedisTemplate.opsForValue().get(limitKey); int limit = -1; if (limitNum == null) { ipCountRedisTemplate.opsForValue().set(limitKey, "0", 600, TimeUnit.SECONDS); } else { limit = Integer.parseInt(limitNum) + 1; ipCountRedisTemplate.opsForValue().set(limitKey, String.valueOf(limit), 600, TimeUnit.SECONDS); } return limit; } /** * * * @param request * @return void * @author yt * @date 2022/1/17 18:40 */ public void CheckIpIsBanned(HttpServletRequest request) { String ipAddress = IpUtil.getIpAddr(request); String limitKey = CacheKey.LIMIT_KEY.getKey() + "_" + ipAddress; String limitNum = (String) ipCountRedisTemplate.opsForValue().get(limitKey); if(null == limitNum) return; If (integer.parseint (limitNum) >= ALLOW_COUNT) throw new RuntimeException(" No frequent access, please try again in 10 minutes "); }Copy the code