SpringBoot 는 인터페이스 데이터 의 복호화 기능 을 실현 합 니 다.

1.암호 화 방안 소개
인터페이스 에 대한 암호 화 복호화 작업 은 주로 다음 과 같은 두 가지 방식 이 있 습 니 다.
사용자 정의 메시지 변환기
장점:인터페이스 만 실현 하고 설정 이 간단 합 니 다.
약점:같은 유형의 MediaType 만 복호화 할 수 있 고 유연성 이 없습니다.
spring 에서 제공 하 는 인터페이스 RequestBody Advice 와 Response Body Advice 를 사용 합 니 다.
장점:요청 한 Referrer,Header 또는 url 에 따라 판단 하고 특정한 수요 에 따라 암호 화 복호화 할 수 있 습 니 다.
예 를 들 어 한 프로젝트 가 업 그 레이 드 될 때 새로운 개발 기능 의 인 터 페 이 스 는 복호화 해 야 한다.오래된 기능 모듈 이 가기 전에 논리 가 암호 화 되 지 않 으 면 위의 두 번 째 방식 만 선택 할 수 있다.다음은 두 번 째 방식 으로 암호 화,복호화 하 는 과정 을 소개 한다.
2.실현 원리
RequestBody Advice 는@RequestBody 이전에 해 야 할 작업 으로 이해 할 수 있 습 니 다.ResponseBody Advice 는@ResponseBody 이후 에 하 는 작업 으로 이해 할 수 있 습 니 다.따라서 인터페이스 에 복호화 가 필요 할 때@RequestBody 를 사용 하여 프론트 인 자 를 받 기 전에 RequestBody Advice 의 실현 클래스 에서 매개 변 수 를 복호화 할 수 있 습 니 다.작업 이 끝나 면 데 이 터 를 되 돌려 야 할 때,@Response Body 이후 Response Body Advice 의 실현 클래스 에 들 어가 매개 변 수 를 암호 화 할 수 있 습 니 다.
RequestBody Advice 요청 처리 과정:
RequestBody Advice 소스 코드 는 다음 과 같 습 니 다.

public interface RequestBodyAdvice {
 boolean supports(MethodParameter methodParameter, Type targetType,
   Class<? extends HttpMessageConverter<?>> converterType);
 HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter parameter,
   Type targetType, Class<? extends HttpMessageConverter<?>> converterType) throws IOException;
 Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter,
   Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
 @Nullable
 Object handleEmptyBody(@Nullable Object body, HttpInputMessage inputMessage, MethodParameter parameter,
   Type targetType, Class<? extends HttpMessageConverter<?>> converterType);
}
RequestBody Advice 구현 클래스 를 호출 하 는 부분 코드 는 다음 과 같 습 니 다.

protected <T> Object readWithMessageConverters(HttpInputMessage inputMessage, MethodParameter parameter,
   Type targetType) throws IOException, HttpMediaTypeNotSupportedException, HttpMessageNotReadableException {
  MediaType contentType;
  boolean noContentType = false;
  try {
   contentType = inputMessage.getHeaders().getContentType();
  }
  catch (InvalidMediaTypeException ex) {
   throw new HttpMediaTypeNotSupportedException(ex.getMessage());
  }
  if (contentType == null) {
   noContentType = true;
   contentType = MediaType.APPLICATION_OCTET_STREAM;
  }
  Class<?> contextClass = parameter.getContainingClass();
  Class<T> targetClass = (targetType instanceof Class ? (Class<T>) targetType : null);
  if (targetClass == null) {
   ResolvableType resolvableType = ResolvableType.forMethodParameter(parameter);
   targetClass = (Class<T>) resolvableType.resolve();
  }
  HttpMethod httpMethod = (inputMessage instanceof HttpRequest ? ((HttpRequest) inputMessage).getMethod() : null);
  Object body = NO_VALUE;
  EmptyBodyCheckingHttpInputMessage message;
  try {
   message = new EmptyBodyCheckingHttpInputMessage(inputMessage);
   for (HttpMessageConverter<?> converter : this.messageConverters) {
    Class<HttpMessageConverter<?>> converterType = (Class<HttpMessageConverter<?>>) converter.getClass();
    GenericHttpMessageConverter<?> genericConverter =
      (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
    if (genericConverter != null ? genericConverter.canRead(targetType, contextClass, contentType) :
      (targetClass != null && converter.canRead(targetClass, contentType))) {
     if (logger.isDebugEnabled()) {
      logger.debug("Read [" + targetType + "] as \"" + contentType + "\" with [" + converter + "]");
     }
     if (message.hasBody()) {
      HttpInputMessage msgToUse =
        getAdvice().beforeBodyRead(message, parameter, targetType, converterType);
      body = (genericConverter != null ? genericConverter.read(targetType, contextClass, msgToUse) :
        ((HttpMessageConverter<T>) converter).read(targetClass, msgToUse));
      body = getAdvice().afterBodyRead(body, msgToUse, parameter, targetType, converterType);
     }
     else {
      body = getAdvice().handleEmptyBody(null, message, parameter, targetType, converterType);
     }
     break;
    }
   }
  }
  catch (IOException ex) {
   throw new HttpMessageNotReadableException("I/O error while reading input message", ex);
  }
  if (body == NO_VALUE) {
   if (httpMethod == null || !SUPPORTED_METHODS.contains(httpMethod) ||
     (noContentType && !message.hasBody())) {
    return null;
   }
   throw new HttpMediaTypeNotSupportedException(contentType, this.allSupportedMediaTypes);
  }
  return body;
 }
위의 소스 코드 에서converter.canRead()message.hasBody()가 모두 true 일 때beforeBodyRead()afterBodyRead()방법 을 호출 할 수 있 기 때문에 우 리 는 실현 류 의 after Body Read()에 복호화 코드 를 추가 하면 된다.
Response Body Advice 처리 응답 과정:
ResponseBody Advice 소스 코드 는 다음 과 같 습 니 다.

public interface ResponseBodyAdvice<T> {
 boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType);
 @Nullable
 T beforeBodyWrite(@Nullable T body, MethodParameter returnType, MediaType selectedContentType,
   Class<? extends HttpMessageConverter<?>> selectedConverterType,
   ServerHttpRequest request, ServerHttpResponse response);
}
Response Body Advice 구현 클래스 를 호출 하 는 부분 코드 는 다음 과 같 습 니 다.

if (selectedMediaType != null) {
   selectedMediaType = selectedMediaType.removeQualityValue();
   for (HttpMessageConverter<?> converter : this.messageConverters) {
    GenericHttpMessageConverter genericConverter =
      (converter instanceof GenericHttpMessageConverter ? (GenericHttpMessageConverter<?>) converter : null);
    if (genericConverter != null ?
      ((GenericHttpMessageConverter) converter).canWrite(declaredType, valueType, selectedMediaType) :
      converter.canWrite(valueType, selectedMediaType)) {
     outputValue = (T) getAdvice().beforeBodyWrite(outputValue, returnType, selectedMediaType,
       (Class<? extends HttpMessageConverter<?>>) converter.getClass(),
       inputMessage, outputMessage);
     if (outputValue != null) {
      addContentDispositionHeader(inputMessage, outputMessage);
      if (genericConverter != null) {
       genericConverter.write(outputValue, declaredType, selectedMediaType, outputMessage);
      }
      else {
       ((HttpMessageConverter) converter).write(outputValue, selectedMediaType, outputMessage);
      }
      if (logger.isDebugEnabled()) {
       logger.debug("Written [" + outputValue + "] as \"" + selectedMediaType +
         "\" using [" + converter + "]");
      }
     }
     return;
    }
   }
  }
위의 소스 코드 에서 converter.canWrite()가 true 일 때 beforeBody Write()방법 을 호출 할 수 있 기 때문에 우 리 는 이러한 beforeBody Write()에 복호화 코드 를 추가 하면 됩 니 다.
실전
spring boot 프로젝트 를 새로 만 듭 니 다.spring-boot-encry 는 다음 단계 로 작 동 합 니 다.
pom.xml 에 jar 도입

<dependencies>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-web</artifactId>
  </dependency>

  <dependency>
   <groupId>org.projectlombok</groupId>
   <artifactId>lombok</artifactId>
   <optional>true</optional>
  </dependency>
  <dependency>
   <groupId>org.springframework.boot</groupId>
   <artifactId>spring-boot-starter-test</artifactId>
   <scope>test</scope>
   <exclusions>
    <exclusion>
     <groupId>org.junit.vintage</groupId>
     <artifactId>junit-vintage-engine</artifactId>
    </exclusion>
   </exclusions>
  </dependency>

  <dependency>
   <groupId>com.alibaba</groupId>
   <artifactId>fastjson</artifactId>
   <version>1.2.60</version>
  </dependency>
 </dependencies>
요청 매개 변수 복호화 차단 클래스
DecryptRequestBody Advice 코드 는 다음 과 같 습 니 다.

/**
 *          
 * * @Author: Java   
 * @Date: 2019/10/24 21:31
 *
 */
@Component
@ControllerAdvice(basePackages = "com.example.springbootencry.controller")
@Slf4j
public class DecryptRequestBodyAdvice implements RequestBodyAdvice {
 @Override
 public boolean supports(MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
  return true;
 }
 @Override
 public HttpInputMessage beforeBodyRead(HttpInputMessage inputMessage, MethodParameter methodParameter, Type targetType, Class<? extends HttpMessageConverter<?>> selectedConverterType) throws IOException {
  return inputMessage;
 }
 @Override
 public Object afterBodyRead(Object body, HttpInputMessage inputMessage, MethodParameter parameter, Type targetType, Class<? extends HttpMessageConverter<?>> converterType) {
  String dealData = null;
  try {
   //    
   Map<String,String> dataMap = (Map)body;
   String srcData = dataMap.get("data");
   dealData = DesUtil.decrypt(srcData);
  } catch (Exception e) {
   log.error("  !", e);
  }
  return dealData;
 }
 @Override
 public Object handleEmptyBody(@Nullable Object var1, HttpInputMessage var2, MethodParameter var3, Type var4, Class<? extends HttpMessageConverter<?>> var5) {
  log.info("3333");
  return var1;
 }
}
응답 매개 변수 암호 화 차단 클래스
암호 응답 Body Advice 코드 는 다음 과 같 습 니 다.

/**
 *          
 *
 * @Author: Java   
 * @Date: 2019/10/24 21:31
 *
 */
@Component
@ControllerAdvice(basePackages = "com.example.springbootencry.controller")
@Slf4j
public class EncryResponseBodyAdvice implements ResponseBodyAdvice<Object> {
 @Override
 public boolean supports(MethodParameter returnType, Class<? extends HttpMessageConverter<?>> converterType) {
  return true;
 }
 @Override
 public Object beforeBodyWrite(Object obj, MethodParameter returnType, MediaType selectedContentType,
         Class<? extends HttpMessageConverter<?>> selectedConverterType, ServerHttpRequest serverHttpRequest,
         ServerHttpResponse serverHttpResponse) {
  //   ServerHttpRequest    ServletServerHttpRequest   HttpServletRequest
  ServletServerHttpRequest sshr = (ServletServerHttpRequest) serverHttpRequest;
  //     request                          ,    
  HttpServletRequest request = sshr.getServletRequest();
  String returnStr = "";
  try {
   //  encry header,         
   serverHttpResponse.getHeaders().add("encry", "true");
   String srcData = JSON.toJSONString(obj);
   //  
   returnStr = DesUtil.encrypt(srcData);
   log.info("  ={},    ={},     ={}", request.getRequestURI(), srcData, returnStr);
  } catch (Exception e) {
   log.error("  !", e);
  }
  return returnStr;
 }
새 controller 클래스
TestController 코드 는 다음 과 같 습 니 다.

/** * @Author: Java   
 * @Date: 2019/10/24 21:40
 */
@RestController
public class TestController {
 Logger log = LoggerFactory.getLogger(getClass());
 /**
  *        
  */
 @RequestMapping(value = "/sendResponseEncryData")
 public Result sendResponseEncryData() {
  Result result = Result.createResult().setSuccess(true);
  result.setDataValue("name", "Java   ");
  result.setDataValue("encry", true);
  return result;
 }
 /**
  *             
  */
 @RequestMapping(value = "/getRequestData")
 public Result getRequestData(@RequestBody Object object) {
  log.info("controller     object={}", object.toString());
  Result result = Result.createResult().setSuccess(true);
  return result;
 }
}
다른 종 류 는 원본 코드 에 있 고 뒤에 github 주소 가 있 습 니 다.
테스트
액세스 응답 데이터 암호 화 인터페이스
postman 보 내기 요청http://localhost:8888/sendResponseEncryData을 사용 하면 반환 데이터 가 암호 화 되 었 음 을 볼 수 있 습 니 다.캡 처 요청 은 다음 과 같 습 니 다.

응답 데이터 암호 화 캡 처
배경 에 도 관련 로 그 를 인쇄 합 니 다.내용 은 다음 과 같 습 니 다.
인터페이스=/sendResponseEncryData
원본 데이터={"data":{"encry":true,"name":"Java "},"success":true}암호 화 된 데이터=vJc26g3SQRU9gAJdG7rhnAx6Ky/IhgioAgdwi6aLMMtyynAB4nEbMxvDsKEPNIa5bQaT7ZAImAL73VeicCuSTA==
액세스 요청 데이터 복호화 인터페이스
postman 보 내기 요청http://localhost:8888/getRequestData을 사용 하면 요청 데이터 가 복호화 되 었 음 을 볼 수 있 습 니 다.캡 처 요청 은 다음 과 같 습 니 다.

데이터 복호화 요청 캡 처
배경 에 도 관련 로 그 를 인쇄 합 니 다.내용 은 다음 과 같 습 니 다.

         ={"data":"VwLvdE8N6FuSxn/jRrJavATopaBA3M1QEN+9bkuf2jPwC1eSofgahQ=="}

     ={"name":"Java   ","des":"    "}
밟 은 구덩이
복호화 요청 파 라 메 터 를 테스트 할 때 요청 체 는 반드시 데이터 가 있어 야 합 니 다.그렇지 않 으 면 클래스 트리거 복호화 작업 을 호출 하지 않 습 니 다.
이 SpringBoot 에서 인터페이스 데이터 의 복호화 기능 을 어떻게 유연 하 게 실현 하 는 지 에 대한 기능 이 모두 실현 되 었 습 니 다.문제 가 있 으 면 댓 글 소통 을 환영 합 니 다!
전체 원본 주소:https://github.com/suisui2019/springboot-study
총결산
위 에서 말 한 것 은 소 편 이 소개 한 SpringBoot 가 인터페이스 데이터 의 복호화 기능 을 실현 하 는 것 입 니 다.여러분 에 게 도움 이 되 기 를 바 랍 니 다.궁금 한 점 이 있 으 면 메 시 지 를 남 겨 주세요.소 편 은 제때에 답 해 드 리 겠 습 니 다.여기 서도 저희 사이트 에 대한 여러분 의 지지 에 감 사 드 립 니 다!
만약 당신 이 본문 이 당신 에 게 도움 이 된다 고 생각한다 면,전 재 를 환영 합 니 다.번 거 로 우 시 겠 지만 출처 를 밝 혀 주 십시오.감사합니다!

좋은 웹페이지 즐겨찾기