Unauthorized and full authentication required to access user's resource - spring-boot

I am working on a resource service that uses Keycloak as the authorization server. The code below is taken from Spring Security in Action by Laurentiu Spilcă. Keycloak is provisioned with some users for testing purposes. So first a token for a user is obtained after login and the token is used to to make a request to retrieve the user's data from the resource server but I keep getting unauthorized and full authentication required. I am unable to figure out what the issue is as I am quite new to Spring.
KeycloakApplication.java
package com.chapter18.app;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.autoconfigure.domain.EntityScan;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.data.jpa.repository.config.EnableJpaRepositories;
#SpringBootApplication
#EnableJpaRepositories(basePackages = {"com.chapter18.repositories"} )
#EntityScan(basePackages = "com.chapter18.entities")
#ComponentScan(basePackages = {"com.chapter18.service", "com.chapter18.config", "com.chapter18.controller"})
public class KeycloakProjectApplication {
public static void main(String[] args) {
SpringApplication.run(KeycloakProjectApplication.class, args);
}
}
ResourceServerConfig.java
package com.chapter18.config;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.access.expression.SecurityExpressionHandler;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.data.repository.query.SecurityEvaluationContextExtension;
import org.springframework.security.oauth2.config.annotation.web.configuration.EnableResourceServer;
import org.springframework.security.oauth2.config.annotation.web.configuration.ResourceServerConfigurerAdapter;
import org.springframework.security.oauth2.config.annotation.web.configurers.ResourceServerSecurityConfigurer;
import org.springframework.security.oauth2.provider.expression.OAuth2WebSecurityExpressionHandler;
import org.springframework.security.oauth2.provider.token.TokenStore;
import org.springframework.security.oauth2.provider.token.store.jwk.JwkTokenStore;
import org.springframework.security.web.FilterInvocation;
/**
* created on 21/04/2022
*/
#Configuration
#EnableResourceServer
#EnableGlobalMethodSecurity(prePostEnabled = true)
public class ResourceServerConfig extends ResourceServerConfigurerAdapter {
#Value("${claim.aud}")
private String claimAud;
#Value("${jwkSetUri}")
private String urlJwk;
#Override
public void configure(ResourceServerSecurityConfigurer resources) {
System.out.println(claimAud + "\t" + urlJwk);
resources.tokenStore(tokenStore());
resources.resourceId(claimAud);
resources.expressionHandler(handler());
}
#Override
public void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
http.headers().frameOptions().disable();
// http.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.authorizeRequests()
.mvcMatchers(HttpMethod.DELETE, "/**")
.hasAuthority("fitnessadmin")
.antMatchers("/h2-console/**").permitAll()
.anyRequest()
.authenticated();
}
#Bean
public SecurityEvaluationContextExtension securityEvaluationContextExtension() {
return new SecurityEvaluationContextExtension();
}
#Bean
public SecurityExpressionHandler<FilterInvocation> handler() {
return new OAuth2WebSecurityExpressionHandler();
}
#Bean
public TokenStore tokenStore() {
return new JwkTokenStore(urlJwk);
}
}
WorkoutController.java
package com.chapter18.controller;
import com.chapter18.entities.Workout;
import com.chapter18.service.WorkoutService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;
import java.util.List;
/**
* created on 21/04/2022
*/
#RestController
#RequestMapping("/workout")
public class WorkoutController {
#Autowired
private WorkoutService workoutService;
#PostMapping("/")
public void add(#RequestBody Workout workout){
workoutService.saveWorkout(workout);
}
#GetMapping("/")
public List<Workout> findAll(){
return workoutService.findWorkouts();
}
#DeleteMapping("/{id}")
public void delete(#PathVariable Integer id){
workoutService.deleteWorkout(id);
}
}
Workout.java
import lombok.Getter;
import lombok.Setter;
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
import java.time.LocalDateTime;
/**
* created on 21/04/2022
*/
#Getter
#Setter
#Entity
public class Workout {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
private int id;
private String user;
private LocalDateTime start;
private LocalDateTime end;
private int diffculty;
}
WorkoutRepository.java
package com.chapter18.repositories;
import com.chapter18.entities.Workout;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.jpa.repository.Query;
import java.util.List;
/**
* created on 21/04/2022
*/
public interface WorkoutRepository extends JpaRepository<Workout, Integer> {
#Query("SELECT w FROM Workout w WHERE w.user = ?#{authentication.name}")
List<Workout> findAllByUser();
}
WorkoutService
package com.chapter18.service;
import com.chapter18.entities.Workout;
import com.chapter18.repositories.WorkoutRepository;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.stereotype.Service;
import java.util.List;
/**
* created on 21/04/2022
*/
#Service
public class WorkoutService {
#Autowired
private WorkoutRepository workoutRepository;
#PreAuthorize("#workout.user == authentication.name and #oauth2.hasScope('fitnessapp')")
public void saveWorkout(Workout workout){
System.out.println(workout.getUser());
workoutRepository.save(workout);
}
public List<Workout> findWorkouts(){
return workoutRepository.findAll();
}
public void deleteWorkout(Integer id){
workoutRepository.deleteById(id);
}
}
application.yml
spring:
application:
name: FitnessApp
datasource:
url: jdbc:h2:mem:spring
username: sa
password: pass
driverClassName: org.h2.Driver
jpa:
spring:
jpa:
database-platform: org.hibernate.dialect.H2Dialect
defer-datasource-initialization: true
h2:
console:
enabled: true
sql:
init:
mode: ALWAYS
claim:
aud: fitnessapp
jwkSetUri: http://localhost:8080/realms/master/protocol/openid-connect/certs
server:
port: 9090
schema.sql
CREATE SCHEMA IF NOT EXISTS spring;
CREATE TABLE IF NOT EXISTS `spring`.`workout` (
`id` INT NOT NULL AUTO_INCREMENT,
`user` VARCHAR(45) NULL,
`start` DATETIME NULL,
`end` DATETIME NULL,
`difficulty` INT NULL,
PRIMARY KEY (`id`)
);
INSERT INTO `spring`.`workout` (`id`, `user`, `start`, `end`, `difficulty`) VALUES (1, 'bill', '2020-06-10 15:05:05', '2020-06-10 16:10:07', '3');
INSERT INTO `spring`.`workout` (`id`, `user`, `start`, `end`, `difficulty`) VALUES (2, 'rachel', '2020-06-10 15:05:10', '2020-06-10 16:10:20', '3');
INSERT INTO `spring`.`workout` (`id`, `user`, `start`, `end`, `difficulty`) VALUES (3, 'bill', '2020-06-12 12:00:10', '2020-06-12 13:01:10', '4');
INSERT INTO `spring`.`workout` (`id`, `user`, `start`, `end`, `difficulty`) VALUES (4, 'rachel', '2020-06-12 12:00:05', '2020-06-12 12:00:11', '4');
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.my</groupId>
<artifactId>KeycloakProject</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>KeycloakProject</name>
<description>KeycloakProject</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<!-- <dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>-->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-oauth2</artifactId>
<version>2.2.5.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-oauth2-resource-server</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-data</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bootstrap</artifactId>
<version>3.1.1</version>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.springframework.security</groupId>
<artifactId>spring-security-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<configuration>
<excludes>
<exclude>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
</exclude>
</excludes>
</configuration>
</plugin>
</plugins>
</build>
</project>

Related

Field departmentrepositoryy in service.DepartementServiceimpl required a bean of type 'repository.DepartmentRepository' that could not be found

entity
import javax.persistence.Entity;
import javax.persistence.GeneratedValue;
import javax.persistence.GenerationType;
import javax.persistence.Id;
#Entity
public class Department {
public long getDepartment_id() {
return department_id;
}
public void setDepartment_id(long department_id) {
this.department_id = department_id;
}
public String getDepartment_name() {
return department_name;
}
public Department(long department_id, String department_name, String department_address, String department_code) {
this.department_id = department_id;
this.department_name = department_name;
this.department_address = department_address;
this.department_code = department_code;
}
public void setDepartment_name(String department_name) {
this.department_name = department_name;
}
public String getDepartment_address() {
return department_address;
}
public void setDepartment_address(String department_address) {
this.department_address = department_address;
}
public String getDepartement_code() {
return department_code;
}
public void setDepartement_code(String department_code) {
this.department_code = department_code;
}
public Department() {
super();
}
#Override
public String toString() {
return "Department{" +
"departement_id=" + department_id +
", departement_name='" + department_name + '\'' +
", departement_address='" + department_address + '\'' +
", departement_code='" + department_code + '\'' +
'}';
}
#Id
#GeneratedValue(strategy = GenerationType.AUTO)
private long department_id;
private String department_name;
private String department_address;
private String department_code;
}
department controller
import entity.Department;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RestController;
import service.DepartmentService;
#RestController
public class DepartmentController {
#Autowired
public DepartmentService departmentServicee;
#PostMapping("/departments")
public Department saveDepartment(#RequestBody Department department)
{
return departmentServicee.saveDepartment(department);
}
}
Department service
import org.springframework.stereotype.Component;
import entity.Department;
import org.springframework.stereotype.Service;
public interface DepartmentService {
public Department saveDepartment(Department department);
}
department service impl
import entity.Department;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import repository.DepartmentRepository;
#Service
public class DepartementServiceimpl implements DepartmentService {
#Autowired
public DepartmentRepository departmentrepositoryy;
#Override
public Department saveDepartment(Department department) {
return departmentrepositoryy.save(department);
}
}
Department repository
import entity.Department;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.jpa.repository.JpaRepository;
import org.springframework.data.repository.CrudRepository;
import org.springframework.data.repository.query.FluentQuery;
import org.springframework.stereotype.Repository;
import java.util.List;
import java.util.Optional;
import java.util.function.Function;
#Repository
public interface DepartmentRepository extends JpaRepository<Department,Long> {
}
application.properties
server.port = 9009
spring.h2.console.enabled=true
spring.datasource.url=jdbc:h2:mem:testdb
spring.datasource.driverClassName=org.h2.Driver
spring.datasource.username=sa
spring.datasource.password=sa
spring.jpa.database-platform=org.hibernate.dialect.H2Dialect
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 https://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.6.6</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.saketh</groupId>
<artifactId>spring_boot_Real</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>spring_boot_Real</name>
<description>Demo project for Spring Boot</description>
<properties>
<java.version>17</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>com.h2database</groupId>
<artifactId>h2</artifactId>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<!--<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
</dependency>-->
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-starter-data-jpa -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-data-jpa</artifactId>
</dependency>
<dependency>
<groupId>org.apache.derby</groupId>
<artifactId>derby</artifactId>
<scope>runtime</scope>
</dependency>
<!-- https://mvnrepository.com/artifact/org.hibernate.javax.persistence/hibernate-jpa-2.1-api -->
<!-- https://mvnrepository.com/artifact/org.hibernate/hibernate-core -->
<dependency>
<groupId>org.hibernate</groupId>
<artifactId>hibernate-core</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
**
Unable to get my mistake tried most of the available solutions
what did I miss?
I did add all the files that i have used , please let me know any other required
Thanks
**
file structure

Using Feign builder requests doesn't send trace-id, span-id to child clients but using rest template is showing all headers on child clients

I'm making a sequential request using Feign Builder. There are no x-b3-traceid,x-b3-spanid .. in the title of the request. That's why the log my last client appears on the zipkin.
I use spring boot 2.4.2 , spring cloud 2020.0.0 , feign-core 10.10.1 , feign-okhttp 10.10.1. I have tried spring-cloud-openfeign and i achieved wanted result. But i don't want to use this lib. There are requests when using Feign Builder and Rest Template in here. I dont' see same log at zipkin.
My Client1 App. I am sending request http://localhost:8082/
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign2.Client2Feign;
import javax.servlet.http.HttpServletRequest;
#RestController
public class SampleController {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private RestTemplate restTemplate;
#Autowired
private Client client;
#Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
#Bean
public OkHttpClient okHttpClient(){
return new OkHttpClient();
}
#GetMapping("/hello/feignBuilder")
public String sayHelloFeignBuilder(HttpServletRequest httpServletRequest){
logger.info("Send to request client2");
Client2Feign client2Feign = Feign.builder()
.client(client)
.decoder(new Decoder.Default())
.encoder(new Encoder.Default())
.target(Client2Feign.class, "http://localhost:8082/");
return client2Feign.sayHelloFeignBuilder();
}
#GetMapping("/hello/say")
public String sayHelloFeignBuilder1(){
return "Hello";
}
#GetMapping("/hello/rest")
public String sayHelloRest(){
System.out.println(tracer.currentSpan());
logger.info("Inside rest 1");
String baseUrl = "http://localhost:8082/sayHelloRest";
String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
logger.info("The response received by client2 is " + response);
return response;
}
}
This is yml of my client1 app. I use same yml conf on other client apps which client2 and clint3. Only changes port and app name.
server:
port: 8081
spring:
application:
name: euraka-client1
zipkin:
enabled: true
service.name: euraka-client1
sender.type: web
base-url: http://localhost:9411
eureka:
client:
serviceUrl:
defaultZone: http://localhost:8761/eureka
instance:
preferIpAddress: true
This is my Feign at Client2 app.
import feign.RequestLine;
public interface Client2Feign {
#RequestLine("GET /sayHelloBuilder")
String sayHelloFeignBuilder();
}
Here impl of ClientFeign2.
import org.springframework.web.bind.annotation.GetMapping;
import javax.servlet.http.HttpServletRequest;
public interface FeignBuilderController {
#GetMapping("/sayHelloBuilder")
String sayHelloBuilder(HttpServletRequest httpServletRequest);
#GetMapping("/sayHelloRest")
String sayHelloRest(HttpServletRequest httpServletRequest);
}
import feign.Client;
import feign.Feign;
import feign.RequestInterceptor;
import feign.codec.Decoder;
import feign.codec.Encoder;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.sleuth.Span;
import org.springframework.cloud.sleuth.Tracer;
import org.springframework.context.annotation.Bean;
import org.springframework.http.HttpMethod;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
import sample.feign.Client3Feign;
import sample.feign2.Client2Feign;
import javax.servlet.http.HttpServletRequest;
#RestController
public class FeignBuilderControllerImpl implements FeignBuilderController{
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Autowired
private RestTemplate restTemplate;
#Autowired
private Client client;
#Bean
public RestTemplate getRestTemplate() {
return new RestTemplate();
}
#Bean
public OkHttpClient okHttpClient(){
return new OkHttpClient();
}
#Override
public String sayHelloBuilder(HttpServletRequest httpServletRequest) {
logger.info("Send to request client3");
Client3Feign client3Feign = Feign.builder()
.client(client)
.decoder(new Decoder.Default())
.encoder(new Encoder.Default())
.target(Client3Feign.class, "http://localhost:8083/");
return client3Feign.sayHelloFeignBuilder3();
}
#Override
public String sayHelloRest(HttpServletRequest httpServletRequest) {
logger.info("Inside rest 2");
String baseUrl = "http://localhost:8083/sayHelloRestClient3";
String response = (String) restTemplate.exchange(baseUrl, HttpMethod.GET, null, String.class).getBody();
logger.info("The response received by client3 is " + response);
return response;
}
This is my Feign at Client3 app.
import feign.RequestLine;
public interface Client3Feign {
#RequestLine("GET /sayHelloBuilderClient3")
String sayHelloFeignBuilder3();
}
Here impl of Client3 Feign.
import javax.servlet.http.HttpServletRequest;
public interface FeignController3 {
#GetMapping("/sayHelloBuilderClient3")
String sayHello3(HttpServletRequest httpServletRequest);
#GetMapping("/sayHelloRestClient3")
String sayHelloRest3(HttpServletRequest httpServletRequest);
}
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
#RestController
#RequestMapping
public class FeignController3Impl implements FeignController3 {
private Logger logger = LoggerFactory.getLogger(this.getClass());
#Override
public String sayHello3(HttpServletRequest httpServletRequest) {
logger.info("Response returned from client3");
return "Hello from client3 using FeignClientBuilder";
}
#Override
public String sayHelloRest3(HttpServletRequest httpServletRequest) {
logger.info("Response returned from client3");
return "Hello from client3 using RestClient";
}
}
pom.xml from client3 and i use client3 at client2/pom and the same as client1.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>oguzhan.example</groupId>
<artifactId>client3</artifactId>
<version>1.0-SNAPSHOT</version>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>11</java.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-dependencies</artifactId>
<version>2.4.2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>2020.0.0</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-netflix-eureka-client</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-sleuth</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-sleuth-zipkin</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-core</artifactId>
</dependency>
<dependency>
<groupId>io.github.openfeign</groupId>
<artifactId>feign-okhttp</artifactId>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
<executions>
<execution>
<id>build-info</id>
<goals>
<goal>build-info</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.1</version>
<configuration>
<source>${java.version}</source>
<target>${java.version}</target>
<release>${java.version}</release>
</configuration>
</plugin>
</plugins>
</build>
</project>
diff-feign-rest-image
feign-zipkin-img
feign-request-img
rstlet-rest-tmplte-img
rest-zipkin-img
The problem might be related to the fact that you're creating the Feign builder manually via Feign.builder() factory method. We're unable to instrument that call. You should create a bean (via SleuthFeignBuilder.builder) and inject that into your code.

Why is PostPersist required to set the id of oneToOne child entity?

I am trying to implement bidirectional OneToOne Mapping and insert child entity(ProjectDetails.java) from parent entity(Project.java). However, entity manager is trying to insert null as id of child entity(ProjectDetails).
Error logs:
[EL Fine]: sql: 2019-08-19 01:16:50.969--ClientSession(1320691525)--Connection(926343068)--INSERT INTO project (name) VALUES (?)
bind => [Project]
[EL Fine]: sql: 2019-08-19 01:16:50.973--ClientSession(1320691525)--Connection(926343068)--SELECT ##IDENTITY
[EL Fine]: sql: 2019-08-19 01:16:50.983--ClientSession(1320691525)--Connection(926343068)--INSERT INTO project_details (project_id, details) VALUES (?, ?)
bind => [null, Details]
[EL Fine]: sql: 2019-08-19 01:16:50.986--ClientSession(1320691525)--SELECT 1
[EL Warning]: 2019-08-19 01:16:50.991--UnitOfWork(1746098804)--Exception [EclipseLink-4002] (Eclipse Persistence Services - 2.7.4.v20190115-ad5b7c6b2a): org.eclipse.persistence.exceptions.DatabaseException
Internal Exception: java.sql.SQLIntegrityConstraintViolationException: Column 'project_id' cannot be null
Error Code: 1048
I have tried by removing insertable=false, and updatable=false from #OneToOne but it gives me error, that same column can't be referenced twice.
I have following entity classes.
Class : Project
package com.example.playground.domain.dbo;
import com.example.playground.jsonviews.BasicView;
import com.example.playground.jsonviews.ProjectView;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.Data;
import lombok.ToString;
import org.eclipse.persistence.annotations.JoinFetch;
import org.eclipse.persistence.annotations.JoinFetchType;
import javax.persistence.*;
#JsonView(BasicView.class)
#Data
#Entity
#Table(name = "project")
public class Project {
#Id
#GeneratedValue(strategy = GenerationType.IDENTITY)
#Column(name="project_id")
private Integer projectId;
#Column(name="name")
private String name;
#ToString.Exclude
#JsonView(ProjectView.class)
#OneToOne(mappedBy = "project", cascade = CascadeType.ALL, optional = false)
private ProjectDetails projectDetails;
}
Class : ProjectDetails
package com.example.playground.domain.dbo;
import com.example.playground.jsonviews.BasicView;
import com.example.playground.jsonviews.ProjectDetailsView;
import com.fasterxml.jackson.annotation.JsonView;
import lombok.Data;
import lombok.ToString;
import javax.persistence.*;
#JsonView(BasicView.class)
#Data
#Entity
#Table(name = "project_details")
public class ProjectDetails {
#Id
#Column(name = "project_id")
private Integer projectId;
#ToString.Exclude
#JsonView(ProjectDetailsView.class)
#OneToOne
#JoinColumn(name = "project_id", nullable = false, insertable = false, updatable = false)
private Project project;
#Column(name = "details")
private String details;
}
class: ProjectController
package com.example.playground.web;
import com.example.playground.domain.dbo.Project;
import com.example.playground.jsonviews.ProjectView;
import com.example.playground.service.ProjectService;
import com.fasterxml.jackson.annotation.JsonView;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
#RestController
#RequestMapping("/projects")
public class ProjectController {
#Autowired
private ProjectService projectService;
#GetMapping("/{projectId}")
#JsonView(ProjectView.class)
public ResponseEntity<Project> getProject(#PathVariable Integer projectId){
Project project = projectService.getProject(projectId);
return ResponseEntity.ok(project);
}
#PostMapping
#JsonView(ProjectView.class)
public ResponseEntity<Project> createProject(#RequestBody Project projectDTO){
Project project = projectService.createProject(projectDTO);
return ResponseEntity.ok(project);
}
}
class ProjectService
package com.example.playground.service;
import com.example.playground.domain.dbo.Project;
public interface ProjectService {
Project createProject(Project projectDTO);
Project getProject(Integer projectId);
}
class ProjectServiceImpl
package com.example.playground.impl.service;
import com.example.playground.domain.dbo.Project;
import com.example.playground.repository.ProjectRepository;
import com.example.playground.service.ProjectService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
#Service
public class ProjectServiceImpl implements ProjectService {
#Autowired
private ProjectRepository projectRepository;
#Transactional
#Override
public Project createProject(Project projectDTO) {
projectDTO.getProjectDetails().setProject(projectDTO);
return projectRepository.saveAndFlush(projectDTO);
}
#Override
public Project getProject(Integer projectId) {
return projectRepository.findById(projectId).get();
}
}
JPAConfig
package com.example.playground.config;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.boot.jdbc.DataSourceBuilder;
import org.springframework.context.annotation.AdviceMode;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.orm.jpa.JpaTransactionManager;
import org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean;
import org.springframework.orm.jpa.vendor.EclipseLinkJpaVendorAdapter;
import org.springframework.transaction.annotation.EnableTransactionManagement;
import javax.persistence.EntityManagerFactory;
import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;
#Configuration
#EnableTransactionManagement(mode= AdviceMode.ASPECTJ)
public class JPAConfig{
#Bean("dataSource")
#ConfigurationProperties(prefix = "db1")
public DataSource getDataSource(){
return DataSourceBuilder.create().build();
}
#Bean("entityManagerFactory")
public LocalContainerEntityManagerFactoryBean getEntityManager(#Qualifier("dataSource") DataSource dataSource){
EclipseLinkJpaVendorAdapter adapter = new EclipseLinkJpaVendorAdapter();
LocalContainerEntityManagerFactoryBean em = new LocalContainerEntityManagerFactoryBean();
em.setPackagesToScan("com.example.playground.domain.dbo");
em.setDataSource(dataSource);
em.setJpaVendorAdapter(adapter);
em.setPersistenceUnitName("persistenceUnit");
em.setJpaPropertyMap(getVendorProperties());
return em;
}
#Bean(name = "transactionManager")
public JpaTransactionManager
transactionManager(#Qualifier("entityManagerFactory") EntityManagerFactory entityManagerFactory)
{
JpaTransactionManager transactionManager = new JpaTransactionManager();
transactionManager.setEntityManagerFactory(entityManagerFactory);
return transactionManager;
}
protected Map<String, Object> getVendorProperties()
{
HashMap<String, Object> map = new HashMap<String, Object>();
map.put("eclipselink.ddl-generation", "none");
map.put("eclipselink.ddl-generation.output-mode", "database");
map.put("eclipselink.weaving", "static");
map.put("eclipselink.logging.level.sql", "FINE");
map.put("eclipselink.logging.parameters", "true");
map.put(
"eclipselink.target-database",
"org.eclipse.persistence.platform.database.SQLServerPlatform");
return map;
}
}
and pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.1.6.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<groupId>com.example</groupId>
<artifactId>playground</artifactId>
<version>0.0.1-SNAPSHOT</version>
<name>Java-Spring-Boot-Playground</name>
<description>Java playground.</description>
<properties>
<java.version>11</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.boot/spring-boot-devtools -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework.data/spring-data-jpa -->
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-jpa</artifactId>
<version>2.1.9.RELEASE</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.springframework/spring-aspects -->
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-aspects</artifactId>
</dependency>
<!-- https://mvnrepository.com/artifact/mysql/mysql-connector-java -->
<dependency>
<groupId>mysql</groupId>
<artifactId>mysql-connector-java</artifactId>
<version>8.0.16</version>
</dependency>
<dependency>
<groupId>org.eclipse.persistence</groupId>
<artifactId>org.eclipse.persistence.jpa</artifactId>
<version>2.7.4</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.apache.tomcat/tomcat-jdbc -->
<dependency>
<groupId>org.apache.tomcat</groupId>
<artifactId>tomcat-jdbc</artifactId>
<version>9.0.21</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.projectlombok/lombok -->
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>1.18.8</version>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
Edit : Got it working, but still looking for explaination
If I add below code to my Project class , It works as expected.
#PostPersist
public void fillIds(){
projectDetails.setProjectId(this.projectId);
}
Buy why is postPersist required? Isn't JPA suppose to autofill these values given the relation is marked as oneToOne? Is there any better way?
JPA is following what you instructed it to do: You have two mappings to the "project_id", and the one with a value, the OneToOne is read-only. This means JPA must pull the value from the basic ID mapping 'projectId' which you have left as null, causing it to insert null into the field.
This is a common issue and there are a number of solutions within JPA. First would have been to mark the #ID mapping as read-only (insertable/updatable=false) and let the relationship mapping control the value.
JPA 2.0 brought in other solutions though.
For this same setup, you can mark the relationship with the #MapsId annotation. This tells JPA that the relationship foreign key value is to be used in the specified ID mapping, and will set it for you exactly as you seem to expect without the postPersist method.
Another alternative in JPA 2.0 is that you can just mark the OneToOne as the ID mapping, and remove the projectId property from the class. A more complex example is shown here

There was an unexpected error (type=Not Found, status=404). No message available

I am getting below error:
There was an unexpected error (type=Not Found, status=404). No message available
While using Spring Boot + Thymeleaf
Code:
Application class:
package com.mycom.extract;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.builder.SpringApplicationBuilder;
import org.springframework.boot.web.support.SpringBootServletInitializer;
#SpringBootApplication(scanBasePackages = "com.mycom.extract")
public class MyAppExtractionWebApplication extends SpringBootServletInitializer {
public static void main(String[] args) {
SpringApplication.run(MyAppExtractionWebApplication.class, args);
}
#Override
protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
return application.sources(MyAppExtractionWebApplication.class);
}
}
pom.xml
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.mycom.extract</groupId>
<artifactId>MyApp-extraction</artifactId>
<version>1</version>
<packaging>war</packaging>
<name>MyAppExtractionWeb</name>
<description>Demo project for Spring Boot</description>
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.5.4.RELEASE</version>
<relativePath/> <!-- lookup parent from repository -->
</parent>
<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<java.version>1.8</java.version>
</properties>
<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-thymeleaf</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-devtools</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-aop</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-integration</artifactId>
</dependency>
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-tomcat</artifactId>
<scope>provided</scope>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
<dependency>
<groupId>javax.servlet</groupId>
<artifactId>javax.servlet-api</artifactId>
</dependency>
<dependency>
<groupId>org.thymeleaf.extras</groupId>
<artifactId>thymeleaf-extras-springsecurity4</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-maven-plugin</artifactId>
</plugin>
</plugins>
</build>
</project>
SecurityConfig
package com.mycom.extract.config.security;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.web.util.matcher.AntPathRequestMatcher;
#Configuration
#EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {
#Autowired
private MyAppAuthenticationProvider authProvider;
#Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authProvider);
}
#Override
protected void configure(HttpSecurity http) throws Exception {
http.authorizeRequests()
.antMatchers("/css/**", "/login").permitAll()
.antMatchers("/*").fullyAuthenticated()
.and()
.formLogin().loginPage("/login")
.loginProcessingUrl("/j_spring_security_check")
.usernameParameter("ipn").passwordParameter("password")
.defaultSuccessUrl("/home").failureUrl("/login?error")
.and()
.logout().logoutRequestMatcher(new AntPathRequestMatcher("/logout"))
.logoutSuccessUrl("/login");
http.csrf().disable();
}
}
WebMvcConfiguration
package com.mycom.extract.config;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.ViewControllerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
#EnableAutoConfiguration
#Configuration
#ComponentScan(basePackages = { "com.mycom.extract" })
public class MyAppConfiguration extends WebMvcConfigurerAdapter{
#Override
public void addViewControllers(ViewControllerRegistry registry) {
registry.addRedirectViewController("/", "/login");
registry.addViewController("/login").setViewName("index");
registry.addViewController("/home").setViewName("home");
}
}
Referring all same kind of post in Stackoverflow could find solution for myself.
Please suggest.
URL http://localhost:8080/MyAppExtractionWeb/
As I am setting up login, and authentication is handled at security config side, so once it is successful it shows home page. Hence no controller mentioned.
package com.mycom.config.security;
import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import javax.security.auth.callback.CallbackHandler;
import javax.security.auth.login.LoginContext;
import org.springframework.beans.factory.annotation.Autowired;*/
import java.util.Collection;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.GrantedAuthority;
import com.mycom.entity.User;
import com.mycom.service.UserService;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
#Configuration
public class MyAppAuthenticationProvider implements AuthenticationProvider {
private static final String SECURITY_DOMAIN = "MyApp-ldapdomain";
#Autowired
private UserService userService;
#Override
public Authentication authenticate(Authentication authentication) {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
try {
CallbackHandler handler = new UserPasswordHandler(name, password);
LoginContext lc = new LoginContext(SECURITY_DOMAIN, handler);
lc.login();
if(lc.getSubject() != null) {
User user = userService.loadUserByUsername(name);
Collection<? extends GrantedAuthority> roles = null;
if(!user.getAuthorities().isEmpty()) {
roles = user.getAuthorities();
}
return new UsernamePasswordAuthenticationToken(name, password,roles);
} catch (Exception e) {
return null;
}
}
#Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
}

Trying to use Oauth2 token with feign client and hystrix

I am trying to call "ServiceB" from "ServiceA", both of the services are resource server, I am trying to make this inter service call through "Feign Client and OAuth2 toke" which is working fine with the below bean implmentation in Configuration class:
#Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
#Override
public void apply(RequestTemplate requestTemplate) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)
SecurityContextHolder.getContext().getAuthentication()
.getDetails();
requestTemplate.header("Authorization",
"bearer " + details.getTokenValue());
}
};
}
When I am trying to use Feign client with fallback i.e. Hystrix without OAuth token(i.e. when none of services are Resource Server) that is also working fine.
But while trying to use three of these (i.e. Feignclient, Hystrix and OAuth2)all together, it is not working. Every time it is going to fallback method though all the services are up and running.
Below are my code:
App.java
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.client.circuitbreaker.EnableCircuitBreaker;
import org.springframework.cloud.netflix.eureka.EnableEurekaClient;
import org.springframework.cloud.netflix.feign.EnableFeignClients;
import org.springframework.context.annotation.Bean;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
import org.springframework.web.bind.annotation.RestController;
import feign.RequestInterceptor;
import feign.RequestTemplate;
#SpringBootApplication
#RestController
#EnableFeignClients
#EnableEurekaClient
#EnableCircuitBreaker
public class App
{
/*#Autowired
#Qualifier("abc")
private GitHubClient gitHub;*/
#Autowired
private CallService callService;
public static void main( String[] args )
{
SpringApplication.run(App.class, args);
}
#RequestMapping(value="/feign",method=RequestMethod.POST,consumes="application/json")
public String contributors1(#RequestBody JSONObject payLoad) {
String callservice2 = callService.callservice(payLoad);
return callservice2;
}
#Bean
public RequestInterceptor requestTokenBearerInterceptor() {
return new RequestInterceptor() {
#Override
public void apply(RequestTemplate requestTemplate) {
OAuth2AuthenticationDetails details = (OAuth2AuthenticationDetails)
SecurityContextHolder.getContext().getAuthentication()
.getDetails();
requestTemplate.header("Authorization",
"bearer " + details.getTokenValue());
}
};
}
}
Callervice.java
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Service;
#Service
public class CallService {
#Autowired
#Qualifier("abc")
private GitHubClient gitHub;
public String callservice(JSONObject payLoad){
String forObject =gitHub.contributors(payLoad);
return forObject;
}
}
HystrixWrappedClient.java
import org.json.simple.JSONObject;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Qualifier;
import org.springframework.stereotype.Component;
import com.netflix.hystrix.contrib.javanica.annotation.HystrixCommand;
#Component("abc")
public class HystrixWrappedClient implements GitHubClient{
#Autowired
#Qualifier("gitHubClient")
private GitHubClient gitHub;
#Override
#HystrixCommand(fallbackMethod="failure")
public String contributors(JSONObject payLoad) {
return gitHub.contributors(payLoad);
}
public String failure(JSONObject payLoad){
System.out.println(payLoad);
return "Failure";
}
}
GitHubClient.java
import org.json.simple.JSONObject;
import org.springframework.cloud.netflix.feign.FeignClient;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestMethod;
#FeignClient("MockRestService")
interface GitHubClient {
#RequestMapping(method = RequestMethod.POST, value = "/test",consumes="application/json")
String contributors(#RequestBody JSONObject payLoad);
}
pom.xml
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>1.2.5.RELEASE</version>
</parent>
<dependencies>
<dependency>
<groupId>com.googlecode.json-simple</groupId>
<artifactId>json-simple</artifactId>
<version>1.1.1</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
<version>1.0.0.RELEASE</version>
</dependency>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
<version>1.0.1.RELEASE</version>
</dependency>
<!-- For swagger documenation -->
<dependency>
<groupId>com.mangofactory</groupId>
<artifactId>swagger-springmvc</artifactId>
<version>1.0.2</version>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-security</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-hystrix</artifactId>
</dependency>
<dependency>
<groupId>org.springframework.security.oauth</groupId>
<artifactId>spring-security-oauth2</artifactId>
</dependency>
<!-- NEW -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-feign</artifactId>
</dependency>
</dependencies>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-parent</artifactId>
<version>1.0.1.RELEASE</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
Please suggest. Whenever trying to use Feignclient, OAuth2 and Hystrix all together it always going to Fallback method.
Did you shared Spring Security context with Hystrix in some way?
Since Spring Cloud Netflix 1.2.0 you can enable sharing of security context with Hystrix using i.e config param
hystrix.shareSecurityContext: true
u can look into this http://kodgemisi.com/2017/02/use-securitycontext-feign-requestinterceptor/
Hystrix execute in another/different thread, transfer your security context by HystrixRequestVariableDefault

Resources