I am using SpringBoot
with Eureka
Server. I have a users microservice
, one eureka server
and one springcloud apigateway
folder. Here is the complete source code
In my users microservice's controller
, I have below code
@RestController
@RequestMapping("/users")
public class UsersController {
@Autowired
private Environment env;
@Autowired
UsersService usersService;
@GetMapping("/status/check")
public String status(){
System.out.println("hereeeeeeeeeee");
return "Working "+env.getProperty("local.server.port");
}
@PostMapping
public ResponseEntity<CreateUserResponseModel> createUser(@Valid @RequestBody CreateUserRequestModel userDetails) {
ModelMapper modelMapper = new ModelMapper();
modelMapper.getConfiguration().setMatchingStrategy(MatchingStrategies.STRICT);
UserDto userDto = modelMapper.map(userDetails, UserDto.class);
UserDto createdUser = usersService.createUser(userDto);
CreateUserResponseModel body = modelMapper.map(createdUser, CreateUserResponseModel.class);
return ResponseEntity.status(HttpStatus.CREATED).body(body);
}
}
Now the Get api endpoint returns in 403 Forbidden , the post endpoint works fine
Below is the screenshot of the error
I have defined AuthorizationHeaderFilter
class in apigateway
which is used for decoding jwt
which I am sending in the GET Api Endpoint and it properly decodes the JWT
@Component
public class AuthorizationHeaderFilter extends AbstractGatewayFilterFactory<AuthorizationHeaderFilter.Config>{
@Autowired
private Environment environment;
public AuthorizationHeaderFilter(){
super(Config.class);
}
public static class Config{
}
@Override
public GatewayFilter apply(Config config) {
return (exchange,chain)->{
ServerHttpRequest request = exchange.getRequest();
if(!request.getHeaders().containsKey(HttpHeaders.AUTHORIZATION)){
return onError(exchange,"No authorization header",HttpStatus.UNAUTHORIZED);
}
String authorizationHeader = request.getHeaders().get(HttpHeaders.AUTHORIZATION).get(0);
String jwt = authorizationHeader.replace("Bearer ", ""); //Make sure you add space
if(!isJwtValid(jwt)){
return onError(exchange, "Jwt token is invalid",HttpStatus.UNAUTHORIZED);
}
return chain.filter(exchange);
};
}
private Mono<Void> onError(ServerWebExchange exchange,String err,HttpStatus httpStatus){
ServerHttpResponse response = exchange.getResponse();
response.setStatusCode(httpStatus);
return response.setComplete();
}
private boolean isJwtValid(String jwt){
System.out.println("1");
boolean isValid = false;
String subject = null;
String tokenSecret = environment.getProperty("token.secret");
System.out.println("2 "+tokenSecret);
SecretKey secretKey = Keys.hmacShaKeyFor(tokenSecret.getBytes());
JwtParser jwtParser = Jwts.parser().verifyWith(secretKey).build();
try{
// Jwt<Header,Claims> parsedToken = jwtParser.parse(jwt);
subject = jwtParser.parseSignedClaims(jwt).getPayload().get("userId").toString();
System.out.println("3 "+subject);
} catch(Exception ex){
isValid = false;
System.out.println("4 "+ex.getLocalizedMessage());
}
if(subject == null || subject.isEmpty()){
isValid = false;
} else {
isValid = true;
}
System.out.println("5 ");
return isValid;
}
}
Here is the application.properties
of my apigateway
spring.application.name=api-gateway
server.port=8082
eureka.client.service-url.defaultZone=http://localhost:8010/eureka
spring.cloud.gateway.routes[0].id=users-status-check
spring.cloud.gateway.routes[0].uri=lb://users-ws
spring.cloud.gateway.routes[0].predicates[0]=Path=/users-ws/users/status/check
spring.cloud.gateway.routes[0].predicates[1]=Method=GET
spring.cloud.gateway.routes[0].predicates[2]=Header=Authorization, Bearer (.*)
spring.cloud.gateway.routes[0].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[0].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}
spring.cloud.gateway.routes[0].filters[2]=AuthorizationHeaderFilter
spring.cloud.gateway.routes[1].id=users-ws
spring.cloud.gateway.routes[1].uri=lb://users-ws
spring.cloud.gateway.routes[1].predicates[0]=Path=/users-ws/users
spring.cloud.gateway.routes[1].predicates[1]=Method=POST
spring.cloud.gateway.routes[1].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[1].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}
spring.cloud.gateway.routes[2].id=users-ws-h2-console
spring.cloud.gateway.routes[2].uri=lb://users-ws
spring.cloud.gateway.routes[2].predicates[0]=Path=/users-ws/h2-console
spring.cloud.gateway.routes[2].predicates[1]=Method=GET
spring.cloud.gateway.routes[2].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[2].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}
spring.cloud.gateway.routes[3].id=users-ws-login
spring.cloud.gateway.routes[3].uri=lb://users-ws
spring.cloud.gateway.routes[3].predicates[0]=Path=/users-ws/users/login
spring.cloud.gateway.routes[3].predicates[1]=Method=POST
spring.cloud.gateway.routes[3].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[3].filters[1]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}
spring.cloud.gateway.routes[4].id=users-ws-get-update-delete
spring.cloud.gateway.routes[4].uri=lb://users-ws
spring.cloud.gateway.routes[4].predicates[0]=Path=/users-ws/users/**
spring.cloud.gateway.routes[4].predicates[1]=Method=GET,PUT,DELETE
spring.cloud.gateway.routes[4].predicates[2]=Header=Authorization, Bearer (.*)
spring.cloud.gateway.routes[4].filters[0]=RemoveRequestHeader=Cookie
spring.cloud.gateway.routes[4].filters[1]=AuthorizationHeaderFilter
spring.cloud.gateway.routes[4].filters[2]=RewritePath=/users-ws/(?<segment>.*), /$\{segment}
token.secret=1aBcD3eF4gH5iJ6kL7mN8oP9qRsTuVwXyZ0A1bCdEfG2hI3jK4lM5nO6pQ7rStU8vW9xYz
I updated the file WebSecurity.java
in your users service, and changed the line:
.authorizeHttpRequests(auth -> auth.requestMatchers(HttpMethod.POST, "/users")
.permitAll()
to
.authorizeHttpRequests(auth -> auth.requestMatchers("/users/**")
.permitAll()
So that Spring Security allows not only POST
requests but also the GET
ones and also you are able to call paths under /users
. After that I got a correct response.