์ด๋ฒ ํ ํ๋ก์ ํธ์์๋ ๋ก๊ทธ์ธ ์ ๋ฐ๊ธ๋ฐ์ ํ ํฐ์ HTTP header์ ํฌํจ์์ผ ๋ก๊ทธ์ธ ์ฌ๋ถ๋ฅผ ํ๋จํ๋ค.
์ฒ์ swagger๋ฅผ ์ ์ฉํ๊ธฐ ์ด์ ์๋ postman
์ ์ด์ฉํ์ฌ ํ
์คํธ๋ฅผ ์งํํ์ผ๋, ์ด ๊ฒฝ์ฐ์๋ ๋ฐ๊ธ ๋ฐ์ ํ ํฐ์ ํ
์คํธํ API์ header์ ๋งค๋ฒ ๊ฐ์ ๋ณ๊ฒฝํด์ฃผ์ด์ผ ํ๋ค๋ ๋ถํธํจ์ด ์กด์ฌํ๋ค.
๋ฐ๋ผ์ ๋ณด๋ค ํธ๋ฆฌํ ํ
์คํธ๋ฅผ ์ํด swagger๋ฅผ ๋์
ํ๊ธฐ๋ก ๊ฒฐ์ ํ๋ค.
swagger๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํด ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ถ๊ฐํ๊ณ ์งํํ์ผ๋ ์์ ๋ด์ฉ ์ฒ๋ผ 500 ์๋ฌ
๊ฐ ๋ฐ์ํ๋ค.
์์ธ์ ์ฐพ์๋ณด๋ ์ฐ๋ฆฌ๊ฐ ํ๋ก์ ํธ์์ ์ ์ฉํ spring security์์ filterChain์ ๊ฑธ๋ ธ๊ธฐ ๋๋ฌธ์ด์๋ค.
๊ทธ๋์ filter์์ swagger ๊ฒฝ๋ก๋ฅผ requestMatchers
๋ก ์ง์ ํ permitAll()
์ ํตํด ์์ธ ์ฒ๋ฆฌ๋ฅผ ํตํด filter์์ ๋งํ์ง ์๋๋ก ์ฒ๋ฆฌ๋ฅผ ํด์ฃผ์๋ค.
๐ ์ฝ๋ ์์
@Bean
public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception {
return http
.csrf(AbstractHttpConfigurer::disable)
.sessionManagement(session -> session
.sessionCreationPolicy(SessionCreationPolicy.STATELESS) // SessionManagementFilter, SecurityContextPersistenceFilter
)
.addFilterBefore(jwtSecurityFilter, SecurityContextHolderAwareRequestFilter.class)
.formLogin(AbstractHttpConfigurer::disable) // UsernamePasswordAuthenticationFilter, DefaultLoginPageGeneratingFilter ๋นํ์ฑํ
.anonymous(AbstractHttpConfigurer::disable) // AnonymousAuthenticationFilter ๋นํ์ฑํ
.httpBasic(AbstractHttpConfigurer::disable) // BasicAuthenticationFilter ๋นํ์ฑํ
.logout(AbstractHttpConfigurer::disable) // LogoutFilter ๋นํ์ฑํ
.exceptionHandling(exception -> exception
.authenticationEntryPoint(jwtAuthEntryPoint) // EntryPoint ๋ฑ๋ก
)
.authorizeHttpRequests(auth -> auth
// โ
์ฝ๋ ์ถ๊ฐ
.requestMatchers("/swagger",
"/swagger-ui.html",
"/swagger-ui/**",
"/api-docs",
"/api-docs/**",
"/v3/api-docs/**")
.permitAll()
.requestMatchers(
"/api/users/register",
"/api/users/login",
"/api/auth/refresh"
)
.permitAll()
.anyRequest().authenticated()
)
.build();
}
์ฒจ๋ถํ์ผ๊ณผ ๊ฒ์๊ธ ๋ฐ์ดํฐ๋ฅผ ๊ฐ์ด ์ ์ฅํด์ผํ๋ ๋ถ๋ถ์ด ์กด์ฌํ๋๋ฐ, swagger์์ json๊ฐ์ ์ธ์ํ์ง ๋ชปํด์ ์ค๋ฅ๊ฐ ๋ฌ๋ค.
ํ์ธํด๋ณธ ๊ฒฐ๊ณผ swagger UI๋ @RequestPart
ํ๋์ JSON๊ฐ์ ์ ๋๋ก ์ฒ๋ฆฌํ์ง ๋ชปํ๋ ๋ฌธ์ ๊ฐ ์กด์ฌํ๋ค๋ ๊ฒ์ ์์๋ค.
๊ทธ๋์ ๊ธฐ์กด requestDto ๊ฐ์ ๊ทธ๋๋ก ๋ฐ์๋ ๊ฒ์ String
ํํ๋ก ๋จผ์ ๋ฐ์ ํ ์๋์ผ๋ก requestDto๋ก ๋ณํํ๋ ๋ฐฉ์์ผ๋ก ํด๊ฒฐํ๋ค.
๐ ๊ธฐ์กด ์ฝ๋)
@PostMapping("/api/boards")
public ResponseEntity<ResponseDto<BoardResponseDto>> save(
@UserSession AuthUsers authUsers, @RequestPart("board") BoardSaveRequestDto dto,
@RequestPart(value = "file") MultipartFile file
) {
return ResponseEntity.ok(boardService.save(authUsers, dto, file));
}
๐ ์์ ์ฝ๋)
// MULTIPART_FORM_DATA ํ์์ผ๋ก ๋ฐ๊ธฐ
@PostMapping(value = "/api/boards", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
public ResponseEntity<ResponseDto<BoardResponseDto>> save(
@Parameter(hidden = true) @UserSession AuthUsers authUsers,
@RequestPart("board") @io.swagger.v3.oas.annotations.media.Schema(type = "string" , example = "{\"title\" : \"์ ๋ชฉ\" , \"content\" : \"๋ด์ฉ\" , \"visibilityType\" : 1}")
String boardJson, // String์ผ๋ก ๋ฐ๊ธฐ
@RequestPart(value = "file", required = false) MultipartFile file
) {
try {
// JSON์ BoardSaveRequestDto๋ก ๋ณํ
BoardSaveRequestDto dto = objectMapper.readValue(boardJson, BoardSaveRequestDto.class);
return ResponseEntity.ok(boardService.save(authUsers, dto, file));
} catch (Exception e) {
return ResponseEntity.badRequest().build();
}
}
@UserSession
์ด๋
ธํ
์ด์
์ requestBody
๋ก ์ธ์ํ์ฌ swagger์์ ๋ณด์ด์ง ์๋๋ก ๋ณ๊ฒฝ์ฌ์ฉ ์ | ์ฌ์ฉ ํ |
---|---|
![]() | ![]() |
์ฌ์ฉ ์ | ์ฌ์ฉ ํ |
---|---|
![]() | ![]() |