항해99

23.10.03 항해 99 16기 주특기 프로젝트 15일차

김용글 2023. 10. 3. 22:37

오늘 공부한 것

* 페어가 작성한 미니프로젝트 정리 공부

 

1.  Cors 

 1) Cors 란

    아래 블로그는 내가 예전에 공부했던 것이고

https://nodaji1012-hanghae99-16.tistory.com/45

 

23.09.11~09.17 항해 99 16기 5주차 회고록

월요일에는 Lv3 과제 제출을 하고 JAVA 객체 지향을 다시 공부했다 화요일에는 Spring 심화 주차 강의를 들었고 Lv4 과제를 시작했다 수요일에는 Lv4 과제를 제출 했다 기존에 만들었던 것을 업그레이

nodaji1012-hanghae99-16.tistory.com

     이 블로그는 페어분께서 참고하신 블로그다

https://ikadnorth.tistory.com/192

 

CORS, SOP

👣 개요 예를 들어, 피싱 사이트가 보통의 네이버 사이트(www.fake:80)를 모사해 피해자를 속였다고 가정해보자. 해당 사이트의 HTML에 포함된 JS 코드에 의해 현재 LocalStorage의 정보들을 모두 긁어서

ikadnorth.tistory.com

  결론을 이야기하자면 Cors란 악의적인 개발자의 정보 남용을 막고자 웹 브라우저 차원에서 바련한 보안장치이다

  서버가 허용한 웹 페이지에서만 해당 서버의 리소스를 확인 할 수 있다

 

 2) Cors 테스트 방법

   다양한 방법이 있지만 대표적인 방법인 preflight 방법을 이용해 테스트 코드를 작성했다

   아래와 같이  OPTIONS  메서드로  Preflight  요청을 보내고 해당 응답에 HttpHeaders.ORIGIN  으로 표기했던 값이

   정확히 돌아오는지를 확인하였다

@ActiveProfiles("prod")
@SpringBootTest
@AutoConfigureMockMvc
@TestPropertySource(properties = {
        "MYSQL_DATABASE_USERNAME=test_account",
        "MYSQL_DATABASE_PASSWORD=q1w2e3r4",
        "MYSQL_URL=localhost:3306",
        "OAUTH2_CLIENT_ID_KAKAO=1234567654123456",
        "FRONTEND_ORIGIN=https://my-web-server-host",
        "KEY_STORE_PASSWORD=q1w2e3r4"
})
class CorsTestInProfileProd {
    @Autowired
    private MockMvc mvc;

    @WithMockUser //인증된 상태로 테스트를 진행하도록 도와줌
    @Test
    @DisplayName("[정상 작동] Preflight 요청 시, 해당 응답이 적절한지 확인")
    void preflight() throws Exception {
        // given
        String clientOrigin = "https://my-web-server-host";
        String method = "POST";
        String host = "/api/signup";

        // when & then
        mvc.perform(
                options(host)
                        .header(HttpHeaders.ACCESS_CONTROL_ALLOW_METHODS, method)
                        .header(HttpHeaders.ORIGIN, clientOrigin)
        )
                .andDo(print())
                .andExpect(status().isOk())
                .andExpect(header().string(HttpHeaders.ACCESS_CONTROL_ALLOW_ORIGIN, clientOrigin));
    }
}

 

2. 다양한 Profile

 1) Profile 이란?

     개발을 할때, 실제 서비스를 운영할때, 테스트를 할때 등등 설정값들은 각각 다를 수 있다

     예를 들어 테스트를 할때는 QA를 위한 테스트 데이터를 DB에 사용할 수도 있고, MySQL이 아닌 H2DB를 사용할 수도

     있다 반면, 실제 서비스를 운영할 때는 MySQL을 사용하고 배포한 MySQL 서버 URL 설정값을 사용해야 할 수도 있다

     상황마다 application.properties 값을 변경해서 사용할 수도 있지만, Prod, Test, Local 상황마다 전환하는 것은 

     Human Error를 유발할 수 있고 비용이 많이 드는 작업이다

     이를 위해 Spring Boot에서는 각 Profile에 따른 설정을 분리할 수 있도록 지원하고있다

 

 2) 프로젝트에서의 Profile 운용 방식

  • 총 3개의 Profiles를 사용했다

     (1) Local

          백엔드 개발을 위함

     (2) Test

          프론트엔드 팀의 편의를 위한 서버 실제로 EC2에 배포를 했다

          다만, MySQL이 아닌 H2DB 사용

     (3) Prod

          실제 서비스를 위해 사용

 

3. SRP 원칙을 준수한 Spring Security 설정방법

 1) SRP란?

     SOLID 5원칙이라고도 불리는 OPP 5대 원칙중 Single Responsibilty Principle의 줄임말로

     '1개의 클래스는 1개의 책임만 가져야한다' 라는 원칙

     기존에 배운 Spring Security들은 '인가 경로정의', 'Cors 설정' 등이 모두 1개의 파일로면 해결되었다

     하지만, 이것을 Profile을 이용하여 정의하려고 하니 코드 중복이 심하고 특정 기술을 위해 어떤 설정을 했는지 기록이

     모호했기에 SRP 원칙을 지키는 파일로 변경하고자  Spring Injecting Collection  을 사용하기로 했다

 

 2) Spring Injecting Collection

     Bean Container는 Bean을 주입할때 Collection 으로도 DI가 가능하다

    예를 들어 아래와 같은 주입이 가능하다 이렇게 받는 다면 같은 타입으로 선언된 Bean을 모두 호출할 수 있다

@Configuration
public Beans {
    @Bean
    public Something bean1() { ... }

    @Bean
    public Something bean2() { ... }
}
@Component
@RequiredArgsConstruction
public Client {
    @Autowired
    public Collection<Something> beans;
    @Autowired
    public List<Something> beans;
    @Autowired
    public Set<Something> beans;
    @Autowired
    public Map<String,Something> beans;
}

 

 3) 실제 설정 사례

                 실제로는 FilterChainRing 이라는 인터페이스를 만들고

                 filterChainRingContainer라는 클래스를 선언하여

                 모든 Security 관련 설정들을 일괄 등록하는 코드를 만들었다

                 이로 인해 SRP 원칙뿐만 아니라 OCP원칙을 준수하는

                 Security 관련 설정들을 수행할 수 있게 되었다

 

 

 

 

 

 

 

 

 

4. DTO 직렬화, 역직렬화

 1) Spring FrameWork에서의 직렬화, 역직렬화의 필요성

     해당 서버로 들어오는 요청은 사실 텍스트로만 이루어진 글자들이다

     Spring 에서는 이를 자바 객체로 사용할수 있도록 Form-data 혹은 Json 데이터를 Java Object로 역질렬화를 해주고

     응답할 때는 반대로 Java Pbject를 직렬화하여 Json 혹은 Form-data로 변환하여 응답을 준다

     때문에 실제로 직렬화, 역직렬화를 돕는 도구인 ObjectMapper에 대한 이해가 필요하다

 

 2) ObjectMapper

     Spring Framework에서 공식적으로 채택한 직렬화, 역직렬화를 위한 라이브러리의 대표적 도구로 Bean DI하여

     사용할 수도있다

      텍스트 원문을 Java Object로 변환해준다고는 하지만 모든 직렬화를 수행하지 않는다 조건은 아래와 같다

  • 기본 생성자 + (public) Getter
  • 기본 생성자 + (*) Setter

  3) JsonCreator 

      ObjectMapper의 역직렬화를 위해 사용되는 어노테이션

      만약 위와 같은 직렬화 조건을 만족할 수 없는 DTO라면

      JsonCreator 어노테이션을 이용하여 역질렬화에 사용될

     생성자를 지정할 수 있다

 

 

 

 

 

 

 

 

 

 

 

 

5. WithSecurityContext를 이용한 TestCode

 1) WithSecurityContext 란?

     Controller Layer에서  @AuthenticationPrincipal  을 사용할 때 UserDetails 객체를 해당 어노테이션이 적용된

     파라미터에 주입한다 

     실제  UserDetails  값을 주입하는 것이기 때문에  @WithMocUser  를 이용해서 테스트를 진행하면 위와 같은

     주입이 정상적으로 이뤄지지 않기 때문에 직접  SecurityContextholder  내부의 Principal을 작성해줘야 한다

     물론   @WithMocUser   역시 SecurityContextholder  내부에 Principal을 주입하긴 하지만  User  라는 타입을

     이용하여 주입하기 때문에 직접 구현한  UserDetailsImpl  을 넣어주는 것이 아니다

     결론적으로 해당 Principal을 직접 넣기 위해 아래와 같은 코드를 작성했다