diff --git a/apigateway/build.gradle b/apigateway/build.gradle index 89a3f41..9de61af 100644 --- a/apigateway/build.gradle +++ b/apigateway/build.gradle @@ -22,12 +22,17 @@ ext { } dependencies { - implementation 'org.springframework.cloud:spring-cloud-starter-gateway-mvc' + implementation 'org.springframework.cloud:spring-cloud-starter-gateway' implementation 'org.springframework.cloud:spring-cloud-starter-netflix-eureka-client' implementation 'org.projectlombok:lombok' developmentOnly 'org.springframework.boot:spring-boot-devtools' testImplementation 'org.springframework.boot:spring-boot-starter-test' testRuntimeOnly 'org.junit.platform:junit-platform-launcher' + + // JWT 관련 의존성 + implementation "io.jsonwebtoken:jjwt:0.9.1" + implementation 'javax.xml.bind:jaxb-api:2.3.1' + } dependencyManagement { diff --git a/apigateway/src/main/java/com/cloudclub/apigateway/filter/JwtAuthenticationFilter.java b/apigateway/src/main/java/com/cloudclub/apigateway/filter/JwtAuthenticationFilter.java new file mode 100644 index 0000000..84f85b6 --- /dev/null +++ b/apigateway/src/main/java/com/cloudclub/apigateway/filter/JwtAuthenticationFilter.java @@ -0,0 +1,64 @@ +package com.cloudclub.apigateway.filter; + +import io.jsonwebtoken.Claims; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.http.HttpHeaders; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.stereotype.Component; + +@Component +public class JwtAuthenticationFilter extends AbstractGatewayFilterFactory { + + @Autowired + private JwtUtil jwtUtil; + + public JwtAuthenticationFilter() { + super(Config.class); + } + + public static class Config { + // 필터 설정이 필요한 경우 여기에 추가 + } + + @Override + public GatewayFilter apply(Config config) { + return ((exchange, chain) -> { + ServerHttpRequest request = exchange.getRequest(); + + // /login, /register 등 인증이 필요없는 경로는 패스 + if (request.getURI().getPath().contains("/login") || + request.getURI().getPath().contains("/register")) { + return chain.filter(exchange); + } + + // Authorization 헤더 확인 + if (!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) { + throw new RuntimeException("Missing authorization header"); + } + + String authHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0); + if (authHeader == null || !authHeader.startsWith("Bearer ")) { + throw new RuntimeException("Invalid authorization header"); + } + + // JWT 토큰 추출 및 검증 + String token = authHeader.substring(7); + try { + Claims claims = jwtUtil.validateToken(token); + + // 검증된 사용자 정보를 헤더에 추가 + ServerHttpRequest modifiedRequest = exchange.getRequest().mutate() + .header("Authorization", authHeader) + .header("X-User-Id", claims.getSubject()) + .header("X-User-Role", claims.get("role", String.class)) + .build(); + + return chain.filter(exchange.mutate().request(modifiedRequest).build()); + } catch (Exception e) { + throw new RuntimeException("Invalid token"); + } + }); + } +} \ No newline at end of file diff --git a/apigateway/src/main/java/com/cloudclub/apigateway/filter/JwtUtil.java b/apigateway/src/main/java/com/cloudclub/apigateway/filter/JwtUtil.java new file mode 100644 index 0000000..205a631 --- /dev/null +++ b/apigateway/src/main/java/com/cloudclub/apigateway/filter/JwtUtil.java @@ -0,0 +1,20 @@ +package com.cloudclub.apigateway.filter; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +@Component +public class JwtUtil { + + @Value("${jwt.secret}") + private String secret; + + public Claims validateToken(String token) { + return Jwts.parser() + .setSigningKey(secret) + .parseClaimsJws(token) + .getBody(); + } +} \ No newline at end of file diff --git a/apigateway/src/main/resources/application.yml b/apigateway/src/main/resources/application.yml index 2c2e18a..6e6c73e 100644 --- a/apigateway/src/main/resources/application.yml +++ b/apigateway/src/main/resources/application.yml @@ -21,4 +21,14 @@ spring: - id: openstack-service uri: http://localhost:8082/ predicates: - - Path=/openstack-service/** \ No newline at end of file + - Path=/openstack-service/** + - id: user-service + uri: http://localhost:8083/ + predicates: + - Path=/user-service/** + filters: + - RewritePath=/user-service(?.*), /$\{segment} + - JwtAuthenticationFilter + +jwt: + secret: cloudclubsecretkey123cloudclubsecretkey123cloudclubsecretkey123cloudclubsecretkey123