Skip to content

Commit

Permalink
Task 44 : Revise Filter Process in product and user service
Browse files Browse the repository at this point in the history
  • Loading branch information
Rapter1990 committed Jul 18, 2024
1 parent b871186 commit 8bbb6a0
Show file tree
Hide file tree
Showing 10 changed files with 165 additions and 13 deletions.
9 changes: 9 additions & 0 deletions productservice/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -179,6 +179,15 @@
</dependency>
<!-- BOUNCY CASTLE DEPENDENCY -->

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-jackson</artifactId>
</dependency>

</dependencies>
<dependencyManagement>
<dependencies>
Expand Down
Original file line number Diff line number Diff line change
@@ -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")
Expand Down
Original file line number Diff line number Diff line change
@@ -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());

}
}
}
Original file line number Diff line number Diff line change
@@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand All @@ -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);
}
}
Original file line number Diff line number Diff line change
@@ -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<UsernamePasswordAuthenticationToken> {

@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);
}
}
Original file line number Diff line number Diff line change
@@ -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);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -11,15 +11,15 @@
@Getter
@Configuration
public class TokenConfigurationParameter {
private final String issuer;

private final int accessTokenExpireMinute;
private final int refreshTokenExpireDay;
private final PublicKey publicKey;
private final PrivateKey privateKey;

public TokenConfigurationParameter() {

this.issuer = ConfigurationParameter.ISSUER.getDefaultValue();
//this.issuer = ConfigurationParameter.ISSUER.getDefaultValue();

this.accessTokenExpireMinute = Integer.parseInt(
ConfigurationParameter.AUTH_ACCESS_TOKEN_EXPIRE_MINUTE.getDefaultValue()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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("""
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -45,7 +44,6 @@ public Token generateToken(final Map<String, Object> claims) {
.type(TokenType.BEARER.getValue())
.and()
.id(UUID.randomUUID().toString())
.issuer(ConfigurationParameter.ISSUER.getDefaultValue())
.issuedAt(tokenIssuedAt)
.expiration(accessTokenExpiresAt)
.signWith(tokenConfigurationParameter.getPrivateKey())
Expand All @@ -62,7 +60,6 @@ public Token generateToken(final Map<String, Object> claims) {
.type(TokenType.BEARER.getValue())
.and()
.id(UUID.randomUUID().toString())
.issuer(tokenConfigurationParameter.getIssuer())
.issuedAt(tokenIssuedAt)
.expiration(refreshTokenExpiresAt)
.signWith(tokenConfigurationParameter.getPrivateKey())
Expand Down Expand Up @@ -96,7 +93,6 @@ public Token generateToken(final Map<String, Object> claims, final String refres
.type(TokenType.BEARER.getValue())
.and()
.id(UUID.randomUUID().toString())
.issuer(tokenConfigurationParameter.getIssuer())
.issuedAt(accessTokenIssuedAt)
.expiration(accessTokenExpiresAt)
.signWith(tokenConfigurationParameter.getPrivateKey())
Expand Down Expand Up @@ -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.)
Expand Down

0 comments on commit 8bbb6a0

Please sign in to comment.