[Spring] Securty + Swagger 적용기(with 404)

BlackBean99·2022년 9월 25일
3

SpringBoot

목록 보기
17/20

Swagger 란?

Swagger를 적용시키기 전에 알아둬야 할 것 바로 Swagger는 2개라는 것이다. springfox, springdocs 가 있는데 2020년부터 springfox 는 업데이트가 없었고, springboot 2.6.x 이상 버전이 호환이 안됩니다.
Spring-Doc는 최근에 나와서 업데이트도 진행되고 있고 Spring Boot 2.6 이상도 지원합니다.
그렇다고 docs이 더 좋다는 이야기는 아니구 많이 넘어가는 추세입니다.
사실 저는 springfox를 아무리 적용해봐도 security를 적용시키면 403, 404 에러가 해결되지 않아서 정말 안찾아본 자료가 없을정도로 다 해봤어요.
버전도 낮춰보고 Security 필터도 빼보고 모든 url을 permitAll() 을 해주기도 하고 진짜 다해봤는데 안돼서...

3일차.. 이게 뭐라고 3일이나 걸렸징..

암튼, Swagger는 개발할때 하는 문서화들을 자동화해주는 툴인데요. 백엔드 컨트롤러에 특정 어노테이션을 달아주면 ui형태로 명세서를 자동으로 만들어주는 참 편한 프로그램이라 자주 사용합니다.

그럼 적용시켜서 한번 써볼까요?

Security를 적용하면 기본적으로 Security가 url을 막는 기능이 있어서 적용을 시켜보겠습니다.

SwaggerConfig

@EnableWebSecurity
@RequiredArgsConstructor
public class SecurityConfig {
    private final JwtProvider jwtTokenProvider;
    private final JwtAuthenticationFilter jwtAuthenticationFilter;
    private final ObjectMapper objectMapper;
    @Bean
    public WebSecurityCustomizer configure(){
        return (web) -> web.ignoring().mvcMatchers(
                "v3/api-docs"
                ,"swagger-ui/**"
        );
    }
    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        return http.antMatcher("/**")
                .authorizeRequests()
                .and()
                .httpBasic().disable() // 
                .cors().disable() // cors 사용 중지
                .csrf().disable()
                .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS) // 세션 사용 중지
                .and()
                .authorizeRequests()// 시큐리티 처리에 HttpServeltRequest를 사용합니다.
                .anyRequest().permitAll()
                .and()
                .addFilterBefore(new JwtAuthenticationFilter(jwtTokenProvider),
                        UsernamePasswordAuthenticationFilter.class)  
                        //JwtAuthenticationFilterUsernamePasswordAuthenticationFilter 전에 넣는다
                .exceptionHandling()    //Exception Handler
                .authenticationEntryPoint(((request, response, authException) -> {
                    response.setStatus(HttpStatus.UNAUTHORIZED.value());
                    response.setContentType(MediaType.APPLICATION_JSON_VALUE);
                    objectMapper.writeValue(
                            response.getOutputStream(),
                            new BasicResponse("exception event",HttpStatus.FORBIDDEN)
                    );
                })).and().build();

Spring Security를 설정해보려고 WebSecurityConfigurerAdapter를 사용하려 보니 Deprecated가 되어 있습니다.
Deprecated 된걸 그대로 쓰려니 당연히 permission이 막힐텐데 말이죠..

Deprecated. Use a SecurityFilterChain Bean to configure HttpSecurity or a WebSecurityCustomizer Bean to configure WebSecurity
하이구야..

WebMvcConfigurerAdapter deprecated

그래서 기존 webmvcconfigureradapter 를 extends 쓰는 방법을 계속 쓰면?
404 에러가 발생하거나 permission denied 가 발생합니다.

SwaggerConfig에서 코드 설명을 하겠습니다.

WebSecurityConfigurerAdapter 공식문서를 보면 위와 같이 나와 있습니다.

그래서 코드를 어떻게 변경해서 써야 할까요?
SpringSecurity 공식문서을 보면 코드와 함께 나와있습니다.

1. WebSecurityCustomizer


기존 코드

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    public void configure(WebSecurity web) {
        web.ignoring().antMatchers("/ignore1", "/ignore2");
    }

}

변경 코드 (WebSecurityCustomizer)

@Configuration
public class SecurityConfiguration {

    @Bean
    public WebSecurityCustomizer webSecurityCustomizer() {
        return (web) -> web.ignoring().antMatchers("/ignore1", "/ignore2");
    }

}

2. WebSecurityFilterChain


기존 코드

@Configuration
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .anyRequest().authenticated()
            )
            .httpBasic(withDefaults());
    }

}

변경 코드 ( WebSecurityFilterChain 등록해서 사용)

@Configuration
public class SecurityConfiguration {

    @Bean
    public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
        http
            .authorizeHttpRequests((authz) -> authz
                .anyRequest().authenticated()
            )
            .httpBasic(withDefaults());
        return http.build();
    }

}

@EnableWebSecurity 어노테이션을 명시하는 것만으로도 springSecurityFilterChain가 자동으로 포함되어 지기 때문에
WebSecurityFilterChain을 Bean으로 등록해서 사용하면 됩니다.

SwaggerConfig

    @Bean
    public GroupedOpenApi jwtApi() {
        return GroupedOpenApi.builder()
                .group("jwt-api")
                .pathsToMatch("/**")
                .build();
    }

    @Bean
    public OpenAPI customOpenAPI() {
        return new OpenAPI()
                .components(new Components())
                .info(new Info().title("Spring Boot API Example")
                        .description("Spring Boot API 예시 프로젝트입니다.")
                        .version("v0.0.1"));
    }

이런식으로 SwaggerConfig 를 선언해주시면 됩니다.
GroupedOpenApi 를 사용하면, 특정 그룹으로 선언된 기능들을 분리를 할 수 있습니다.

OpenAPI를 선언하면 기본 Swagger 설명들을 세팅할 수 있습니다. 자세한건 Document를 살펴봅시다~

Controller

이제 컨트롤러에 어노테이션을 붙여서 명세서 내용을 채워주면 끝입니다.

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.responses.ApiResponse;
import io.swagger.v3.oas.annotations.responses.ApiResponses;

--

    @Operation(summary = "logout", description = "로그아웃")
    @ApiResponses({
            @ApiResponse(responseCode = "200", description = "OK"),
            @ApiResponse(responseCode = "400", description = "BAD REQUEST"),
            @ApiResponse(responseCode = "404", description = "NOT FOUND"),
            @ApiResponse(responseCode = "500", description = "INTERNAL SERVER ERROR")
    })
    @GetMapping("/logout")
    public ResponseEntity<BasicResponse> logout(@AuthUser Account account, HttpServletRequest request) {
		~~~~~~~~~~~~~~~~~~
    }

이렇게 작성하면

Result

와! 이제 동작을 합니다 ㅠㅠㅠ deprecated는 오기부리지 말고 쓰지 마세요~

profile
like_learning

0개의 댓글