I have implemented the following microservice applications.
Request flow.
Ui Client(http://localhost:8080) ------> spring cloud gateway(http://localhost:8081) ------> user microservice(http://localhost:8602)(api endpoint=/api/v1/users/bulkUpload)
I am sending an Ajax request to user microservice through the spring cloud gateway service. Ajax request contains refresh token as a cookie value.
$.ajax({
type: "POST",
enctype: 'multipart/form-data',
url: "http://localhost:8081/api/v1/users/bulkUpload",
xhrFields: {
withCredentials: true
},
data: newData,
processData: false,
contentType: false,
crossDomain: false,
cache: false,
timeout: 600000,
success: function (data) {
......
}
but if the refresh token is not available in Ajax request I want to terminate the request at API gateway level and i want to redirect the user to the Ui client logout page(http://localhost:8080/Logout). for that, I have implemented a spring cloud gateway filter as follows.
@Component
public class AccessTokenCheckingGlobalFilterPre extends AbstractGatewayFilterFactory<AccessTokenCheckingGlobalFilterPre.Config> {
@Value("${security.oauth2.client.client-id}")
private String client_id;
@Value("${security.oauth2.client.client-secret}")
private String client_secret;
public AccessTokenCheckingGlobalFilterPre() {
super(AccessTokenCheckingGlobalFilterPre.Config.class);
}
@Override
public GatewayFilter apply(AccessTokenCheckingGlobalFilterPre.Config config) {
return (exchange, chain) -> {
Route route = exchange.getAttribute(ServerWebExchangeUtils.GATEWAY_ROUTE_ATTR);
ServerHttpRequest request = exchange.getRequest();
ServerHttpResponse response = exchange.getResponse();
if(route!=null && request.getPath().toString().contains("oauth/token")) {
return chain.filter(exchange.mutate().request(request).response(response).build());
}else {
MultiValueMap<String, HttpCookie> cookies = request.getCookies();
List<HttpCookie> accessTokenList = cookies.get("access_token");
List<HttpCookie> refreshTokenList = cookies.get("refresh_token");
HttpHeaders heraders = request.getHeaders();
String access_token="";
String refresh_token = "";
if(accessTokenList != null) {
access_token = accessTokenList.get(0).getValue();
}
if(refreshTokenList != null) {
refresh_token = refreshTokenList.get(0).getValue();
}
if(access_token.isEmpty() && !refresh_token.isEmpty()) {
RestTemplate restTemplate = new RestTemplate();
String credentials = client_id + ":" + client_secret;
String encodedCredentials = new String(Base64.encode(credentials.getBytes()));
HttpHeaders headers = new HttpHeaders();
headers.setAccept(Arrays.asList(MediaType.APPLICATION_JSON));
headers.add("Authorization", "Basic " + encodedCredentials);
HttpEntity<String> requestEntity = new HttpEntity<String>(headers);
String access_token_url = "http://localhost:8602/oauth/token";
access_token_url += "?grant_type=refresh_token";
access_token_url += "&refresh_token=" + refresh_token;
ResponseEntity<String> aouthResponse = restTemplate.exchange(access_token_url, HttpMethod.POST, requestEntity, String.class);
String responseJson = access_token = aouthResponse.getBody();
ObjectMapper mapper = new ObjectMapper();
JsonNode node = null;
try {
node = mapper.readTree(responseJson);
} catch (JsonProcessingException e) {
e.printStackTrace();
}
String newRefreshToken = node.path("refresh_token").asText();
String newAccessToken = node.path("access_token").asText();
int expiresIn = Integer.parseInt(node.path("expires_in").asText());
int refreshTokenExpireTime = Integer.parseInt(node.path("refreshTokenExpires_In").asText());
ResponseCookie accessTokenCookie = ResponseCookie.from("access_token", newAccessToken)
.path("/")
.maxAge(expiresIn)
.build();
ResponseCookie refreshTokenCookie = ResponseCookie.from("refresh_token", newRefreshToken)
.path("/")
.maxAge(refreshTokenExpireTime)
.build();
response.addCookie(refreshTokenCookie);
response.addCookie(accessTokenCookie);
access_token = newAccessToken;
}else if(refresh_token.isEmpty()){
//request.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
//response.setComplete();
return chain.filter(exchange.mutate().request(request).response(response).build());
}
final String value = access_token;
request = request.mutate()
.headers(httpHeaders -> httpHeaders.add("Authorization", "Bearer " + value))
.build();
}
return chain.filter(exchange.mutate().request(request).response(response).build());
};
}
public static class Config {
}
}
this logic has been implemented to check whether refresh token present in the request. unless it is redirecting Ui client logout page(http://localhost:8080/Logout).
}else if(refresh_token.isEmpty()){
//request.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
//response.setComplete();
return chain.filter(exchange.mutate().request(request).response(response).build());
}
but still, no request termination happening at the API gateway level and the request still is forwarding to user microservice.
How to terminate the request flow at apigateway filter and redirect back to ui client logout page.
Instead of
}else if(refresh_token.isEmpty()){
//request.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
response.setStatusCode(HttpStatus.PERMANENT_REDIRECT);
response.getHeaders().setLocation(URI.create("http://localhost:8080/Logout"));
//response.setComplete();
return chain.filter(exchange.mutate().request(request).response(response).build());
}
to redirect the user, use
}else if(refresh_token.isEmpty()){
response.setStatusCode(HttpStatus.FOUND); //302
response
.getHeaders()
.set("Location", "/logout");
return response.setComplete();
}