diff --git a/productservice/pom.xml b/productservice/pom.xml
index 7a9d64d..8525467 100644
--- a/productservice/pom.xml
+++ b/productservice/pom.xml
@@ -179,6 +179,15 @@
+
+ com.fasterxml.jackson.core
+ jackson-databind
+
+
+ io.github.openfeign
+ feign-jackson
+
+
diff --git a/productservice/src/main/java/com/springbootmicroservices/productservice/client/UserServiceClient.java b/productservice/src/main/java/com/springbootmicroservices/productservice/client/UserServiceClient.java
index bce85b8..67e6eb5 100644
--- a/productservice/src/main/java/com/springbootmicroservices/productservice/client/UserServiceClient.java
+++ b/productservice/src/main/java/com/springbootmicroservices/productservice/client/UserServiceClient.java
@@ -1,12 +1,13 @@
package com.springbootmicroservices.productservice.client;
+import com.springbootmicroservices.productservice.config.FeignClientConfig;
import org.springframework.cloud.openfeign.FeignClient;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestParam;
-@FeignClient(name = "userservice", path = "/api/v1/users")
+@FeignClient(name = "userservice", path = "/api/v1/users", configuration = FeignClientConfig.class)
public interface UserServiceClient {
@PostMapping("/validate-token")
diff --git a/productservice/src/main/java/com/springbootmicroservices/productservice/config/FeignClientConfig.java b/productservice/src/main/java/com/springbootmicroservices/productservice/config/FeignClientConfig.java
new file mode 100644
index 0000000..27f7e00
--- /dev/null
+++ b/productservice/src/main/java/com/springbootmicroservices/productservice/config/FeignClientConfig.java
@@ -0,0 +1,93 @@
+package com.springbootmicroservices.productservice.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import feign.FeignException;
+import feign.Request;
+import feign.Response;
+import feign.codec.Decoder;
+import feign.codec.ErrorDecoder;
+import lombok.extern.slf4j.Slf4j;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.http.HttpStatus;
+
+import java.io.IOException;
+import java.io.InputStream;
+import java.lang.reflect.Type;
+import java.util.Collection;
+import java.util.Map;
+
+@Slf4j
+@Configuration
+public class FeignClientConfig {
+
+ @Bean
+ public Decoder feignDecoder(ObjectMapper objectMapper) {
+ return new CustomDecoder(objectMapper);
+ }
+
+ @Bean
+ public ErrorDecoder errorDecoder() {
+ return new CustomErrorDecoder();
+ }
+
+ private static class CustomDecoder implements Decoder {
+
+ private final ObjectMapper objectMapper;
+
+ public CustomDecoder(ObjectMapper objectMapper) {
+ this.objectMapper = objectMapper;
+ }
+
+ @Override
+ public Object decode(Response response, Type type) throws IOException {
+ // Handle specific HTTP status codes and throw corresponding FeignExceptions
+ if (response.status() == HttpStatus.UNAUTHORIZED.value()) {
+ throw new FeignException.Unauthorized("Unauthorized", response.request(), response.request().body(), response.headers());
+ }
+ if (response.status() == HttpStatus.FORBIDDEN.value()) {
+ throw new FeignException.Forbidden("Forbidden", response.request(), response.request().body(), response.headers());
+ }
+ if (response.status() == HttpStatus.NOT_FOUND.value()) {
+ throw new FeignException.NotFound("Not Found", response.request(), response.request().body(), response.headers());
+ }
+ if (response.status() == HttpStatus.METHOD_NOT_ALLOWED.value()) {
+ throw new FeignException.MethodNotAllowed("Method Not Allowed", response.request(), response.request().body(), response.headers());
+ }
+ if (response.status() == HttpStatus.BAD_REQUEST.value()) {
+ throw new FeignException.BadRequest("Bad Request", response.request(), response.request().body(), response.headers());
+ }
+
+ // Deserialize the response body using Jackson
+ if (response.body() != null) {
+ InputStream inputStream = response.body().asInputStream();
+ return objectMapper.readValue(inputStream, objectMapper.constructType(type));
+ }
+
+ return null;
+ }
+ }
+
+ private static class CustomErrorDecoder implements ErrorDecoder {
+
+ @Override
+ public Exception decode(String methodKey, Response response) {
+ HttpStatus status = HttpStatus.valueOf(response.status());
+ // Handle specific HTTP status codes and return corresponding FeignExceptions
+ if (status == HttpStatus.UNAUTHORIZED) {
+ return new FeignException.Unauthorized("Unauthorized", response.request(), response.request().body(), response.headers());
+ }
+ if (status == HttpStatus.FORBIDDEN) {
+ return new FeignException.Forbidden("Forbidden", response.request(), response.request().body(), response.headers());
+ }
+ if (status == HttpStatus.NOT_FOUND) {
+ return new FeignException.NotFound("Not Found", response.request(), response.request().body(), response.headers());
+ }
+ if (status == HttpStatus.METHOD_NOT_ALLOWED) {
+ return new FeignException.MethodNotAllowed("Method Not Allowed", response.request(), response.request().body(), response.headers());
+ }
+ return new FeignException.BadRequest("Bad Request", response.request(), response.request().body(), response.headers());
+
+ }
+ }
+}
\ No newline at end of file
diff --git a/productservice/src/main/java/com/springbootmicroservices/productservice/config/JacksonConfig.java b/productservice/src/main/java/com/springbootmicroservices/productservice/config/JacksonConfig.java
new file mode 100644
index 0000000..9c17e6a
--- /dev/null
+++ b/productservice/src/main/java/com/springbootmicroservices/productservice/config/JacksonConfig.java
@@ -0,0 +1,18 @@
+package com.springbootmicroservices.productservice.config;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import com.springbootmicroservices.productservice.serializer.UsernamePasswordAuthenticationTokenMixin;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+
+@Configuration
+public class JacksonConfig {
+
+ @Bean
+ public ObjectMapper objectMapper() {
+ ObjectMapper mapper = new ObjectMapper();
+ mapper.addMixIn(UsernamePasswordAuthenticationToken.class, UsernamePasswordAuthenticationTokenMixin.class);
+ return mapper;
+ }
+}
\ No newline at end of file
diff --git a/productservice/src/main/java/com/springbootmicroservices/productservice/filter/CustomBearerTokenAuthenticationFilter.java b/productservice/src/main/java/com/springbootmicroservices/productservice/filter/CustomBearerTokenAuthenticationFilter.java
index 5eb4b3b..4d8865e 100644
--- a/productservice/src/main/java/com/springbootmicroservices/productservice/filter/CustomBearerTokenAuthenticationFilter.java
+++ b/productservice/src/main/java/com/springbootmicroservices/productservice/filter/CustomBearerTokenAuthenticationFilter.java
@@ -49,8 +49,6 @@ protected void doFilterInternal(@NonNull final HttpServletRequest httpServletReq
// Set authentication to SecurityContextHolder
SecurityContextHolder.getContext().setAuthentication(authentication);
- // Proceed with the filter chain
- filterChain.doFilter(httpServletRequest, httpServletResponse);
} catch (FeignException e) {
log.error("Token validation failed for request: {}", httpServletRequest.getRequestURI(), e);
@@ -64,7 +62,9 @@ protected void doFilterInternal(@NonNull final HttpServletRequest httpServletReq
}
} else {
log.warn("Missing or invalid Authorization header for request: {}", httpServletRequest.getRequestURI());
- filterChain.doFilter(httpServletRequest, httpServletResponse);
}
+
+ // Proceed with the filter chain in any case
+ filterChain.doFilter(httpServletRequest, httpServletResponse);
}
}
\ No newline at end of file
diff --git a/productservice/src/main/java/com/springbootmicroservices/productservice/serializer/UsernamePasswordAuthenticationTokenDeserializer.java b/productservice/src/main/java/com/springbootmicroservices/productservice/serializer/UsernamePasswordAuthenticationTokenDeserializer.java
new file mode 100644
index 0000000..3f93843
--- /dev/null
+++ b/productservice/src/main/java/com/springbootmicroservices/productservice/serializer/UsernamePasswordAuthenticationTokenDeserializer.java
@@ -0,0 +1,26 @@
+package com.springbootmicroservices.productservice.serializer;
+
+import com.fasterxml.jackson.core.JsonParser;
+import com.fasterxml.jackson.core.JsonProcessingException;
+import com.fasterxml.jackson.databind.DeserializationContext;
+import com.fasterxml.jackson.databind.JsonDeserializer;
+import com.fasterxml.jackson.databind.JsonNode;
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+
+import java.io.IOException;
+
+public class UsernamePasswordAuthenticationTokenDeserializer extends JsonDeserializer {
+
+ @Override
+ public UsernamePasswordAuthenticationToken deserialize(JsonParser p, DeserializationContext ctxt)
+ throws IOException, JsonProcessingException {
+ JsonNode node = p.getCodec().readTree(p);
+
+ // Assuming the response contains the necessary fields
+ String principal = node.get("principal").asText();
+ String credentials = node.get("credentials").asText();
+
+ return new UsernamePasswordAuthenticationToken(principal, credentials);
+ }
+}
diff --git a/productservice/src/main/java/com/springbootmicroservices/productservice/serializer/UsernamePasswordAuthenticationTokenMixin.java b/productservice/src/main/java/com/springbootmicroservices/productservice/serializer/UsernamePasswordAuthenticationTokenMixin.java
new file mode 100644
index 0000000..6445ee5
--- /dev/null
+++ b/productservice/src/main/java/com/springbootmicroservices/productservice/serializer/UsernamePasswordAuthenticationTokenMixin.java
@@ -0,0 +1,11 @@
+package com.springbootmicroservices.productservice.serializer;
+
+import com.fasterxml.jackson.databind.annotation.JsonDeserialize;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+
+@JsonDeserialize(using = UsernamePasswordAuthenticationTokenDeserializer.class)
+public class UsernamePasswordAuthenticationTokenMixin extends UsernamePasswordAuthenticationToken {
+ public UsernamePasswordAuthenticationTokenMixin(Object principal, Object credentials) {
+ super(principal, credentials);
+ }
+}
diff --git a/userservice/src/main/java/com/springbootmicroservices/userservice/config/TokenConfigurationParameter.java b/userservice/src/main/java/com/springbootmicroservices/userservice/config/TokenConfigurationParameter.java
index a0c7869..02d0392 100644
--- a/userservice/src/main/java/com/springbootmicroservices/userservice/config/TokenConfigurationParameter.java
+++ b/userservice/src/main/java/com/springbootmicroservices/userservice/config/TokenConfigurationParameter.java
@@ -11,7 +11,7 @@
@Getter
@Configuration
public class TokenConfigurationParameter {
- private final String issuer;
+
private final int accessTokenExpireMinute;
private final int refreshTokenExpireDay;
private final PublicKey publicKey;
@@ -19,7 +19,7 @@ public class TokenConfigurationParameter {
public TokenConfigurationParameter() {
- this.issuer = ConfigurationParameter.ISSUER.getDefaultValue();
+ //this.issuer = ConfigurationParameter.ISSUER.getDefaultValue();
this.accessTokenExpireMinute = Integer.parseInt(
ConfigurationParameter.AUTH_ACCESS_TOKEN_EXPIRE_MINUTE.getDefaultValue()
diff --git a/userservice/src/main/java/com/springbootmicroservices/userservice/model/user/enums/ConfigurationParameter.java b/userservice/src/main/java/com/springbootmicroservices/userservice/model/user/enums/ConfigurationParameter.java
index b5028b3..2f4821c 100644
--- a/userservice/src/main/java/com/springbootmicroservices/userservice/model/user/enums/ConfigurationParameter.java
+++ b/userservice/src/main/java/com/springbootmicroservices/userservice/model/user/enums/ConfigurationParameter.java
@@ -7,8 +7,6 @@
@RequiredArgsConstructor
public enum ConfigurationParameter {
- ISSUER("ISSUER"),
-
AUTH_ACCESS_TOKEN_EXPIRE_MINUTE("30"),
AUTH_REFRESH_TOKEN_EXPIRE_DAY("1"),
AUTH_PUBLIC_KEY("""
diff --git a/userservice/src/main/java/com/springbootmicroservices/userservice/service/impl/TokenServiceImpl.java b/userservice/src/main/java/com/springbootmicroservices/userservice/service/impl/TokenServiceImpl.java
index 08d283e..60caf2d 100644
--- a/userservice/src/main/java/com/springbootmicroservices/userservice/service/impl/TokenServiceImpl.java
+++ b/userservice/src/main/java/com/springbootmicroservices/userservice/service/impl/TokenServiceImpl.java
@@ -2,7 +2,6 @@
import com.springbootmicroservices.userservice.config.TokenConfigurationParameter;
import com.springbootmicroservices.userservice.model.user.Token;
-import com.springbootmicroservices.userservice.model.user.enums.ConfigurationParameter;
import com.springbootmicroservices.userservice.model.user.enums.TokenClaims;
import com.springbootmicroservices.userservice.model.user.enums.TokenType;
import com.springbootmicroservices.userservice.model.user.enums.UserType;
@@ -45,7 +44,6 @@ public Token generateToken(final Map claims) {
.type(TokenType.BEARER.getValue())
.and()
.id(UUID.randomUUID().toString())
- .issuer(ConfigurationParameter.ISSUER.getDefaultValue())
.issuedAt(tokenIssuedAt)
.expiration(accessTokenExpiresAt)
.signWith(tokenConfigurationParameter.getPrivateKey())
@@ -62,7 +60,6 @@ public Token generateToken(final Map claims) {
.type(TokenType.BEARER.getValue())
.and()
.id(UUID.randomUUID().toString())
- .issuer(tokenConfigurationParameter.getIssuer())
.issuedAt(tokenIssuedAt)
.expiration(refreshTokenExpiresAt)
.signWith(tokenConfigurationParameter.getPrivateKey())
@@ -96,7 +93,6 @@ public Token generateToken(final Map claims, final String refres
.type(TokenType.BEARER.getValue())
.and()
.id(UUID.randomUUID().toString())
- .issuer(tokenConfigurationParameter.getIssuer())
.issuedAt(accessTokenIssuedAt)
.expiration(accessTokenExpiresAt)
.signWith(tokenConfigurationParameter.getPrivateKey())
@@ -150,7 +146,7 @@ public void verifyAndValidate(final String jwt) {
.parseSignedClaims(jwt);
// Log the claims for debugging purposes
- Claims claims = claimsJws.getBody();
+ Claims claims = claimsJws.getPayload();
log.info("Token claims: {}", claims);
// Additional checks (e.g., expiration, issuer, etc.)