Bank Application

[Bank Application] 2-1. Security Config

겨르 2024. 9. 26. 14:52

BankApplication > config > SecurityConfig.java 파일을 생성해준다

@Bean //Ioc 컴테이너에 BCryptPasswordEncoder() 객체가 등록됨 , @Configuration이 붙여진 곳에서만 등록 가능
public BCryptPasswordEncoder passwordEncoder(){
    log.debug("디버그: BCryptPasswordEncoder 빈 등록");
    return new BCryptPasswordEncoder();
}

 

//JWT 서버를 만들것 -> Session 사용 안함
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http)throws Exception{
        log.debug("디버그: filterChain 빈 등록");
        http.headers().frameOptions().disable(); //iframe 허용 안함
        http.csrf().disable(); //enable 이면 post 작동 안함
        http.cors().configurationSource(configurationSource());

        //JSessionId를 서버쪽에서 관리 안하겠다는 뜻
        http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);

        //React, app으로 요청할 예정
        http.formLogin().disable();

        //httpBasic은 브라우저가 팝업창을 이용해서 사용자 인증을 진행함
        http.httpBasic().disable();

        http.authorizeRequests()
                .antMatchers("/api/s/**").authenticated()
                .antMatchers("/api/admin/**").hasRole(""+UserEnum.ADMIN)
                .anyRequest().permitAll();

        return http.build();
    }
public CorsConfigurationSource configurationSource(){
        log.debug("디버그: configurationSource cors 설정이 SecurityFilterChain에 등록");

        CorsConfiguration configuration = new CorsConfiguration();
        configuration.addAllowedHeader("*");
        configuration.addAllowedMethod("*"); //GET, POST, PUT, DELETE (JS 요청 허용)
        configuration.addAllowedOriginPattern("*"); //모든 IP주소 허용 (프론트앤드 IP만 허용)
        configuration.setAllowCredentials(true); //클라이언트에서 쿠키 요청 허용;

        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**", configuration);

        return source;
    }

세가지 기본 Security Config를 생성 후 Bean에 등록된걸 확인하기 위해 log.debug 찾기

알맞게 등록이 되었다는걸 확인할 수 있었다.

 

ioc에 올라간것을 확인하기 위해서는

main 파일에서 String배열을 뜯어봐서 확인

 

Postman으로 테스트 해보면

1. 그냥 주소로 접근 시 404

2. /s/** 주소로 들어갔을때 403 

3. admin으로 접근 시 403이 나오는것을 확인할 수 있었다


+ JUnit 테스트

class 를 생성해주고

@AutoConfigureMockMvc //Mock 환경에 MockMvc가 등록됨
@SpringBootTest(webEnvironment = WebEnvironment.MOCK)
class SecurityConfigTest {

    //Mock 환경에 등록된 MockMvc를 DI함
    @Autowired
    private MockMvc mvc;

    //서버는 일관성있게 에러가 리턴되어야 한다
    //내가 모르는 에러가 프론트로 나타나지 않게 내가 다 제어할 수 있도록
    @Test
    public void authentication_test() throws Exception{
        // given

        // when
        ResultActions resultActions = mvc.perform(get("/api/s/hello"));
        String responseBody = resultActions.andReturn().getResponse().getContentAsString();
        int httpStatusCode = resultActions.andReturn().getResponse().getStatus();
        System.out.println("테스트1 : "+responseBody);
        System.out.println("테스트2 : "+httpStatusCode);
        // then
        assertThat(httpStatusCode).isEqualTo(401);
    }

    @Test
    public void authorization_test() throws Exception {
        // given

        // when
        ResultActions resultActions = mvc.perform(get("/api/admin/hello"));
        String responseBody = resultActions.andReturn().getResponse().getContentAsString();
        int httpStatusCode = resultActions.andReturn().getResponse().getStatus();
        System.out.println("테스트 : " + responseBody);
        System.out.println("테스트 : " + httpStatusCode);

        // then
        assertThat(httpStatusCode).isEqualTo(401);
    }

}

 

authentication은 인가되지 않은 상태

authorization은 인증되지 않은 상태로 각각 나누어 확인해본다

 

이때, console에 나오는 내용을 JSON으로 표시하기 위해 SecureConfig에 Exception을 추가한다

 

공통DTO로 만들어준다

util > CustomResponseUtil.java

public class CustomResponseUtil {
    private static final Logger log = LoggerFactory.getLogger(CustomResponseUtil.class);
    public static void unAuthentication(HttpServletResponse response, String msg){
        try {
            ObjectMapper om = new ObjectMapper();
            ResponseDto<?> responseDto = new ResponseDto<>(-1, msg, null);
            String responseBody = om.writeValueAsString(responseDto); //JSON으로 변함
            response.setContentType("application/json; charset=utf-8");
            response.setStatus(401);
            response.getWriter().println(responseBody);
        }catch (Exception e){
            log.error("서버 파싱 에러");
        }
    }
}

401일때 가로채서 로그인 진행 메세지 뿌리기

//Exception 가로채기
        http.exceptionHandling().authenticationEntryPoint((request, response, authException)->{
            CustomResponseUtil.unAuthentication(response, "로그인을 진행해 주세요");
                });

 

 

결과적으로 JUnit 실행했을때

형태로 내보낸것과 통과함을 확인할 수 있다