아직 남들에게 보여줄 만큼은 아니지만 혼자 나름대로 열심히 토이프로젝트를 진행하고 있는데, 아무래도 BackEnd 와 FrontEnd 를 분리해서 진행하려고 보니 테스트하는데에 불편함이 있습니다.

게다가 일반 회원 로그인 기능 없이 소셜 로그인으로만 Security 를 구현해놨더니 더더욱 REST API 만으로는 테스트가 힘들어서 뒤로 미뤄뒀던 Swagger 를 개발 초기 단계에서 적용하기로 했습니다.

1. build.gradle 에 dependency 추가

// open api 3.0 + swagger
implementation 'org.springdoc:springdoc-openapi-ui:1.5.8'

여기까지 추가하면 알아서 /v3/api-docs/swagger-ui.html 이 자동으로 생성되기때문에 바로 확인할 수 있….긴한데 테스트를 해보니 POST 요청이 모두 Forbidden 으로 떨어지는 문제가 발생했다. 이는 Security 에 csrf 문제로 아래와 같이 해결할 수 있다.

2. SecurityConfig

특정 URL 요청(swagger)에만 csrf 를 비활성화 시킨다.

CsrfRequireMatcher.class 생성

public class CsrfRequireMatcher implements RequestMatcher {
	private static final Pattern ALLOWED_METHODS = Pattern.compile("^(GET|HEAD|TRACE|OPTIONS)$");

	@Override
	public boolean matches(HttpServletRequest request) {
		if (ALLOWED_METHODS.matcher(request.getMethod()).matches())
			return false;

		final String referer = request.getHeader("Referer");
		if (referer != null && referer.contains("/swagger-ui")) {
			return false;
		}
		return true;
	}
}


SecurityConfig 수정

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
	
	// ...

	@Override
	protected void configure(HttpSecurity http) {
		http.csrf().disable()
            .authorizeRequests()
            .antMatchers("swagger-ui.html", "/swagger-ui/**", "/api-docs", "/api-docs/**").hasRole(Role.USER.name())
            // ...
        ;

		http.csrf()
				.requireCsrfProtectionMatcher(new CsrfRequireMatcher())
				.csrfTokenRepository(CookieCsrfTokenRepository.withHttpOnlyFalse());
	}
}

작성된 내용에 대한 지적은 환영입니다. 많이 알려주세요.


Reference

https://springdoc.org
https://www.baeldung.com/spring-rest-openapi-documentation
https://blog.jiniworld.me/83#a02-3