본문 바로가기
IT/Web

Swagger + JWT

by 최고영회 2019. 9. 27.
728x90
반응형
SMALL

2019/08/28 - [IT/Web] - Swagger 를 이용한 API 문서화 및 테스트 자동화(?)

 

Swagger 를 이용한 API 문서화 및 테스트 자동화(?)

요즘 Backend 는 Business Logic 만 수행하고 그에 대한 결과만 반환하며 나머지는 Frontend 에서 처리하도록 구현한다. Backend를 REST API 로 만들게 되면 당연히 그에 대한 API 문서도 필요하게 된다. 그리고 R..

kimyhcj.tistory.com

Swagger 를 이용하여 API 문서화와 각각의 API 테스트를 진행하고 있다. 

그리고 Restful API 에 대한 인증에 JWT 적용했다.

2019/08/23 - [IT] - JWT (토큰 기반 인증 방식) 의 이해

 

JWT (토큰 기반 인증 방식) 의 이해

JWT Jason Web Token의 약자로 전자 서명 된 URL-safe의 JSON이다. 거대하고 복잡한 단일 어플리케이션 개발에서 서비스를 작은 단위로 분할하여 민첩한 개발을 할 수 있는 Microservice Architecture 로 전향할..

kimyhcj.tistory.com

JWT를 적용하고 나니 Swagger 를 이용한 테스트에 시 모두 Token 이 없어서 401 오류가 발생한다. 

JWT 를 검증하는 Filter 를 추가 했으니 당연한 결과이다. 

API Method 에 아래와 같이 JWT 를 입력하도록 Param을 넣어주면 해결 된다. 

@ApiImplicitParams({
 @ApiImplicitParam(name = Constant.HEADER_AUTH, value = "로그인 성공 후 access_token", required = true, dataType = "String", paramType = "header")
})
@GetMapping
public ResponseEntity<List<DocLayout>> getAllDocLayout(HttpServletRequest req) {
  return new ResponseEntity<List<DocLayout>>(layoutService.findAll(DocLayoutSearch.builder().build().setParam(req)), HttpStatus.OK);
}

모든 API Method 마다 위와 같은 작업을 하는 것은.... 사실 말이 안된다. 

Swagger Configure 를 통해 이를 해결 할 수 있다.

해결된 화면을 먼저 보자.

우측 상단에 Authorize 가 생겼다. 

버튼을 클릭하면 아래와 같이 JWT 값을 입력하는 인증 화면이 나온다. 

 

이제 다시 테스트 해 보면.. 잘된다.!!

 


소스코드를 살펴 보자. 

SwaggerConfiguration.java

중요 부분은 apiKey(), securityContext(), defaultAuth() 가 전부이다. 

@Configuration
@EnableSwagger2
@Profile("dev")
@Import(springfox.bean.validators.configuration.BeanValidatorPluginsConfiguration.class)
public class SwaggerConfiguration {

    @Bean
    public Docket swaggerSpringfoxDocket() {

        Docket docket = new Docket(DocumentationType.SWAGGER_2)
            .apiInfo(apiEndPointsInfo())
            .pathMapping("/")
            .forCodeGeneration(true)
            .genericModelSubstitutes(ResponseEntity.class)
            .ignoredParameterTypes(java.sql.Date.class)
            .directModelSubstitute(java.time.LocalDate.class, java.sql.Date.class)
            .directModelSubstitute(java.time.ZonedDateTime.class, Date.class)
            .directModelSubstitute(java.time.LocalDateTime.class, Date.class)
            .securityContexts(Lists.newArrayList(securityContext()))
            .securitySchemes(Lists.newArrayList(apiKey()))
            .useDefaultResponseMessages(false);

        docket = docket.select()
        	.paths(PathSelectors.any())
            .build();
        return docket;
    }
    
    private ApiInfo apiEndPointsInfo() {
		return new ApiInfoBuilder().title("Decide REST API")
	            .description("This documents describes about decide version 7 REST API")
	            .contact(new Contact("Kim Young Hoi", "kimyhcj.tistory.com", "kimyhcj@gmail.com"))
	            .license("Apache 2.0")
	            .version("v1")
	            .build();
	}

    private ApiKey apiKey() {
        return new ApiKey("JWT", Constant.HEADER_AUTH, "header");
    }

    private springfox.documentation.spi.service.contexts.SecurityContext securityContext() {
        return springfox.documentation.spi.service.contexts.SecurityContext.builder()
            .securityReferences(defaultAuth())
            .forPaths(PathSelectors.any())
            .build();
    }

    List<SecurityReference> defaultAuth() {
        AuthorizationScope authorizationScope = new AuthorizationScope("global", "accessEverything");
        AuthorizationScope[] authorizationScopes = new AuthorizationScope[1];
        authorizationScopes[0] = authorizationScope;
        return Lists.newArrayList(new SecurityReference("JWT", authorizationScopes));
    }
}

 

그리고 Spring Security + JWT 를 이용했기 때문에 Swagger 는 security 에서 제외 시키도록 해야 한다. 

@Override
public void configure(WebSecurity web) {
  web.ignoring().antMatchers("/v2/api-docs", "/swagger-resources/**", "/swagger-ui.html", "/webjars/**", "/swagger/**");
}

 

728x90
반응형
LIST