From 4290f53f618730bfd94aa64f65aad8cca81e6e58 Mon Sep 17 00:00:00 2001 From: seungryeol Date: Fri, 27 Oct 2023 23:00:04 +0900 Subject: [PATCH 1/4] =?UTF-8?q?[fix]=20=EC=97=90=EB=9F=AC=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=20=EC=9C=84=EC=B9=98=20=EB=B0=94=EA=BF=88?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .github/workflows/gradle.yml | 2 +- ...JwtAuthenticationGatewayFilterFactory.java | 24 ++++++++++--------- 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/.github/workflows/gradle.yml b/.github/workflows/gradle.yml index 5cbb19a..e180bc1 100644 --- a/.github/workflows/gradle.yml +++ b/.github/workflows/gradle.yml @@ -9,7 +9,7 @@ name: Java CI with Gradle on: push: - branches: [ "main" ] + branches: [ "feature_4/에러-수정" ] pull_request: branches: [ "dev" ] diff --git a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java index 803d1bf..a0603c5 100644 --- a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java +++ b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java @@ -41,6 +41,19 @@ public GatewayFilter apply(Config config) { String jwt = authorizationHeader.replace("Bearer ", ""); log.info("jwt : {}", jwt); + if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) { + return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED); + } + + if(!isJwtValid(jwt, exchange)) { + return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED); + } + + // 헤더 출력 + request.getHeaders().forEach((k, v) -> { + log.info("{} : {}", k, v); + }); + String subject = decode(jwt); request.mutate() .header("user", subject) @@ -58,18 +71,7 @@ public GatewayFilter apply(Config config) { return chain.filter(exchange); } - if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) { - return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED); - } - - if(!isJwtValid(jwt, exchange)) { - return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED); - } - // 헤더 출력 - request.getHeaders().forEach((k, v) -> { - log.info("{} : {}", k, v); - }); // Custom Post Filter return chain.filter(exchange); From 10ebbe6a65835395c6df0142bdbb4a84da612666 Mon Sep 17 00:00:00 2001 From: seungryeol Date: Fri, 27 Oct 2023 23:09:55 +0900 Subject: [PATCH 2/4] =?UTF-8?q?[fix]=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20json=EC=9C=BC=EB=A1=9C=20=ED=8C=8C?= =?UTF-8?q?=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../filter/JwtAuthenticationGatewayFilterFactory.java | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java index a0603c5..fcb91a5 100644 --- a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java +++ b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java @@ -10,14 +10,18 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.cloud.gateway.filter.GatewayFilter; import org.springframework.cloud.gateway.filter.factory.AbstractGatewayFilterFactory; +import org.springframework.core.io.buffer.DataBuffer; import org.springframework.http.HttpHeaders; import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; +import java.nio.charset.StandardCharsets; + @Component @Slf4j public class JwtAuthenticationGatewayFilterFactory extends AbstractGatewayFilterFactory { @@ -131,10 +135,14 @@ public String decode(String token) { private Mono onError(ServerWebExchange exchange, String error, HttpStatus httpStatus) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(httpStatus); + response.getHeaders().setContentType(MediaType.APPLICATION_JSON); + + String errorMessage = "{\"error\": \"" + error + "\"}"; + DataBuffer buffer = response.bufferFactory().wrap(errorMessage.getBytes(StandardCharsets.UTF_8)); log.error(error); - return response.setComplete(); + return response.writeWith(Mono.just(buffer)).then(response.setComplete()); } @Data From 859169ad8d0278070f84e17785f93e5aba7c2dfb Mon Sep 17 00:00:00 2001 From: seungryeol Date: Fri, 27 Oct 2023 23:15:17 +0900 Subject: [PATCH 3/4] =?UTF-8?q?[fix]=20=EC=97=90=EB=9F=AC=20=EB=A9=94?= =?UTF-8?q?=EC=8B=9C=EC=A7=80=20json=EC=9C=BC=EB=A1=9C=20=ED=8C=8C?= =?UTF-8?q?=EC=8B=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...JwtAuthenticationGatewayFilterFactory.java | 20 +++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java index fcb91a5..7b18cef 100644 --- a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java +++ b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java @@ -1,6 +1,8 @@ package com.example.farmusgateway.filter; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; import io.jsonwebtoken.ExpiredJwtException; import io.jsonwebtoken.JwtException; import io.jsonwebtoken.Jwts; @@ -21,6 +23,8 @@ import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; @Component @Slf4j @@ -132,19 +136,31 @@ public String decode(String token) { } // Mono, Flux -> Spring WebFlux + private Mono onError(ServerWebExchange exchange, String error, HttpStatus httpStatus) { ServerHttpResponse response = exchange.getResponse(); response.setStatusCode(httpStatus); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); - String errorMessage = "{\"error\": \"" + error + "\"}"; - DataBuffer buffer = response.bufferFactory().wrap(errorMessage.getBytes(StandardCharsets.UTF_8)); + Map errorResponse = new HashMap<>(); + errorResponse.put("error", error); + + ObjectMapper objectMapper = new ObjectMapper(); + byte[] errorResponseBytes; + try { + errorResponseBytes = objectMapper.writeValueAsBytes(errorResponse); + } catch (JsonProcessingException e) { + errorResponseBytes = "{\"error\": \"Internal Server Error\"}".getBytes(StandardCharsets.UTF_8); + } + + DataBuffer buffer = response.bufferFactory().wrap(errorResponseBytes); log.error(error); return response.writeWith(Mono.just(buffer)).then(response.setComplete()); } + @Data public static class Config { From 0bf29b84527d4148e00521be2912c98ccd4f4374 Mon Sep 17 00:00:00 2001 From: seungryeol Date: Sat, 28 Oct 2023 02:49:44 +0900 Subject: [PATCH 4/4] =?UTF-8?q?[fix]=20gateway=20=EC=97=90=EB=9F=AC=20?= =?UTF-8?q?=EB=A9=94=EC=8B=9C=EC=A7=80=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...JwtAuthenticationGatewayFilterFactory.java | 133 +++++------------- 1 file changed, 39 insertions(+), 94 deletions(-) diff --git a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java index 7b18cef..d4dd1c5 100644 --- a/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java +++ b/src/main/java/com/example/farmusgateway/filter/JwtAuthenticationGatewayFilterFactory.java @@ -19,12 +19,9 @@ import org.springframework.http.server.reactive.ServerHttpRequest; import org.springframework.http.server.reactive.ServerHttpResponse; import org.springframework.stereotype.Component; -import org.springframework.web.server.ServerWebExchange; import reactor.core.publisher.Mono; import java.nio.charset.StandardCharsets; -import java.util.HashMap; -import java.util.Map; @Component @Slf4j @@ -38,129 +35,77 @@ public JwtAuthenticationGatewayFilterFactory() { } - // login -> token -> users (with token) -> header(include token) + @Override public GatewayFilter apply(Config config) { return (exchange, chain) -> { ServerHttpRequest request = exchange.getRequest(); + ServerHttpResponse response = exchange.getResponse(); String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0); - log.info("authorizationHeader : {}", authorizationHeader); + log.info("authorizationHeader: {}", authorizationHeader); String jwt = authorizationHeader.replace("Bearer ", ""); - log.info("jwt : {}", jwt); - - if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)) { - return onError(exchange, "no authorization header", HttpStatus.UNAUTHORIZED); - } - - if(!isJwtValid(jwt, exchange)) { - return onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED); - } + log.info("jwt: {}", jwt); - // 헤더 출력 - request.getHeaders().forEach((k, v) -> { - log.info("{} : {}", k, v); - }); + try { + String subject = Jwts.parserBuilder().setSigningKey(secret).build() + .parseClaimsJws(jwt).getBody() + .getSubject(); - String subject = decode(jwt); - request.mutate() - .header("user", subject) - .build(); + if (subject == null || subject.isEmpty()) { + return onError(response, "JWT token is not valid", HttpStatus.UNAUTHORIZED); + } - log.info("request.getURI().toString() : {}", request.getURI().toString()); + String decodedSubject = decode(jwt); + request.mutate().header("user", decodedSubject).build(); - // get url after endpoint - int index = request.getURI().toString().indexOf("/api"); - String url = request.getURI().toString().substring(index); + // get url after endpoint + int index = request.getURI().toString().indexOf("/api"); + String url = request.getURI().toString().substring(index); + log.info("url: {}", url); - log.info("url : {}", url); + if (url.equals("/api/user/reissue-token")) { + return chain.filter(exchange); + } - if(url.equals("/api/user/reissue-token")) { return chain.filter(exchange); + } catch (IllegalArgumentException e) { + return onError(response, "Invalid access token header", HttpStatus.BAD_REQUEST); + } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { + return onError(response, "Verification error", HttpStatus.UNAUTHORIZED); + } catch (ExpiredJwtException e) { + return onError(response, "Token expired", HttpStatus.PRECONDITION_FAILED); + } catch (JwtException e) { + return onError(response, "JWT error", HttpStatus.UNAUTHORIZED); } - - - - // Custom Post Filter - return chain.filter(exchange); }; } - private boolean isJwtValid(String jwt, ServerWebExchange exchange) { - boolean returnValue = true; - - try { - String subject = Jwts.parserBuilder().setSigningKey(secret).build() - .parseClaimsJws(jwt).getBody() - .getSubject(); - - log.info("subject : {}", subject); - - if (subject == null || subject.isEmpty()) { - returnValue = false; - onError(exchange, "JWT token is not valid", HttpStatus.UNAUTHORIZED); - } - } catch (IllegalArgumentException e) { - returnValue = false; - onError(exchange, "Invalid access token header", HttpStatus.BAD_REQUEST); - } catch (io.jsonwebtoken.security.SecurityException | MalformedJwtException e) { - returnValue = false; - onError(exchange, "Verification error", HttpStatus.UNAUTHORIZED); - } catch (ExpiredJwtException e) { - returnValue = false; - onError(exchange, "Token expired", HttpStatus.PRECONDITION_FAILED); - } catch (JwtException e) { - returnValue = false; - onError(exchange, "JWT error", HttpStatus.UNAUTHORIZED); - } - - return returnValue; - } public String decode(String token) { String subject = null; - try { - subject = Jwts.parser().setSigningKey(secret) - .parseClaimsJws(token).getBody() - .getSubject(); - } catch(Exception ex) { - onError(null, "JWT error", HttpStatus.UNAUTHORIZED); - } - - if(subject == null || subject.isEmpty()) { - onError(null, "JWT error", HttpStatus.UNAUTHORIZED); - } + + subject = Jwts.parser().setSigningKey(secret) + .parseClaimsJws(token).getBody() + .getSubject(); return subject; } - // Mono, Flux -> Spring WebFlux + private Mono onError(ServerHttpResponse response, String message, HttpStatus status) { - private Mono onError(ServerWebExchange exchange, String error, HttpStatus httpStatus) { - ServerHttpResponse response = exchange.getResponse(); - response.setStatusCode(httpStatus); + int statusCode = status.value(); // 상태 코드 가져오기 + response.setStatusCode(status); response.getHeaders().setContentType(MediaType.APPLICATION_JSON); - Map errorResponse = new HashMap<>(); - errorResponse.put("error", error); + // JSON 포맷으로 응답 데이터 구성 + String jsonResponse = "{\"message\": \"" + message + "\", \"code\":" + statusCode + "}"; - ObjectMapper objectMapper = new ObjectMapper(); - byte[] errorResponseBytes; - try { - errorResponseBytes = objectMapper.writeValueAsBytes(errorResponse); - } catch (JsonProcessingException e) { - errorResponseBytes = "{\"error\": \"Internal Server Error\"}".getBytes(StandardCharsets.UTF_8); - } - - DataBuffer buffer = response.bufferFactory().wrap(errorResponseBytes); - - log.error(error); - - return response.writeWith(Mono.just(buffer)).then(response.setComplete()); + DataBuffer buffer = response.bufferFactory().wrap(jsonResponse.getBytes(StandardCharsets.UTF_8)); + return response.writeWith(Mono.just(buffer)); } - @Data public static class Config {