SpringBoot의 사용자 정의 메모 구현 컨트롤러 액세스 횟수 제한 사례

5405 단어 spring컨트롤러
오늘은 SpringBoot에서 컨트롤러의 접근 횟수를 제한하는 주해를 사용자 정의하는 방법을 소개합니다.
웹에서 가장 자주 발생하는 것은 악성 URL을 이용하여 폭발 서버에 접근하는 것과 같은 공격입니다. 오늘은 사용자 정의 주석을 이용하여 이러한 공격을 어떻게 방어하는지 소개해 드리겠습니다.
사실 이런 문제의 일반적인 해결 사고방식은 컨트롤러에 사용자 정의 주석을 넣어 방문 횟수를 제한하는 기능을 실현하는 것이다.
구체적인 실현 과정은 다음과 같다.
1단계: 먼저 주석 클래스를 정의하고 코드 사례를 보십시오.

package example.controller.limit; 
import org.springframework.core.Ordered; 
import org.springframework.core.annotation.Order; 
import java.lang.annotation.*; 
@Retention(RetentionPolicy.RUNTIME) 
@Target(ElementType.METHOD) 
@Documented 
//  
@Order(Ordered.HIGHEST_PRECEDENCE) 
public @interface RequestLimit { 
  /** 
   * 
   *  , MAX_VALUE 
   */ 
  int count() default Integer.MAX_VALUE; 
 
  /** 
   * 
   *  , ,  
   */ 
  long time() default 60000; 
} 
단계 2: URL 공격을 처리할 때 발생하는 이상 문제를 처리하기 위해 이상 클래스를 정의합니다. 다음은 코드 사례를 보십시오.

package example.controller.exception; 
public class RequestLimitException extends Exception { 
  private static final long serialVersionUID = 1364225358754654702L; 
 
  public RequestLimitException() { 
    super("HTTP "); 
  } 
 
  public RequestLimitException(String message) { 
    super(message); 
  } 
 
} 
단계 3: 주해의 구체적인 실현 유형을 정의하고 다음은 코드 사례를 본다.

package example.controller.limit; 
import example.controller.exception.RequestLimitException; 
import org.aspectj.lang.JoinPoint; 
import org.aspectj.lang.annotation.Aspect; 
import org.aspectj.lang.annotation.Before; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.stereotype.Component; 
import javax.servlet.http.HttpServletRequest; 
import java.util.HashMap; 
import java.util.Map; 
import java.util.Timer; 
import java.util.TimerTask; 
import java.util.concurrent.TimeUnit; 
 
@Aspect 
@Component 
public class RequestLimitContract { 
  private static final Logger logger = LoggerFactory.getLogger("RequestLimitLogger"); 
  private Map<String, Integer> redisTemplate=new HashMap<String,Integer>(); 
  @Before("within(@org.springframework.stereotype.Controller *) && @annotation(limit)") 
  public void requestLimit(final JoinPoint joinPoint, RequestLimit limit) throws RequestLimitException { 
    try { 
      Object[] args = joinPoint.getArgs(); 
      HttpServletRequest request = null; 
      for (int i = 0; i < args.length; i++) { 
        if (args[i] instanceof HttpServletRequest) { 
          request = (HttpServletRequest) args[i]; 
          break; 
        } 
      } 
      if (request == null) { 
        throw new RequestLimitException(" HttpServletRequest "); 
      } 
      String ip = request.getLocalAddr(); 
      String url = request.getRequestURL().toString(); 
      String key = "req_limit_".concat(url).concat(ip); 
      if(redisTemplate.get(key)==null || redisTemplate.get(key)==0){ 
        redisTemplate.put(key,1); 
      }else{ 
        redisTemplate.put(key,redisTemplate.get(key)+1); 
      } 
      int count = redisTemplate.get(key); 
      if (count > 0) { 
        Timer timer= new Timer(); 
        TimerTask task = new TimerTask(){  // 。 
          @Override 
          public void run() { 
            redisTemplate.remove(key); 
          } 
        }; 
        timer.schedule(task, limit.time()); 
        // 。task :  。10000 :  , 。 
      } 
      if (count > limit.count()) { 
        //logger.info(" IP[" + ip + "] [" + url + "] [" + limit.count() + "]"); 
        throw new RequestLimitException(); 
      } 
    } catch (RequestLimitException e) { 
      throw e; 
    } catch (Exception e) { 
      logger.error(" : ", e); 
    } 
  } 
} 
4단계: 제어 클래스를 실현하고 주석 기능을 추가합니다.코드 사례를 살펴보겠습니다.

package example.controller; 
import example.controller.limit.RequestLimit; 
import org.springframework.stereotype.Controller; 
import org.springframework.ui.ModelMap; 
import org.springframework.web.bind.annotation.RequestMapping; 
import org.springframework.web.bind.annotation.ResponseBody; 
import javax.servlet.http.HttpServletRequest; 
@Controller 
public class URLController { 
  @RequestLimit(count=10,time=5000) 
  @RequestMapping("/urltest") 
  @ResponseBody 
  public String test(HttpServletRequest request, ModelMap modelMap) { 
    return "aaa"; 
  } 
} 
그 중에서count는 규정된 시간 내의 방문 횟수를 가리키고time는 규정된 시간을 가리키며 단위는 밀리초이다.
이렇게 하면 컨트롤러라는 차원에서 URL을 차단할 수 있다.그러나 여기에 문제가 하나 있다. 모든 URL 페이지에서 이런 차단을 하려면 이런 방법이 현저히 부족하다는 것이다.모든 컨트롤러에 URL 차단 주석을 추가할 수 없기 때문에 이런 방법은 특정한 URL 차단 위에서만 사용하기에 적합하다.
그러면 필터 레벨 위의 URL 접근 차단을 어떻게 실현합니까?여기서 먼저 여러분께 스위치를 하나 드리겠습니다. 다음 절에서 필터를 이용하여 URL 접근 차단을 어떻게 하는지, 그리고 JPA를 이용하여 IP 블랙리스트의 기능을 실현하는지, IP 블랙리스트를 가입하면 어떠한 URL도 접근할 수 없습니다.
이상은 본문의 전체 내용입니다. 여러분의 학습에 도움이 되고 저희를 많이 응원해 주십시오.

좋은 웹페이지 즐겨찾기