I have two micro-services.
- auth-service (which uses spring-security-oauth2)
- property-service
property-microservice implements a feign client in order get user information from the auth-service via the link
/auth/users/get/{USER_ID}
property-microservice uses oauth2 authentication in order to access to the auth-service end-point above (which works fine, i can get the response)
But auth-service does not return default response data and for this reason feign client interceptor cannot parse auth token from the response.
To be clear, this is the default response from auth-service which spring provides:
{
"access_token": "6e7519de-f211-47ca-afc0-b65ede51bdfc",
"token_type": "bearer",
"refresh_token": "6146216f-bedd-42bf-b4e5-95131b0c6380",
"expires_in": 7199,
"scope": "ui"
}
But i do return response like this:
{
"code": 0,
"message": {
"type": "message",
"status": 200,
"result": 200,
"message": "Token aquired successfully."
},
"data": {
"access_token": "6e7519de-f211-47ca-afc0-b65ede51bdfc",
"token_type": "bearer",
"refresh_token": "6146216f-bedd-42bf-b4e5-95131b0c6380",
"expires_in": 7199,
"scope": "ui"
}
}
Thus, fiegn client looks for the standard response data and does't able to find it because of the modifications i made. If only i can override ResponseExtractor inside OAuth2AccessTokenSupport class i can parse the response correctly. How can i manage parsing custom oauth2 responses from feign clients (or is there any other solution)?
Application.java (property-service)
// For jsr310 java 8 java.time.* support for JPA
@EntityScan(basePackageClasses = {Application.class, Jsr310JpaConverters.class})
@SpringBootApplication
@EnableResourceServer
@EnableOAuth2Client
@EnableFeignClients
@EnableHystrix
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableConfigurationProperties
@Configuration
@EnableAutoConfiguration
public class Application extends ResourceServerConfigurerAdapter {
@Autowired
private ResourceServerProperties sso;
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
HystrixDummy.start();
}
@Bean
@ConfigurationProperties(prefix = "security.oauth2.client")
public ClientCredentialsResourceDetails clientCredentialsResourceDetails() {
return new ClientCredentialsResourceDetails();
}
@Bean
public RequestInterceptor oauth2FeignRequestInterceptor() {
return new OAuth2FeignRequestInterceptor(new DefaultOAuth2ClientContext(), clientCredentialsResourceDetails());
}
@Bean
public OAuth2RestTemplate clientCredentialsRestTemplate() {
return new OAuth2RestTemplate(clientCredentialsResourceDetails());
}
@Bean
public ResourceServerTokenServices tokenServices() {
return new CustomUserInfoTokenServices(this.sso.getUserInfoUri(), this.sso.getClientId());
}
}
AuthServiceClient (property-service)
@FeignClient(name = "auth-service", fallbackFactory = AuthServiceClient.AuthServiceClientFallback.class)
public interface AuthServiceClient {
@RequestMapping(path = "/auth/users/get/{userId}", method = RequestMethod.GET)
RestResponse get(@PathVariable(value = "userId") Long userId);
@Component
class AuthServiceClientFallback implements FallbackFactory<AuthServiceClient> {
@Override
public AuthServiceClient create(Throwable cause) {
return userId -> new RestResponse(null, AppConstant.CODE_FAILURE, null);
}
}
}
Application.java (auth-service)
@SpringBootApplication
@EnableResourceServer
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
UserController.java (auth-service)
@RestController
@RequestMapping("/users")
public class UserController {
@Autowired
private UserService userService;
@PreAuthorize("#oauth2.hasScope('server')")
@RequestMapping(value = "/get/{userId}", method = RequestMethod.GET)
public ResponseEntity<RestResponse> get(@Valid @PathVariable Long userId) throws UserNotFoundException {
User user = this.userService.findOne(userId);
RestResponse response = new RestResponse();
RestMessage message = new RestMessage();
message.setMessage(AppConstant.MESSAGE_USER_FETCHED_SUCCESS);
message.setResult(AppConstant.CODE_USER_FETCHED);
message.setStatus(HttpStatus.OK.value());
response.setCode(AppConstant.CODE_SUCCESS);
response.setMessage(message);
response.setData(user);
return new ResponseEntity<>(response, HttpStatus.OK);
}
}
I just ended up writing custom
FeignClientRequestInterceptor
andFeignClientAccessTokenProvider
like this:FeignClientAccessTokenProvider.java
FeignClientRequestInterceptor .java
Hope this helps to anyone facing this problem.