AOP spring boot by preventing repeat request API

Realization of ideas

Based on Spring Boot 2.x

Custom annotation, which is used to mark the API is the need to monitor whether the repeat request

Spring AOP to be cut by the Controller layer, monitoring

Inspection repeat requests Key: Token + ServletPath + SHA1RequestParas

  1. Token: When a user logs generated Token
  2. ServletPath: Path request
  3. SHA1RequestParas: request parameters used encryption algorithm SHA-1 hash

Using the above three parameters spliced ​​Key as to judge whether a repeat request

Use Redis storage Key, and characteristics of redis, key can be set to be automatically deleted within the specified time. Here the specified time, can not be repeated api is submitted within the prescribed time.

 

Custom Annotations ( Annotation acting on the Controller API layer )

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface NoRepeatSubmission {
 
}

  

Logic section

@ slf4j
@Aspect
@Component
public class NoRepeatSubmissionAspect {
 
    @Autowired
    RedisTemplate<String, String> redisTemplate;
 
    /**
     * Around advice
     * @Param Pjp
     * @param ars
     * @return
     */
    @Around("execution(public * com.example.apirepeatrequest.controller..*.*(..)) && @annotation(ars)")
    public Object doAround(ProceedingJoinPoint pjp, NoRepeatSubmission ars) {
        ValueOperations<String, String> opsForValue = redisTemplate.opsForValue();
        try {
            if (ars == null) {
                return pjp.proceed();
            }
 
            HttpServletRequest request = ((ServletRequestAttributes) Objects.requireNonNull(RequestContextHolder.getRequestAttributes())).getRequest();
 
            String token = request.getHeader("Token");
            if (!checkToken(token)) {
                return Result.failure("Token无效");
            }
            String servletPath = request.getServletPath();
            String jsonString = this.getRequestParasJSONString(pjp);
            String sha1 = this.generateSHA1(jsonString);
 
            // key = token + servlet path
            String key = token + "-" + servletPath + "-" + sha1;
 
            log.info("\n{\n\tServlet Path: {}\n\tToken: {}\n\tJson String: {}\n\tSHA-1: {}\n\tResult Key: {} \n}", servletPath, token, jsonString, sha1, key);
 
            // if the key Redis, url considered repeat request 
            IF (opsForValue.get (Key) == null ) {
                Object o = pjp.proceed();
                opsForValue.set(key, String.valueOf(0), 3, TimeUnit.SECONDS);
                return o;
            } The else {
                 return Result.failure ( "Do not repeat request" );
            }
        } catch (Throwable e) {
            e.printStackTrace ();
            return Result.failure ( "Unknown abnormal repeat request verification" );
        }
    }
 
    /**
     * Get the request parameters
     * @Param Pjp
     * @return
     */
    private String getRequestParasJSONString(ProceedingJoinPoint pjp) {
        String[] parameterNames = ((MethodSignature) pjp.getSignature()).getParameterNames();
        ConcurrentHashMap<String, String> args = null;
 
        if (Objects.nonNull(parameterNames)) {
            args = new ConcurrentHashMap<>(parameterNames.length);
            for (int i = 0; i < parameterNames.length; i++) {
                String value = pjp.getArgs()[i] != null ? pjp.getArgs()[i].toString() : "null";
                args.put(parameterNames[i], value);
            }
        }
        return JacksonSerializer.toJSONString(args);
    }
}

 

The main logic of the code section, the request is to obtain the relevant information, and then spliced ​​into a Key; Redis determines whether there is, it does not exist and is added after a predetermined time is set automatically removed, is the presence of repeat request.

 

Guess you like

Origin www.cnblogs.com/21-Gram/p/11971340.html