html
Spring Boot RESTful API์์ Swagger์ JWT ํตํฉ: ์ข ํฉ ๊ฐ์ด๋
๋ชฉ์ฐจ
- ์๊ฐ
- Swagger ์ดํดํ๊ธฐ
- JWT (JSON Web Tokens) ์๊ฐ
- Spring Boot์์ Swagger ์ค์ ํ๊ธฐ
- JWT ์ธ์ฆ ๊ตฌํ
- Swagger UI ์ฌ์ฉ์ ์ง์
- Swagger๋ก API ํ ์คํธํ๊ธฐ
- ๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๋ณด์ ๊ณ ๋ ค ์ฌํญ
- ๊ฒฐ๋ก
์๊ฐ
ํ๋ ์น ๊ฐ๋ฐ ๋ถ์ผ์์ ์์ ํ๊ณ ์ ๋ฌธ์ํ๋ API๋ฅผ ๋ง๋๋ ๊ฒ์ ๋งค์ฐ ์ค์ํฉ๋๋ค. ์ด ์ ์์ฑ ์ Swagger์ JWT (JSON Web Tokens)๋ฅผ Spring Boot RESTful API์ ํตํฉํ๋ ๋ฐฉ๋ฒ์ ์์ธํ ๋ค๋ฃน๋๋ค. API ๋ฌธ์ํ๋ฅผ ์ํด Swagger๋ฅผ ํ์ฉํ๊ณ ์ธ์ฆ์ ์ํด JWT๋ฅผ ์ฌ์ฉํจ์ผ๋ก์จ, ๊ฐ๋ฐ์๋ค์ ๊ฒฌ๊ณ ํ๊ณ ์์ ํ๋ฉฐ ์ ์ง ๊ด๋ฆฌ๊ฐ ์ฉ์ดํ ์ ํ๋ฆฌ์ผ์ด์ ์ ๊ตฌ์ถํ ์ ์์ต๋๋ค. ์ด ๊ฐ์ด๋๋ ์ด๋ณด์์ ๊ธฐ๋ณธ ์ง์์ ๊ฐ์ง ๊ฐ๋ฐ์๋ฅผ ์ํด ๋ง์ถคํ๋์ด ์์ผ๋ฉฐ, ๋ช ํํ๊ณ ๊ฐ๊ฒฐํ ์ง์นจ๊ณผ ์ค์ฉ์ ์ธ ์์ ๋ฅผ ์ ๊ณตํฉ๋๋ค.
Swagger ์ดํดํ๊ธฐ
Swagger๋ ๋ฌด์์ธ๊ฐ?
Swagger๋ RESTful ์น ์๋น์ค๋ฅผ ์ค๊ณ, ๊ตฌ์ถ, ๋ฌธ์ํ ๋ฐ ์๋นํ๋ ๋ฐ ๋์์ ์ฃผ๋ ์คํ ์์ค ํ๋ ์์ํฌ์ ๋๋ค. ๊ตฌํ ๋ก์ง ์์ด API์ ๋ฆฌ์์ค๋ฅผ ์๊ฐํํ๊ณ ์ํธ ์์ฉํ ์ ์๋ ์ฌ์ฉ์ ์นํ์ ์ธ ์ธํฐํ์ด์ค๋ฅผ ์ ๊ณตํฉ๋๋ค.
Swagger์ ์ฃผ์ ๊ธฐ๋ฅ
- API ๋ฌธ์ํ: ์๋์ผ๋ก ๋ํํ ๋ฌธ์๋ฅผ ์์ฑํฉ๋๋ค.
- API ํ ์คํธ: UI์์ ์ง์ ์๋ํฌ์ธํธ๋ฅผ ํ ์คํธํ ์ ์๋๋ก ๋์์ค๋๋ค.
- ์คํค๋ง ์ ์: ์์ฒญ ๋ฐ ์๋ต์ ์ํ ๋ฐ์ดํฐ ๋ชจ๋ธ๊ณผ ๊ตฌ์กฐ๋ฅผ ์ ์ํฉ๋๋ค.
API ๊ฐ๋ฐ์์ Swagger์ ์ค์์ฑ
Swagger๋ ๋ช ํํ ๋ฌธ์๋ฅผ ์ ๊ณตํ์ฌ ํ์ ๊ณผ ์ ์ง ๊ด๋ฆฌ๋ฅผ ์ฉ์ดํ๊ฒ ํจ์ผ๋ก์จ ๊ฐ๋ฐ ์ํฌํ๋ก์ฐ๋ฅผ ํฅ์์ํต๋๋ค. API ์๋ํฌ์ธํธ์ ๊ทธ ๊ธฐ๋ฅ์ ์ดํดํ๋ ๊ณผ์ ์ ๋จ์ํํฉ๋๋ค.
JWT (JSON Web Tokens) ์๊ฐ
JWT๋ ๋ฌด์์ธ๊ฐ?
JWT (JSON Web Token)์ ๋ ๋น์ฌ์ ๊ฐ์ ์ ์ก๋ ํด๋ ์์ ํํํ๋ ์ปดํฉํธํ๊ณ URL-์์ ํ ์๋จ์ ๋๋ค. ์น ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ์ ๋๋ฆฌ ์ฌ์ฉ๋ฉ๋๋ค.
JWT์ ์ฃผ์ ๊ตฌ์ฑ ์์
- ํค๋: ํ ํฐ์ ์ ํ๊ณผ ์๋ช ์๊ณ ๋ฆฌ์ฆ์ ํฌํจํ๋ ๋ฉํ๋ฐ์ดํฐ๋ฅผ ๋ด๊ณ ์์ต๋๋ค.
- ํ์ด๋ก๋: ์ฌ์ฉ์ ๋๋ ์ํฐํฐ์ ๋ํ ํด๋ ์ ๋๋ ์ง์ ์ ๋ด๊ณ ์์ต๋๋ค.
- ์๋ช : ํ ํฐ์ด ๋ณ๊ฒฝ๋์ง ์์์์ ๊ฒ์ฆํ์ฌ ํ ํฐ์ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํฉ๋๋ค.
JWT ์ฌ์ฉ์ ์ฅ์
- ๋ฌด์ํ ์ธ์ฆ: ์๋ฒ ์ธก ์ธ์ ์ ํ์์ฑ์ ์์ฑ๋๋ค.
- ํ์ฅ์ฑ: ๋ถ์ฐ ์์คํ ๋ฐ ๋ง์ดํฌ๋ก์๋น์ค์ ์ ํฉํฉ๋๋ค.
- ๋ณด์: ๋ง๋ฃ ์๊ฐ์ด ์๋ ์ฌ์ฉ์ ์ ๋ณด๋ฅผ ์์ ํ๊ฒ ์ธ์ฝ๋ฉํฉ๋๋ค.
Spring Boot์์ Swagger ์ค์ ํ๊ธฐ
ํ์ ์กฐ๊ฑด
- Spring Boot์ ๋ํ ๊ธฐ๋ณธ ์ง์.
- Java Development Kit (JDK) ์ค์น.
- Maven ๋๋ Gradle ๋น๋ ๋๊ตฌ.
๋จ๊ณ๋ณ ํตํฉ
- Swagger ์์กด์ฑ ์ถ๊ฐ
1 2 3 4 5 6 7 8 |
// pom.xml <dependencies> <dependency> <groupId>io.springfox</groupId> <artifactId>springfox-boot-starter</artifactId> <version>3.0.0</version> </dependency> </dependencies> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
// SwaggerConfig.java package com.example.demo.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import springfox.documentation.builders.PathSelectors; import springfox.documentation.builders.RequestHandlerSelectors; import springfox.documentation.spi.DocumentationType; import springfox.documentation.spring.web.plugins.Docket; @Configuration public class SwaggerConfig { @Bean public Docket api() { return new Docket(DocumentationType.OAS_30) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo")) .paths(PathSelectors.any()) .build(); } } |
Spring Boot ์ ํ๋ฆฌ์ผ์ด์ ์ ์์ํ๊ณ http://localhost:8080/swagger-ui/๋ก ์ด๋ํ์ฌ ๋ํํ API ๋ฌธ์๋ฅผ ํ์ธํ์ญ์์ค.
JWT ์ธ์ฆ ๊ตฌํ
์ JWT๋ฅผ ์ฌ์ฉํ๋๊ฐ?
JWT๋ ๋ฌด์ํ ์ ํ๋ฆฌ์ผ์ด์ ์์ ์ธ์ฆ ๋ฐ ๊ถํ ๋ถ์ฌ๋ฅผ ์ฒ๋ฆฌํ๋ ์์ ํ๊ณ ํจ์จ์ ์ธ ๋ฐฉ๋ฒ์ ์ ๊ณตํฉ๋๋ค. ์๋ฒ ์ธก ์ธ์ ์ ์ ์งํ์ง ์๊ณ ๊ฐ ์์ฒญ์ด ์ธ์ฆ๋๋๋ก ๋ณด์ฅํฉ๋๋ค.
Spring Boot์์ JWT ์ค์
- JWT ์์กด์ฑ ์ถ๊ฐ
1 2 3 4 5 6 7 8 |
// pom.xml <dependencies> <dependency> <groupId>io.jsonwebtoken</groupId> <artifactId>jjwt</artifactId> <version>0.9.1</version> </dependency> </dependencies> |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 |
// JwtUtil.java package com.example.demo.util; import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; import org.springframework.stereotype.Component; import java.util.Date; import java.util.HashMap; import java.util.Map; import java.util.function.Function; @Component public class JwtUtil { private String SECRET_KEY = "secret"; public String extractUsername(String token) { return extractClaim(token, Claims::getSubject); } public Date extractExpiration(String token) { return extractClaim(token, Claims::getExpiration); } public <T> T extractClaim(String token, Function<Claims, T> claimsResolver) { final Claims claims = extractAllClaims(token); return claimsResolver.apply(claims); } private Claims extractAllClaims(String token) { return Jwts.parser().setSigningKey(SECRET_KEY).parseClaimsJws(token).getBody(); } private Boolean isTokenExpired(String token) { return extractExpiration(token).before(new Date()); } public String generateToken(String username) { Map<String, Object> claims = new HashMap<>(); return createToken(claims, username); } private String createToken(Map<String, Object> claims, String subject) { return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) .signWith(SignatureAlgorithm.HS256, SECRET_KEY).compact(); } public Boolean validateToken(String token, String username) { final String extractedUsername = extractUsername(token); return (extractedUsername.equals(username) && !isTokenExpired(token)); } } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 |
// AuthController.java package com.example.demo.controller; import com.example.demo.util.JwtUtil; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.*; @RestController public class AuthController { @Autowired private JwtUtil jwtUtil; @PostMapping("/token") public ResponseEntity<?> generateToken(@RequestBody AuthRequest authRequest) { // ์ฌ์ฉ์ ์ธ์ฆ String token = jwtUtil.generateToken(authRequest.getUsername()); return ResponseEntity.ok(new AuthResponse(token)); } } // AuthRequest.java package com.example.demo.controller; public class AuthRequest { private String username; private String password; // Getters and Setters } // AuthResponse.java package com.example.demo.controller; public class AuthResponse { private final String token; public AuthResponse(String token) { this.token = token; } public String getToken() { return token; } } |
Swagger UI ์ฌ์ฉ์ ์ง์
์ ํ๋ฆฌ์ผ์ด์ ์ ๋ณด ์ ๋ฐ์ดํธ
์ ํ๋ฆฌ์ผ์ด์ ์ด๋ฆ, ๋ฒ์ ๋ฐ ์ค๋ช ๊ณผ ๊ฐ์ ์ ํ๋ฆฌ์ผ์ด์ ๋ณ ์ธ๋ถ ์ ๋ณด๋ฅผ ์ฌ์ฉํ์ฌ Swagger UI๋ฅผ ์ฌ์ฉ์ ์ง์ ํ ์ ์์ต๋๋ค.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 |
// SwaggerConfig.java @Bean public Docket api() { return new Docket(DocumentationType.OAS_30) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo")) .paths(PathSelectors.any()) .build() .apiInfo(apiInfo()); } private ApiInfo apiInfo() { return new ApiInfo( "User API", "Spring Boot RESTful API Demo", "1.0", "์๋น์ค ์ฝ๊ด", "API ๋ผ์ด์ ์ค", "API ๋ผ์ด์ ์ค URL", Collections.emptyList()); } |
Swagger์ ์ธ์ฆ ์ถ๊ฐ
Swagger UI๋ API ์์ฒญ์ ์ธ์ฆ ํค๋๋ฅผ ์ถ๊ฐํ ์ ์์ด ์ธ์ฆ๋ ํ ์คํธ๋ฅผ ๊ฐ๋ฅํ๊ฒ ํฉ๋๋ค.
- ๋ณด์ ์คํค๋ง ๊ตฌ์ฑ
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// SwaggerConfig.java @Bean public Docket api() { return new Docket(DocumentationType.OAS_30) .securitySchemes(Arrays.asList(apiKey())) .select() .apis(RequestHandlerSelectors.basePackage("com.example.demo")) .paths(PathSelectors.any()) .build(); } private ApiKey apiKey() { return new ApiKey("JWT", "Authorization", "header"); } |
- Swagger UI์์ "Authorize" ๋ฒํผ์ ํด๋ฆญํฉ๋๋ค.
Bearer
์ ๋์ฌ๊ฐ ์๋ JWT ํ ํฐ์ ์ ๋ ฅํฉ๋๋ค (์:Bearer your_jwt_token
).- ์ธ์ฆ๋๋ฉด Swagger๋ ์ดํ์ API ์์ฒญ์ ํ ํฐ์ ํฌํจํฉ๋๋ค.
Swagger๋ก API ํ ์คํธํ๊ธฐ
์ธ์ฆ๋ ์์ฒญ ๋ง๋ค๊ธฐ
- JWT ํ ํฐ ์์ฑ
- ์ ํจํ ์๊ฒฉ ์ฆ๋ช
์ ์ฌ์ฉํ์ฌ
/token
์๋ํฌ์ธํธ๋ฅผ ์ฌ์ฉํ๋ฉด JWT๋ฅผ ๋ฐ์ ์ ์์ต๋๋ค. - Swagger UI ์ธ์ฆ
- "Authorize"๋ฅผ ํด๋ฆญํ๊ณ ์์ ์ค๋ช ํ ๋๋ก ํ ํฐ์ ์ ๋ ฅํฉ๋๋ค.
- ๋ณดํธ๋ ์๋ํฌ์ธํธ ์ ๊ทผ
- ์ธ์ฆ์ด ์ค์ ๋๋ฉด Swagger UI์์ ์ง์ ๋ณด์๋ API์ ์ ๊ทผํ ์ ์์ต๋๋ค.
์ํ ํ๋ก๊ทธ๋จ ์ฝ๋
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
// SampleController.java package com.example.demo.controller; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class SampleController { @GetMapping("/homepage") public String homepage() { return "homepage"; } } |
์ค๋ช
- ์๋ํฌ์ธํธ:
/homepage
- ๋ฉ์๋: GET
- ์ค๋ช : ๊ฐ๋จํ ์ธ์ฌ๋ฅผ ๋ฐํํฉ๋๋ค.
ํ๋ก๊ทธ๋จ ์ถ๋ ฅ
http://localhost:8080/homepage์ ์ ๊ทผํ๋ฉด ๋ค์๊ณผ ๊ฐ์ ์๋ต์ด ํ์๋ฉ๋๋ค:
1 |
homepage |
๋ชจ๋ฒ ์ฌ๋ก ๋ฐ ๋ณด์ ๊ณ ๋ ค ์ฌํญ
JWT ๋น๋ฐํค์ ์์ ํ ์ ์ฅ
JWT ์๋ช ์ ์ํ ๋น๋ฐํค๋ ์ฝ๋๋ฒ ์ด์ค์ ๋ ธ์ถ๋์ง ์๋๋ก ์์ ํ๊ฒ ์ ์ฅํด์ผ ํฉ๋๋ค. ํ๊ฒฝ ๋ณ์๋ ๋ณด์ ๊ธ๊ณ ๋ฅผ ์ฌ์ฉํ์ญ์์ค.
ํ ํฐ ๋ง๋ฃ ์ค์
JWT์ ๋ง๋ฃ ์๊ฐ์ ํญ์ ์ค์ ํ์ฌ ํ ํฐ ๋๋ ๋ฐ ๋จ์ฉ์ ์ํ์ ์ต์ํํ์ญ์์ค.
HTTPS ์ฌ์ฉ
๋ชจ๋ API ํต์ ์ด HTTPS๋ฅผ ํตํด ์ด๋ฃจ์ด์ง๋๋ก ํ์ฌ ์ ์ก ์ค์ธ ๋ฐ์ดํฐ๋ฅผ ๋ณดํธํ์ญ์์ค.
ํ ํฐ ํด๋ ์ ๊ฒ์ฆ
JWT ๋ด์ ํด๋ ์(์: ๋ฐ๊ธ์, ๋์, ๋ง๋ฃ)์ ํญ์ ๊ฒ์ฆํ์ฌ ํ ํฐ์ ๋ฌด๊ฒฐ์ฑ์ ๋ณด์ฅํ์ญ์์ค.
์์กด์ฑ ์ ๊ธฐ ์ ๋ฐ์ดํธ
Swagger, JWT ๋ผ์ด๋ธ๋ฌ๋ฆฌ ๋ฐ ๊ธฐํ ์์กด์ฑ์ ์ต์ ์ํ๋ก ์ ์งํ์ฌ ์๋ ค์ง ์ทจ์ฝ์ ์ ํจ์นํ์ญ์์ค.
๊ฒฐ๋ก
Swagger์ JWT๋ฅผ Spring Boot RESTful API์ ํตํฉํจ์ผ๋ก์จ ๊ฒฌ๊ณ ํ ๋ฌธ์ํ์ ์์ ํ ์ธ์ฆ ๋ฉ์ปค๋์ฆ์ ์ ๊ณตํ์ฌ ๊ฐ๋ฐ ํ๋ก์ธ์ค๋ฅผ ํฌ๊ฒ ํฅ์์ํฌ ์ ์์ต๋๋ค. Swagger๋ API ํ์ ๋ฐ ํ ์คํธ๋ฅผ ๋จ์ํํ๊ณ , JWT๋ ํ์ฅ ๊ฐ๋ฅํ ์ ํ๋ฆฌ์ผ์ด์ ์ ์ ํฉํ ์์ ํ๊ณ ๋ฌด์ํ ์ธ์ฆ์ ๋ณด์ฅํฉ๋๋ค. ์ด ์ ์์ฑ ์ ์ค๋ช ๋ ์ง์นจ๊ณผ ๋ชจ๋ฒ ์ฌ๋ก๋ฅผ ๋ฐ๋ฅด๋ฉด ๊ฐ๋ฐ์๋ค์ ํ์ฌ์ ๋ฏธ๋์ ์๊ตฌ๋ฅผ ์ถฉ์กฑํ๋ ์์ ํ๊ณ ์ ๋ฌธ์ํ๋ API๋ฅผ ๊ตฌ์ถํ ์ ์์ต๋๋ค.
ํค์๋: Swagger, JWT, Spring Boot, RESTful API, API Documentation, JSON Web Token, Authentication, Authorization, Springfox, API Security, OpenAPI, Microservices, Stateless Authentication, Secure APIs
์ฐธ๊ณ : ์ด ๊ธฐ์ฌ๋ AI์ ์ํด ์์ฑ๋์์ต๋๋ค.