diff --git a/03.microservices/currency-conversion-service/pom.xml b/03.microservices/currency-conversion-service/pom.xml
index a3202e3..0e87c2b 100644
--- a/03.microservices/currency-conversion-service/pom.xml
+++ b/03.microservices/currency-conversion-service/pom.xml
@@ -28,6 +28,21 @@
org.springframework.boot
spring-boot-starter-web
+
+ org.springframework.boot
+ spring-boot-starter-thymeleaf
+
+
+ org.springframework.boot
+ spring-boot-starter-security
+
+
+
+ com.google.guava
+ guava
+ 19.0
+
+
org.springframework.cloud
spring-cloud-starter-config
@@ -56,7 +71,11 @@
org.springframework.amqp
spring-rabbit
-
+
+
+ org.springframework.kafka
+ spring-kafka
+
org.springframework.boot
@@ -69,6 +88,30 @@
spring-boot-starter-test
test
+
+
+ org.springframework.kafka
+ spring-kafka-test
+ test
+
+
+
+ io.jsonwebtoken
+ jjwt-api
+ 0.11.5
+
+
+ io.jsonwebtoken
+ jjwt-impl
+ 0.11.5
+ runtime
+
+
+ io.jsonwebtoken
+ jjwt-jackson
+ 0.11.5
+ runtime
+
@@ -89,6 +132,14 @@
org.springframework.boot
spring-boot-maven-plugin
+
+ org.apache.maven.plugins
+ maven-compiler-plugin
+
+ 16
+ 16
+
+
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionController.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionController.java
index ee56f4b..7c51534 100644
--- a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionController.java
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionController.java
@@ -5,18 +5,22 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.ResponseEntity;
+import org.springframework.security.access.prepost.PreAuthorize;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.client.RestTemplate;
@RestController
+@RequestMapping("/api")
public class CurrencyConversionController {
@Autowired
private CurrencyExchangeProxy proxy;
@GetMapping("/currency-conversion/from/{from}/to/{to}/quantity/{quantity}")
+ @PreAuthorize("hasAnyRole('ROLE_STUDENT')")
public CurrencyConversion calculateCurrencyConversion(
@PathVariable String from,
@PathVariable String to,
@@ -42,7 +46,8 @@ public CurrencyConversion calculateCurrencyConversion(
}
@GetMapping("/currency-conversion-feign/from/{from}/to/{to}/quantity/{quantity}")
- public CurrencyConversion calculateCurrencyConversionFeign(
+ @PreAuthorize("hasAuthority('course:write')")
+ public CurrencyConversion calculateCurrencyConversionFeign(
@PathVariable String from,
@PathVariable String to,
@PathVariable BigDecimal quantity
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplication.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplication.java
index e2d7f6a..7aa54f5 100644
--- a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplication.java
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/CurrencyConversionServiceApplication.java
@@ -1,8 +1,11 @@
package com.in28minutes.microservices.currencyconversionservice;
+import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.cloud.openfeign.EnableFeignClients;
+import org.springframework.context.annotation.Bean;
+import org.springframework.kafka.core.KafkaTemplate;
@SpringBootApplication
@EnableFeignClients
@@ -12,4 +15,8 @@ public static void main(String[] args) {
SpringApplication.run(CurrencyConversionServiceApplication.class, args);
}
+ @Bean
+ CommandLineRunner commandLineRunner(KafkaTemplate kafkaTemplate){
+ return args -> {kafkaTemplate.send("xecTest","hello xec from kafka");};
+ }
}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaConsumerConfig.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaConsumerConfig.java
new file mode 100644
index 0000000..1d64143
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaConsumerConfig.java
@@ -0,0 +1,58 @@
+package com.in28minutes.microservices.currencyconversionservice.Message;
+
+import org.apache.kafka.clients.consumer.ConsumerConfig;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.apache.kafka.common.serialization.StringDeserializer;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.config.ConcurrentKafkaListenerContainerFactory;
+import org.springframework.kafka.config.KafkaListenerContainerFactory;
+import org.springframework.kafka.core.ConsumerFactory;
+import org.springframework.kafka.core.DefaultKafkaConsumerFactory;
+import org.springframework.kafka.listener.ConcurrentMessageListenerContainer;
+
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class KafkaConsumerConfig {
+
+ @Value("localhost:9092")
+ private String bootstrapServers;
+
+ public Map consumerConfig() {
+ Map props = new HashMap<>();
+ props.put(ConsumerConfig.BOOTSTRAP_SERVERS_CONFIG, bootstrapServers);
+ props.put(ConsumerConfig.KEY_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+ props.put(ConsumerConfig.AUTO_OFFSET_RESET_CONFIG, "earliest");
+ props.put(ConsumerConfig.VALUE_DESERIALIZER_CLASS_CONFIG, StringDeserializer.class);
+ props.put(ConsumerConfig.GROUP_ID_CONFIG, "hello");
+ return props;
+ }
+
+
+ //creating consumer instances
+ @Bean
+ public ConsumerFactory consumerFactory() {
+ return new DefaultKafkaConsumerFactory<>((Map) consumerConfig());
+ }
+
+ //listerner container
+ @Bean
+ public KafkaListenerContainerFactory> factory(
+ ConsumerFactory consumerFactory
+ ) {
+ ConcurrentKafkaListenerContainerFactory factory = new ConcurrentKafkaListenerContainerFactory<>();
+ factory.setConsumerFactory(consumerFactory);
+ return factory;
+ }
+
+ public KafkaConsumer getConsumer() {
+ KafkaConsumer consumer = new KafkaConsumer<>(consumerConfig());
+ consumer.subscribe(Collections.singletonList("currencyConversion"));
+ return consumer;
+ }
+}
\ No newline at end of file
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaProducerConfig.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaProducerConfig.java
new file mode 100644
index 0000000..a455b8a
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaProducerConfig.java
@@ -0,0 +1,42 @@
+package com.in28minutes.microservices.currencyconversionservice.Message;
+
+import org.apache.kafka.clients.producer.ProducerConfig;
+import org.apache.kafka.common.config.ConfigDef;
+import org.apache.kafka.common.serialization.StringSerializer;
+import org.springframework.beans.factory.annotation.Value;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.core.DefaultKafkaProducerFactory;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.kafka.core.ProducerFactory;
+
+import java.util.HashMap;
+import java.util.Map;
+
+@Configuration
+public class KafkaProducerConfig {
+
+ @Value("${spring.kafka.bootstrap-servers}")
+ private String bootstrapServers;
+
+ public Map producerConfig(){
+ Map props=new HashMap<>();
+ props.put(ProducerConfig.BOOTSTRAP_SERVERS_CONFIG,bootstrapServers);
+ props.put(ProducerConfig.KEY_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ props.put(ProducerConfig.VALUE_SERIALIZER_CLASS_CONFIG, StringSerializer.class);
+ return props;
+ }
+
+
+ //creating producer instances
+ @Bean
+ public ProducerFactory producerFactory(){
+ return new DefaultKafkaProducerFactory<>(producerConfig());
+ }
+
+ //send messages
+ @Bean
+ public KafkaTemplate kafkaTemplate(ProducerFactory producerFactory){
+ return new KafkaTemplate<>(producerFactory);
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaTopicConfig.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaTopicConfig.java
new file mode 100644
index 0000000..d658088
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/KafkaTopicConfig.java
@@ -0,0 +1,20 @@
+package com.in28minutes.microservices.currencyconversionservice.Message;
+
+import org.apache.kafka.clients.admin.NewTopic;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+import org.springframework.kafka.config.TopicBuilder;
+
+@Configuration
+public class KafkaTopicConfig {
+
+ @Bean
+ public NewTopic xecTopic(){
+ return TopicBuilder.name("xecTest").build();
+ }
+
+ @Bean
+ public NewTopic currencyConversion(){
+ return TopicBuilder.name("currencyConversion").build();
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/ConsumerSuperThread.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/ConsumerSuperThread.java
new file mode 100644
index 0000000..27b7ea0
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/ConsumerSuperThread.java
@@ -0,0 +1,68 @@
+package com.in28minutes.microservices.currencyconversionservice.Message.api;
+
+import com.in28minutes.microservices.currencyconversionservice.CurrencyConversion;
+import com.in28minutes.microservices.currencyconversionservice.Message.KafkaConsumerConfig;
+import io.jsonwebtoken.lang.Collections;
+import org.apache.kafka.clients.consumer.ConsumerRecord;
+import org.apache.kafka.clients.consumer.ConsumerRecords;
+import org.apache.kafka.clients.consumer.KafkaConsumer;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.stereotype.Component;
+
+import java.math.BigDecimal;
+import java.time.Duration;
+import java.util.HashMap;
+import java.util.Map;
+
+@Component
+public class ConsumerSuperThread extends Thread {
+
+ public ConsumerSuperThread() {
+ }
+
+ Logger logger= LoggerFactory.getLogger(this.getClass());
+
+ @Autowired
+ private KafkaConsumerConfig kafkaConsumerConfig;
+
+ public Map MY_MAP=new HashMap<>();
+
+ public void triggerConsumerData(String from,String to,BigDecimal quantity){
+ if(Collections.isEmpty(MY_MAP)) {
+ this.start();
+ }else {
+ BigDecimal multiple = BigDecimal.valueOf(Long.parseLong(MY_MAP.get("multiply")));
+
+ CurrencyConversion hello_from_messaging_kafka = new CurrencyConversion(1L,
+ from, to, quantity,
+ multiple,
+ quantity.multiply(multiple),
+ "Hello from Messaging kafka");
+ System.out.println(hello_from_messaging_kafka);
+ MY_MAP.clear();
+ }
+ }
+ @Override
+ public void run() {
+ BigDecimal multiple = BigDecimal.ZERO;
+ KafkaConsumer consumer = kafkaConsumerConfig.getConsumer();
+ try {
+ while (MY_MAP.isEmpty()) {
+ ConsumerRecords records = consumer.poll(Duration.ofSeconds(5));
+ for (ConsumerRecord record : records)
+ {
+ logger.info("topic = %s, partition = %d, offset = %d, multipleKey = %s multipleValue = %s",
+ record.topic(), record.partition(), record.offset(),
+ record.key(), record.value());
+
+ MY_MAP.put("multiply", record.value().split("-")[0]);
+ }
+ }
+ } finally {
+ consumer.close();
+ }
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/CurrencyConversionKafkaController.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/CurrencyConversionKafkaController.java
new file mode 100644
index 0000000..0b11ac8
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/CurrencyConversionKafkaController.java
@@ -0,0 +1,46 @@
+package com.in28minutes.microservices.currencyconversionservice.Message.api;
+
+import com.in28minutes.microservices.currencyconversionservice.CurrencyExchangeProxy;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.security.access.prepost.PreAuthorize;
+import org.springframework.web.bind.annotation.GetMapping;
+import org.springframework.web.bind.annotation.PathVariable;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+import java.math.BigDecimal;
+import java.util.Date;
+import java.util.concurrent.ExecutionException;
+
+@RestController
+ @RequestMapping("/app")
+ public class CurrencyConversionKafkaController {
+ @Autowired
+ private CurrencyExchangeProxy proxy;
+ @Autowired
+ private KafkaTemplate kafkaTemplate;
+
+ @Autowired
+ private ConsumerSuperThread consumerSuperThread;
+
+ @GetMapping("/currency-conversion-feign/from/{from}/to/{to}/quantity/{quantity}")
+ @PreAuthorize("hasAuthority('course:write')")
+ public String calculateCurrencyConversionKafka(
+ @PathVariable String from,
+ @PathVariable String to,
+ @PathVariable BigDecimal quantity
+ ) throws ExecutionException, InterruptedException {
+ kafkaTemplate.send("currencyConversion", from + "-" + to + "-" + new Date());
+ consumerSuperThread.triggerConsumerData(from, to, quantity);
+ return "Success";
+ }
+
+ }
+
+
+
+
+
+
+
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/CurrencyConversionMessageRequest.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/CurrencyConversionMessageRequest.java
new file mode 100644
index 0000000..ffcfe7a
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/CurrencyConversionMessageRequest.java
@@ -0,0 +1,37 @@
+package com.in28minutes.microservices.currencyconversionservice.Message.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class CurrencyConversionMessageRequest {
+
+
+ @JsonProperty("requestFrom")
+ private String requestFrom;
+
+ @JsonProperty("requestTo")
+ private String requestTo;
+
+ public CurrencyConversionMessageRequest(String requestFrom,String requestTo) {
+ this.requestFrom = requestFrom;
+ this.requestTo = requestTo;
+ }
+
+ public CurrencyConversionMessageRequest() {
+ }
+
+ public String getRequestFrom() {
+ return requestFrom;
+ }
+
+ public void setRequestFrom(String requestFrom) {
+ this.requestFrom = requestFrom;
+ }
+
+ public String getRequestTo() {
+ return requestTo;
+ }
+
+ public void setRequestTo(String requestTo) {
+ this.requestTo = requestTo;
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/MessageController.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/MessageController.java
new file mode 100644
index 0000000..621cb54
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/MessageController.java
@@ -0,0 +1,28 @@
+package com.in28minutes.microservices.currencyconversionservice.Message.api;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.kafka.core.KafkaTemplate;
+import org.springframework.web.bind.annotation.PostMapping;
+import org.springframework.web.bind.annotation.RequestBody;
+import org.springframework.web.bind.annotation.RequestMapping;
+import org.springframework.web.bind.annotation.RestController;
+
+@RestController
+@RequestMapping("api/v1/messages")
+public class MessageController {
+
+ private KafkaTemplate kafkaTemplate;
+
+ @Autowired
+ public MessageController(KafkaTemplate kafkaTemplate){
+ this.kafkaTemplate=kafkaTemplate;
+ }
+
+ public MessageController(){
+ }
+
+ @PostMapping
+ public void publish(@RequestBody MessageRequest request){
+ kafkaTemplate.send("xecTest",request.getMessage());
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/MessageRequest.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/MessageRequest.java
new file mode 100644
index 0000000..823bb4d
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/api/MessageRequest.java
@@ -0,0 +1,24 @@
+package com.in28minutes.microservices.currencyconversionservice.Message.api;
+
+import com.fasterxml.jackson.annotation.JsonProperty;
+
+public class MessageRequest{
+
+ @JsonProperty("message")
+ private String message;
+
+ public MessageRequest(String message) {
+ this.message = message;
+ }
+
+ public MessageRequest() {
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public void setMessage(String message) {
+ this.message = message;
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/listner/kafkaListeners.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/listner/kafkaListeners.java
new file mode 100644
index 0000000..1d45f72
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/Message/listner/kafkaListeners.java
@@ -0,0 +1,13 @@
+package com.in28minutes.microservices.currencyconversionservice.Message.listner;
+
+import org.springframework.kafka.annotation.KafkaListener;
+import org.springframework.stereotype.Component;
+
+@Component
+public class kafkaListeners {
+
+ @KafkaListener(topics = "currencyExchange", groupId = "hello")
+ void listener(String data) {
+ System.out.println("Listener received of currencyExchange: " + data + " :)");
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUser.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUser.java
new file mode 100644
index 0000000..6af7cb2
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUser.java
@@ -0,0 +1,83 @@
+package com.in28minutes.microservices.currencyconversionservice.auth;
+
+import java.util.Collection;
+import java.util.List;
+import java.util.Set;
+
+import org.springframework.security.core.GrantedAuthority;
+import org.springframework.security.core.userdetails.UserDetails;
+
+public class ApplicationUser implements UserDetails {
+
+ private final String username;
+
+
+ private final String password;
+
+ private final Set extends GrantedAuthority> grantedAuthorities;
+
+ private final Boolean isAccountNonExpired;
+
+ private final Boolean isAccountNonLocked;
+
+ private final Boolean isCredentialsNonExpired;
+
+ private final Boolean isEnabled;
+
+
+ public ApplicationUser( String username,String password, Set extends GrantedAuthority> grantedAuthorities,
+ Boolean isAccountNonExpired, Boolean isAccountNonLocked, Boolean isCredentialsNonExpired,
+ Boolean isEnabled) {
+ super();
+ this.password = password;
+ this.username = username;
+ this.grantedAuthorities = grantedAuthorities;
+ this.isAccountNonExpired = isAccountNonExpired;
+ this.isAccountNonLocked = isAccountNonLocked;
+ this.isCredentialsNonExpired = isCredentialsNonExpired;
+ this.isEnabled = isEnabled;
+ }
+
+ @Override
+ public Collection extends GrantedAuthority> getAuthorities() {
+ // TODO Auto-generated method stub
+ return grantedAuthorities;
+ }
+
+ @Override
+ public String getPassword() {
+ // TODO Auto-generated method stub
+ return password;
+ }
+
+ @Override
+ public String getUsername() {
+ // TODO Auto-generated method stub
+ return username;
+ }
+
+ @Override
+ public boolean isAccountNonExpired() {
+ // TODO Auto-generated method stub
+ return isAccountNonExpired;
+ }
+
+ @Override
+ public boolean isAccountNonLocked() {
+ // TODO Auto-generated method stub
+ return isAccountNonLocked;
+ }
+
+ @Override
+ public boolean isCredentialsNonExpired() {
+ // TODO Auto-generated method stub
+ return isCredentialsNonExpired;
+ }
+
+ @Override
+ public boolean isEnabled() {
+ // TODO Auto-generated method stub
+ return isEnabled;
+ }
+
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUserDao.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUserDao.java
new file mode 100644
index 0000000..3e71035
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUserDao.java
@@ -0,0 +1,7 @@
+package com.in28minutes.microservices.currencyconversionservice.auth;
+
+import java.util.Optional;
+
+public interface ApplicationUserDao {
+Optional selectApplicationUserName(String username);
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUserService.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUserService.java
new file mode 100644
index 0000000..7718659
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/ApplicationUserService.java
@@ -0,0 +1,29 @@
+package com.in28minutes.microservices.currencyconversionservice.auth;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.beans.factory.annotation.Qualifier;
+import org.springframework.security.core.userdetails.UserDetails;
+import org.springframework.security.core.userdetails.UserDetailsService;
+import org.springframework.security.core.userdetails.UsernameNotFoundException;
+import org.springframework.stereotype.Service;
+
+@Service
+public class ApplicationUserService implements UserDetailsService {
+
+ private final ApplicationUserDao applicationUserDao;
+
+ @Autowired
+ public ApplicationUserService(@Qualifier("fake") ApplicationUserDao applicationUserDao) {
+ this.applicationUserDao=applicationUserDao;
+ }
+ @Override
+ public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
+ // TODO Auto-generated method stub
+ ApplicationUser applicationUser = applicationUserDao.selectApplicationUserName(username).orElseThrow(() -> new UsernameNotFoundException("user not found :" + username));
+ if(applicationUser==null || !applicationUser.isEnabled() ){
+ throw new UsernameNotFoundException(String.format("%s user not found in DB",username));
+ }
+ return applicationUser;
+ }
+
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/FakeApplicationUserDaoService.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/FakeApplicationUserDaoService.java
new file mode 100644
index 0000000..f7bc17e
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/auth/FakeApplicationUserDaoService.java
@@ -0,0 +1,78 @@
+package com.in28minutes.microservices.currencyconversionservice.auth;
+
+import java.util.List;
+import java.util.Optional;
+
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.security.crypto.password.PasswordEncoder;
+import org.springframework.stereotype.Repository;
+
+import com.google.common.collect.Lists;
+import com.in28minutes.microservices.currencyconversionservice.security.ApplicationUserRole;
+
+@Repository("fake")
+public class FakeApplicationUserDaoService implements ApplicationUserDao {
+
+
+ private final PasswordEncoder passwordEncoder;
+
+ @Autowired
+ public FakeApplicationUserDaoService(PasswordEncoder passwordEncoder) {
+ super();
+ this.passwordEncoder = passwordEncoder;
+ }
+
+ @Override
+ public Optional selectApplicationUserName(String username) {
+ // TODO Auto-generated method stub
+ return getApplicationUsers().stream().filter(user->user.getUsername().equals(username)).findFirst();
+ }
+
+ private List getApplicationUsers(){
+ List appUsers=Lists.newArrayList(
+
+ new ApplicationUser(
+ "imran",
+ passwordEncoder.encode("password"),
+ ApplicationUserRole.ADMIN.getAuthority(),
+ true,
+ true,
+ true
+ ,true),
+ new ApplicationUser(
+ "salman",
+ passwordEncoder.encode("password"),
+ ApplicationUserRole.STUDENT.getAuthority(),
+ true,
+ true,
+ true
+ ,true),
+ new ApplicationUser(
+ "imtiaz",
+ passwordEncoder.encode("password"),
+ ApplicationUserRole.STUDENT.getAuthority(),
+ true,
+ true,
+ true
+ ,true),
+ new ApplicationUser(
+ "ibrahim",
+ passwordEncoder.encode("password"),
+ ApplicationUserRole.STUDENT.getAuthority(),
+ true,
+ true,
+ true
+ ,true),
+ new ApplicationUser(
+ "heena",
+ passwordEncoder.encode("password"),
+ ApplicationUserRole.STUDENT.getAuthority(),
+ true,
+ true,
+ true
+ ,true)
+ );
+
+ return appUsers;
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomAccessDeniedHandler.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomAccessDeniedHandler.java
new file mode 100644
index 0000000..682d02c
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomAccessDeniedHandler.java
@@ -0,0 +1,53 @@
+package com.in28minutes.microservices.currencyconversionservice.exceptions;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.web.access.AccessDeniedHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class CustomAccessDeniedHandler implements AccessDeniedHandler {
+ // Jackson JSON serializer instance
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ @Override
+ public void handle(HttpServletRequest request, HttpServletResponse response, org.springframework.security.access.AccessDeniedException accessDeniedException) throws IOException, ServletException {
+
+
+ HttpStatus httpStatus = HttpStatus.FORBIDDEN; // 403
+
+ Map data = new HashMap<>();
+ data.put(
+ "timestamp",
+ new Date()
+ );
+ data.put(
+ "code",
+ httpStatus.value()
+ );
+ data.put(
+ "status",
+ httpStatus.name()
+ );
+ data.put(
+ "message",
+ accessDeniedException.getMessage() + "from Custom Access denied :)"
+ );
+
+ // setting the response HTTP status code
+ response.setStatus(httpStatus.value());
+
+ // serializing the response body in JSON
+ response
+ .getOutputStream()
+ .println(
+ objectMapper.writeValueAsString(data)
+ );
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomAuthenticationFailureHandler.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomAuthenticationFailureHandler.java
new file mode 100644
index 0000000..c1e6508
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomAuthenticationFailureHandler.java
@@ -0,0 +1,56 @@
+package com.in28minutes.microservices.currencyconversionservice.exceptions;
+
+import com.fasterxml.jackson.databind.ObjectMapper;
+import org.springframework.http.HttpStatus;
+import org.springframework.security.core.AuthenticationException;
+import org.springframework.security.web.authentication.AuthenticationFailureHandler;
+
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.Date;
+import java.util.HashMap;
+import java.util.Map;
+
+public class CustomAuthenticationFailureHandler implements AuthenticationFailureHandler {
+ // Jackson JSON serializer instance
+ private ObjectMapper objectMapper = new ObjectMapper();
+
+ @Override
+ public void onAuthenticationFailure(
+ HttpServletRequest request,
+ HttpServletResponse response,
+ AuthenticationException exception
+ ) throws IOException, ServletException {
+ HttpStatus httpStatus = HttpStatus.UNAUTHORIZED; // 401
+
+ Map data = new HashMap<>();
+ data.put(
+ "timestamp",
+ new Date()
+ );
+ data.put(
+ "code",
+ httpStatus.value()
+ );
+ data.put(
+ "status",
+ httpStatus.name()
+ );
+ data.put(
+ "message",
+ exception.getMessage()
+ );
+
+ // setting the response HTTP status code
+ response.setStatus(httpStatus.value());
+
+ // serializing the response body in JSON
+ response
+ .getOutputStream()
+ .println(
+ objectMapper.writeValueAsString(data)
+ );
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomizedResponseEntityExceptionHandler.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomizedResponseEntityExceptionHandler.java
new file mode 100644
index 0000000..2aeb2e0
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/CustomizedResponseEntityExceptionHandler.java
@@ -0,0 +1,32 @@
+package com.in28minutes.microservices.currencyconversionservice.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.http.ResponseEntity;
+import org.springframework.web.bind.annotation.ControllerAdvice;
+import org.springframework.web.bind.annotation.ExceptionHandler;
+import org.springframework.web.context.request.WebRequest;
+import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;
+
+import java.time.LocalDateTime;
+
+@ControllerAdvice
+public class CustomizedResponseEntityExceptionHandler extends ResponseEntityExceptionHandler {
+
+ @ExceptionHandler(Exception.class)
+ public final ResponseEntity handleAllExceptions(Exception ex, WebRequest request) throws Exception {
+ ErrorDetails errorDetails = new ErrorDetails(LocalDateTime.now(),
+ ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity(errorDetails, HttpStatus.INTERNAL_SERVER_ERROR);
+
+ }
+
+ @ExceptionHandler(UserNotFoundException.class)
+ public final ResponseEntity handleUserNotFoundException(Exception ex, WebRequest request) throws Exception {
+ ErrorDetails errorDetails = new ErrorDetails(LocalDateTime.now(),
+ ex.getMessage(), request.getDescription(false));
+
+ return new ResponseEntity(errorDetails, HttpStatus.NOT_FOUND);
+
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/ErrorDetails.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/ErrorDetails.java
new file mode 100644
index 0000000..f737ed8
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/ErrorDetails.java
@@ -0,0 +1,31 @@
+package com.in28minutes.microservices.currencyconversionservice.exceptions;
+
+import java.time.LocalDateTime;
+
+public class ErrorDetails {
+
+ private LocalDateTime timestamp;
+ private String message;
+ private String details;
+
+ public ErrorDetails(LocalDateTime timestamp, String message, String details) {
+ super();
+ this.timestamp = timestamp;
+ this.message = message;
+ this.details = details;
+ }
+
+ public LocalDateTime getTimestamp() {
+ return timestamp;
+ }
+
+ public String getMessage() {
+ return message;
+ }
+
+ public String getDetails() {
+ return details;
+ }
+
+
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/UserNotFoundException.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/UserNotFoundException.java
new file mode 100644
index 0000000..d8c489f
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/exceptions/UserNotFoundException.java
@@ -0,0 +1,13 @@
+package com.in28minutes.microservices.currencyconversionservice.exceptions;
+
+import org.springframework.http.HttpStatus;
+import org.springframework.web.bind.annotation.ResponseStatus;
+
+@ResponseStatus(code = HttpStatus.NOT_FOUND)
+public class UserNotFoundException extends RuntimeException {
+
+ public UserNotFoundException(String message) {
+ super(message);
+ }
+
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtManualConfig.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtManualConfig.java
new file mode 100644
index 0000000..ae05248
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtManualConfig.java
@@ -0,0 +1,45 @@
+package com.in28minutes.microservices.currencyconversionservice.jwt;
+
+import com.google.common.net.HttpHeaders;
+import org.springframework.boot.context.properties.ConfigurationProperties;
+import org.springframework.context.annotation.Configuration;
+
+@ConfigurationProperties(prefix = "application.jwt")
+@Configuration
+public class JwtManualConfig {
+
+ private String secretKey;
+ private String tokenPrefix;
+ private Integer tokenExpirationAfterDays;
+
+ public JwtManualConfig() {
+ }
+
+ public String getSecretKey() {
+ return secretKey;
+ }
+
+ public void setSecretKey(String secretKey) {
+ this.secretKey = secretKey;
+ }
+
+ public String getTokenPrefix() {
+ return tokenPrefix;
+ }
+
+ public void setTokenPrefix(String tokenPrefix) {
+ this.tokenPrefix = tokenPrefix;
+ }
+
+ public Integer getTokenExpirationAfterDays() {
+ return tokenExpirationAfterDays;
+ }
+
+ public void setTokenExpirationAfterDays(Integer tokenExpirationAfterDays) {
+ this.tokenExpirationAfterDays = tokenExpirationAfterDays;
+ }
+
+ public String getAuthorizationHeader() {
+ return HttpHeaders.AUTHORIZATION;
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtManualSecretKey.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtManualSecretKey.java
new file mode 100644
index 0000000..15fe5d3
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtManualSecretKey.java
@@ -0,0 +1,24 @@
+package com.in28minutes.microservices.currencyconversionservice.jwt;
+
+import io.jsonwebtoken.security.Keys;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.context.annotation.Bean;
+import org.springframework.context.annotation.Configuration;
+
+import javax.crypto.SecretKey;
+
+@Configuration
+public class JwtManualSecretKey {
+
+ private final JwtManualConfig jwtManualConfig;
+
+ @Autowired
+ public JwtManualSecretKey(JwtManualConfig jwtManualConfig) {
+ this.jwtManualConfig = jwtManualConfig;
+ }
+
+ @Bean
+ public SecretKey secretKey() {
+ return Keys.hmacShaKeyFor(jwtManualConfig.getSecretKey().getBytes());
+ }
+}
diff --git a/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtTokenVerifier.java b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtTokenVerifier.java
new file mode 100644
index 0000000..93238b8
--- /dev/null
+++ b/03.microservices/currency-conversion-service/src/main/java/com/in28minutes/microservices/currencyconversionservice/jwt/JwtTokenVerifier.java
@@ -0,0 +1,86 @@
+package com.in28minutes.microservices.currencyconversionservice.jwt;
+
+import com.google.common.base.Strings;
+import io.jsonwebtoken.Claims;
+import io.jsonwebtoken.Jws;
+import io.jsonwebtoken.JwtException;
+import io.jsonwebtoken.Jwts;
+import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
+import org.springframework.security.core.Authentication;
+import org.springframework.security.core.authority.SimpleGrantedAuthority;
+import org.springframework.security.core.context.SecurityContextHolder;
+import org.springframework.web.filter.OncePerRequestFilter;
+
+import javax.crypto.SecretKey;
+import javax.servlet.FilterChain;
+import javax.servlet.ServletException;
+import javax.servlet.http.HttpServletRequest;
+import javax.servlet.http.HttpServletResponse;
+import java.io.IOException;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+public class JwtTokenVerifier extends OncePerRequestFilter {
+
+ private final SecretKey secretKey;
+ private final JwtManualConfig jwtManualConfig;
+
+ public JwtTokenVerifier(SecretKey secretKey,
+ JwtManualConfig jwtManualConfig) {
+ this.secretKey = secretKey;
+ this.jwtManualConfig = jwtManualConfig;
+ }
+
+ @Override
+ protected void doFilterInternal(HttpServletRequest request,
+ HttpServletResponse response,
+ FilterChain filterChain) throws ServletException, IOException {
+
+ String authorizationHeader = request.getHeader(jwtManualConfig.getAuthorizationHeader());
+
+ if (request.getServletPath().equals("/login")) {
+ filterChain.doFilter(request, response);
+ } else {
+
+ if (Strings.isNullOrEmpty(authorizationHeader) || !authorizationHeader.startsWith(jwtManualConfig.getTokenPrefix())) {
+ filterChain.doFilter(request, response);
+ return;
+ }
+
+ String token = authorizationHeader.replace(jwtManualConfig.getTokenPrefix(), "");
+
+ try {
+
+ Jws claimsJws = Jwts.parser()
+ .setSigningKey(secretKey)
+ .parseClaimsJws(token);
+
+ Claims body = claimsJws.getBody();
+
+ String username = body.getSubject();
+
+ var authorities = (List