지난 포스팅에서는 Spring Security와 JWT를 도입하여 사용자가 누구인지 확인하는 '인증(Authentication)' 기능을 구현했습니다.
이번 포스팅에서는 인증된 사용자가 특정 작업을 수행할 '권한'이 있는지 확인하는 '인가(Authorization)' 로직을 최종 테스트하고, 다른 개발자들과의 협업을 위해 Swagger(Springdoc)로 API 문서를 자동화하는 과정을 다뤄보겠습니다.
### 1. 인가(Authorization) 로직 최종 테스트 🛡️
PostService에는 "게시글 작성자 본인만 해당 게시글을 수정/삭제할 수 있다"는 비즈니스 로직을 이미 구현해 두었습니다. 이제 이 권한 확인 로직이 실제로 잘 동작하는지 Postman을 통해 시나리오 테스트를 진행했습니다.
#### 테스트 시나리오
- 사용자 A, B 생성: POST /api/users/signup API를 호출하여 userA와 userB를 각각 생성합니다.
- 사용자 A 로그인 및 게시글 작성:
- userA로 로그인하여 토큰(A-Token)을 발급받습니다.
- Authorization 헤더에 A-Token을 넣고 POST /api/posts를 호출하여 새 게시글을 작성합니다. (이때 생성된 게시글 ID가 1이라고 가정)
- 사용자 B 로그인: userB로 로그인하여 토큰(B-Token)을 발급받습니다.
- 타인의 글 삭제 시도:
- DELETE /api/posts/1 API를 호출합니다.
- Authorization 헤더에는 **userB의 토큰(B-Token)**을 넣습니다.
테스트 결과
예상대로, 서버는 403 Forbidden 응답을 반환했습니다! IntelliJ 콘솔에는 우리가 PostService에 설정해 둔 IllegalStateException: 게시글을 삭제할 권한이 없습니다. 로그가 찍혔습니다.
이것으로 우리가 구현한 인가 로직이 완벽하게 동작함을 확인했습니다.
### 2. API 문서화 with Swagger (Springdoc) 📖
프로젝트의 기능 구현을 마쳤다면, 다른 개발자(특히 프론트엔드)와의 협업을 위해 API 명세를 문서화하는 작업이 필수적입니다. **Swagger(스웨거)**는 우리가 작성한 컨트롤러 코드를 분석하여, API 명세를 웹 페이지로 자동 생성하고 직접 테스트까지 해볼 수 있는 강력한 도구입니다.
스프링 부트 환경에서는 Springdoc이라는 라이브러리를 통해 Swagger를 매우 간단하게 적용할 수 있습니다.
#### Q&A: Swagger? Springdoc? 뭐가 다른가요?
- Swagger UI: API 문서를 보여주는 '웹 페이지' 그 자체입니다.
- OpenAPI: API 명세를 정의하는 **'표준 규칙(시나리오)'**입니다.
- Springdoc: 우리 코드를 분석해 OpenAPI 문서를 **'자동 생성'**하고 Swagger UI를 **'내장'**하는 라이브러리입니다.
즉, 우리는 Springdoc 라이브러리 하나만 추가하면, OpenAPI 규칙에 맞는 API 문서가 자동으로 생성되고, 그것을 Swagger UI라는 멋진 웹 페이지로 볼 수 있게 되는 것입니다.
또한 Swagger(OpenAPI) 문서를 만드는 방법은 크게 두 가지로, '코드 우선(Code-First)' 방식과 '설계 우선(Design-First)' 방식으로 나뉩니다.
### 1단계: 의존성 추가
build.gradle 파일에 Springdoc 라이브러리 의존성을 한 줄 추가합니다.
implementation 'org.springdoc:springdoc-openapi-starter-webmvc-ui:2.8.13'
이것만으로 기본 설정은 끝입니다! 이제 서버를 실행하고 http://localhost:8080/swagger-ui/index.html에 접속하면, 잘 정리된 API 문서를 확인하고 직접 테스트까지 해볼 수 있습니다.
그러나 처음엔 접속을 하면 오류가 뜹니다. 우리는 지금 Spring Security를 사용하고 있으므로 접근을 허용해줘야 접속이 가능합니다.
### 2단계: SecurityConfig 수정 (접근 허용)
Spring Security는 기본적으로 모든 경로를 보호하므로, Swagger UI 페이지에 접근할 수 있도록 경로를 열어주어야 합니다.
SecurityConfig.java의 filterChain 메서드를 수정합니다.
// SecurityConfig.java
@Bean
public SecurityFilterChain filterChain(HttpSecurity http) throws Exception {
http
// ... (csrf, sessionManagement 설정) ...
.authorizeHttpRequests(authorize -> authorize
// 기존의 회원가입, 로그인 경로 허용
.requestMatchers("/api/users/signup", "/api/users/login").permitAll()
// 👇 Swagger UI 관련 경로들도 모두 허용 👇
.requestMatchers("/swagger-ui/**", "/v3/api-docs/**").permitAll()
// 나머지 모든 요청은 인증 필요
.anyRequest().authenticated()
);
// ... (addFilterBefore 설정) ...
return http.build();
}
그런 후 다시 접속해보면


이러면 API들을 확인하거나 기본적인 로그인을 통한 토큰 얻기 테스트 등은 가능합니다. 하지만 인증이 필요한 API 메소드들은 지금 실행하지 못합니다. 인증할 방법이 없기 때문입니다. 이를 추가해주기 위해 3단계를 진행합니다.
### 3단계: SwaggerConfig 설정 (JWT 인증 버튼 추가)
Swagger UI 페이지에서 JWT 토큰을 입력하여 인증이 필요한 API를 테스트하려면, 'Authorize' 버튼을 활성화해야 합니다. config 패키지에 SwaggerConfig.java 파일을 생성하고 아래 코드를 작성합니다.
// SwaggerConfig.java
@Configuration
public class SwaggerConfig {
@Bean
public OpenAPI openAPI() {
Info info = new Info()
.version("v1.0.0")
.title("커뮤니티 게시판 API")
.description("API 명세서");
// JWT 인증 방식을 위한 SecurityScheme 설정
String jwtSchemeName = "jwtAuth";
SecurityRequirement securityRequirement = new SecurityRequirement().addList(jwtSchemeName);
Components components = new Components()
.addSecuritySchemes(jwtSchemeName, new SecurityScheme()
.name(jwtSchemeName)
.type(SecurityScheme.Type.HTTP) // HTTP 방식
.scheme("bearer")
.bearerFormat("JWT")); // Bearer 토큰 방식
return new OpenAPI()
.info(info)
.addSecurityItem(securityRequirement)
.components(components);
}
}
이 설정 파일을 추가하고 서버를 재시작하니, 드디어 Swagger UI 페이지 오른쪽 상단에 Authorize 버튼이 나타났습니다!

### 4단계: API에 상세 설명 추가하기 (선택 사항)
API 문서의 가독성을 높이기 위해, 컨트롤러 코드에 Swagger 어노테이션을 추가할 수 있습니다.
- @Tag: 컨트롤러 그룹의 이름과 설명을 설정합니다.
- @Operation: 각 API의 제목과 상세 설명을 추가합니다.
- @ApiResponse: API의 성공/실패 응답 코드를 명시합니다.
- @Parameter: 파라미터에 대한 설명을 추가합니다.
// PostController.java 예시
@Tag(name = "게시글 API", description = "게시글 관련 API")
@RestController
@RequestMapping("/api/posts")
public class PostController {
// ...
@Operation(summary = "게시글 작성", description = "새로운 게시글을 작성합니다.")
@ApiResponse(responseCode = "201", description = "게시글 작성 성공")
@PostMapping
public ResponseEntity<Long> createPost(...) {
// ...
}
//...
}
그 외에 UserController와 CommentController도 작성해줍니다.

### 5단계: Swagger UI로 인증 테스트
-
- 먼저 Authorize를 하지 않고 게시글 생성을 시도해봅니다.

실패
- 먼저 Authorize를 하지 않고 게시글 생성을 시도해봅니다.
- user-controller의 POST /api/users/login을 실행하여 JWT 토큰을 발급받습니다.

- Authorize 버튼을 눌러, Bearer [복사한_토큰] 형식으로 토큰을 등록합니다.
- post-controller의 POST /api/posts API를 실행하니, 201 Created 응답과 함께 게시글이 성공적으로 생성되는 것을 확인했습니다.


추가적으로 Swagger의 단점도 있는데요.
### 비판: '코드 침투(Code Intrusion)' 문제
그 영상에서 지적한 '코드 침투'란, 원래 비즈니스 로직을 처리해야 할 Controller 코드에, 부가 기능인 '문서화'를 위한 어노테이션들이 섞여 들어가는 것을 의미합니다.
- 단점:
- 객체 지향의 **'단일 책임 원칙(SRP)'**에 어긋날 수 있습니다. 컨트롤러가 '요청 처리'와 '문서 작성'이라는 두 가지 책임을 갖게 됩니다.
- 코드가 길어지고, 비즈니스 로직과 관련 없는 어노테이션들 때문에 가독성이 떨어질 수 있습니다.
이러한 비판 때문에, "API 명세는 코드와 분리하여 별도의 YAML이나 JSON 파일로 관리해야 한다"고 주장하는 '설계 우선(Design-First)' 방식도 존재합니다.
### 현실: 그럼에도 불구하고 왜 많이 사용할까?
이론적인 비판에도 불구하고, 실무에서 Springdoc 같은 어노테이션 기반의 방식을 압도적으로 많이 사용하는 이유는 **'생산성'과 '정확성'**이 그 단점을 상쇄하고도 남기 때문입니다.
- 압도적인 생산성과 유지보수 편의성 API 명세를 별도의 파일로 관리하면, 코드가 변경될 때마다 문서 파일도 잊지 않고 사람이 직접 수정해야 합니다. API가 수십, 수백 개가 되면 이 작업은 매우 번거롭고 실수가 발생하기 쉽습니다. 하지만 어노테이션 방식은 코드 바로 위에 설명이 있으므로, 코드를 수정하면서 문서를 동시에 수정하기가 매우 편리합니다.
- '코드'가 곧 '문서' (Single Source of Truth) 어노테이션 방식의 가장 큰 장점은 코드가 항상 가장 정확한 최신 문서라는 점을 보장한다는 것입니다. 문서가 코드와 다른 내용일 가능성(e.g., 문서는 name인데 코드는 username으로 바뀜)이 원천적으로 차단됩니다
그래서 다른 API 명세 툴을 사용하는 프로그래머들도 있다고 합니다.
### 3. 프로젝트의 다음 단계: 배포(Deployment) ☁️
이것으로 백엔드 애플리케이션의 모든 기능 구현과 문서화가 끝났습니다. 이제 이 프로젝트를 포트폴리오로 완성하기 위한 마지막 단계, 클라우드 배포가 남았습니다.
다음 목표는 이 프로젝트를 Docker로 컨테이너화하고, AWS 같은 클라우드 서버에 올려서 누구나 접속할 수 있는 실제 서비스로 만드는 것입니다. 더 나아가 GitHub Actions를 이용해 git push만 하면 자동으로 테스트와 배포가 이루어지는 CI/CD 파이프라인을 구축할 수도 있습니다.
'개발 공부 > 백엔드' 카테고리의 다른 글
| 백엔드 개발자를 위한 '생존형' 자바스크립트 (Fetch API & Debugging) (0) | 2026.01.03 |
|---|---|
| 제미나이와 게시판 만들기: (8) Docker로 배포 준비하기 🐳 (0) | 2025.10.11 |
| 제미나이와 게시판 만들기: (6) Spring Security와 JWT로 인증/인가 구현하기 (0) | 2025.10.08 |
| 제미나이와 게시판 만들기: (5) Post, Comment 컨트롤러 구현 (0) | 2025.10.06 |
| 제미나이와 게시판 만들기: (4) 컨트롤러 구현과 Postman API 테스트 (0) | 2025.10.05 |