diff --git a/gateway-service/src/main/java/com/comatching/gateway/filter/AuthorizationHeaderFilter.java b/gateway-service/src/main/java/com/comatching/gateway/filter/AuthorizationHeaderFilter.java index 1930d87..3890ba8 100644 --- a/gateway-service/src/main/java/com/comatching/gateway/filter/AuthorizationHeaderFilter.java +++ b/gateway-service/src/main/java/com/comatching/gateway/filter/AuthorizationHeaderFilter.java @@ -60,14 +60,21 @@ public GatewayFilter apply(Config config) { try { Claims claims = jwtUtil.parseToken(accessToken); ServerHttpRequest.Builder requestBuilder = request.mutate() - .header("X-Member-Id", claims.getSubject()) - .header("X-Member-Email", claims.get("email", String.class)) - .header("X-Member-Role", claims.get("role", String.class)); + .headers(headers -> { + headers.remove("X-Member-Id"); + headers.remove("X-Member-Email"); + headers.remove("X-Member-Role"); + headers.remove("X-Member-Nickname"); + + headers.set("X-Member-Id", claims.getSubject()); + headers.set("X-Member-Email", claims.get("email", String.class)); + headers.set("X-Member-Role", claims.get("role", String.class)); + }); String nickname = claims.get("nickname", String.class); if (nickname != null && !nickname.isBlank()) { - nickname = URLEncoder.encode(nickname, StandardCharsets.UTF_8); - requestBuilder.header("X-Member-Nickname", nickname); + String encodedNickname = URLEncoder.encode(nickname, StandardCharsets.UTF_8); + requestBuilder.headers(headers -> headers.set("X-Member-Nickname", encodedNickname)); } return chain.filter(exchange.mutate().request(requestBuilder.build()).build()); @@ -101,4 +108,4 @@ private Mono onError(ServerWebExchange exchange, ErrorCode errorCode) { return response.setComplete(); } } -} \ No newline at end of file +} diff --git a/gateway-service/src/main/resources/application-aws.yml b/gateway-service/src/main/resources/application-aws.yml index e543e84..570fd56 100644 --- a/gateway-service/src/main/resources/application-aws.yml +++ b/gateway-service/src/main/resources/application-aws.yml @@ -18,7 +18,7 @@ spring: - "https://comatching.site" - "http://localhost:3000" - "http://localhost:5173" - allowedMethods: [GET, POST, PUT, DELETE, OPTIONS] + allowedMethods: [GET, POST, PUT, PATCH, DELETE, OPTIONS] allowedHeaders: "*" allowCredentials: true diff --git a/gateway-service/src/main/resources/application.yml b/gateway-service/src/main/resources/application.yml index 411d086..11c633d 100644 --- a/gateway-service/src/main/resources/application.yml +++ b/gateway-service/src/main/resources/application.yml @@ -18,7 +18,7 @@ spring: - "http://localhost:3000" - "http://localhost:5173" - "http://localhost:5500" - allowedMethods: [GET, POST, PUT, DELETE, OPTIONS] + allowedMethods: [GET, POST, PUT, PATCH, DELETE, OPTIONS] allowedHeaders: "*" allowCredentials: true diff --git a/gateway-service/src/test/java/com/comatching/gateway/filter/AuthorizationHeaderFilterTest.java b/gateway-service/src/test/java/com/comatching/gateway/filter/AuthorizationHeaderFilterTest.java new file mode 100644 index 0000000..f1f0b69 --- /dev/null +++ b/gateway-service/src/test/java/com/comatching/gateway/filter/AuthorizationHeaderFilterTest.java @@ -0,0 +1,60 @@ +package com.comatching.gateway.filter; + +import static org.assertj.core.api.Assertions.assertThat; + +import java.util.concurrent.atomic.AtomicReference; + +import org.junit.jupiter.api.Test; +import org.springframework.cloud.gateway.filter.GatewayFilter; +import org.springframework.http.HttpCookie; +import org.springframework.http.server.reactive.ServerHttpRequest; +import org.springframework.mock.http.server.reactive.MockServerHttpRequest; +import org.springframework.mock.web.server.MockServerWebExchange; + +import com.comatching.common.util.JwtUtil; +import com.fasterxml.jackson.databind.ObjectMapper; + +import reactor.core.publisher.Mono; + +class AuthorizationHeaderFilterTest { + + private static final String SECRET_KEY = + "c2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQtc2lsdmVybmluZS10ZWNoLXNwcmluZy1ib290LWp3dC10dXRvcmlhbC1zZWNyZXQK"; + + private final JwtUtil jwtUtil = new JwtUtil(SECRET_KEY, 3600000L, 3600000L); + private final AuthorizationHeaderFilter filter = new AuthorizationHeaderFilter(jwtUtil, new ObjectMapper()); + + @Test + void shouldReplaceClientMemberHeadersWithTokenClaims() { + String accessToken = jwtUtil.createAccessToken( + 1L, + "admin@comatching.com", + "ROLE_ADMIN", + "ACTIVE", + "관리자" + ); + MockServerHttpRequest request = MockServerHttpRequest.get("/api/v1/admin/users") + .cookie(new HttpCookie("accessToken", accessToken)) + .header("X-Member-Id", "999") + .header("X-Member-Email", "user@comatching.com") + .header("X-Member-Role", "ROLE_USER") + .header("X-Member-Nickname", "stale") + .build(); + MockServerWebExchange exchange = MockServerWebExchange.from(request); + AtomicReference downstreamRequest = new AtomicReference<>(); + GatewayFilter gatewayFilter = filter.apply(new AuthorizationHeaderFilter.Config()); + + gatewayFilter.filter(exchange, filteredExchange -> { + downstreamRequest.set(filteredExchange.getRequest()); + return Mono.empty(); + }).block(); + + ServerHttpRequest mutatedRequest = downstreamRequest.get(); + assertThat(mutatedRequest.getHeaders().get("X-Member-Id")).containsExactly("1"); + assertThat(mutatedRequest.getHeaders().get("X-Member-Email")).containsExactly("admin@comatching.com"); + assertThat(mutatedRequest.getHeaders().get("X-Member-Role")).containsExactly("ROLE_ADMIN"); + assertThat(mutatedRequest.getHeaders().get("X-Member-Nickname")).containsExactly( + "%EA%B4%80%EB%A6%AC%EC%9E%90" + ); + } +}