From d4b26da46561bfafae8c63cd61835bb564e047b6 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Sat, 14 Dec 2024 12:57:49 +0530 Subject: [PATCH 1/5] jwt implementation --- pom.xml | 52 +++++--- src/main/environment/104_ci.properties | 3 +- src/main/environment/104_dev.properties | 2 +- src/main/environment/104_example.properties | 2 +- src/main/environment/104_test.properties | 2 +- src/main/environment/104_uat.properties | 2 +- .../users/IEMRUserRepositoryCustom.java | 2 + .../iemr/helpline104/utils/CookieUtil.java | 31 +++++ .../iemr/helpline104/utils/FilterConfig.java | 19 +++ .../utils/JwtAuthenticationUtil.java | 85 +++++++++++++ .../utils/JwtUserIdValidationFilter.java | 114 ++++++++++++++++++ .../com/iemr/helpline104/utils/JwtUtil.java | 63 ++++++++++ 12 files changed, 355 insertions(+), 22 deletions(-) create mode 100644 src/main/java/com/iemr/helpline104/utils/CookieUtil.java create mode 100644 src/main/java/com/iemr/helpline104/utils/FilterConfig.java create mode 100644 src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java create mode 100644 src/main/java/com/iemr/helpline104/utils/JwtUserIdValidationFilter.java create mode 100644 src/main/java/com/iemr/helpline104/utils/JwtUtil.java diff --git a/pom.xml b/pom.xml index 7a0ab6a..25ea26c 100644 --- a/pom.xml +++ b/pom.xml @@ -39,10 +39,10 @@ org.springframework.boot spring-boot-starter - - co.elastic.logging - logback-ecs-encoder - 1.3.2 + + co.elastic.logging + logback-ecs-encoder + 1.3.2 org.springframework.boot @@ -115,8 +115,7 @@ 1.5.5.Final - + org.springframework.boot spring-boot-starter-data-jpa @@ -146,7 +145,7 @@ poi-ooxml 5.3.0 - + jakarta.ws.rs @@ -154,7 +153,7 @@ 3.1.0 - + com.google.guava guava @@ -192,14 +191,13 @@ org.springframework.boot spring-boot-starter-mail - - + + org.springframework.boot spring-boot-starter-data-redis - + org.springframework.session spring-session-data-redis @@ -219,8 +217,7 @@ jackson-datatype-joda 2.17.0 - + com.fasterxml.jackson.core jackson-databind @@ -232,9 +229,30 @@ jackson-core 2.17.0-rc1 + + + io.jsonwebtoken + jjwt-api + 0.12.6 + + + + io.jsonwebtoken + jjwt-impl + 0.12.6 + runtime + + + + io.jsonwebtoken + jjwt-jackson + 0.12.6 + runtime + + - + 104api-v3.0.0 @@ -318,8 +336,8 @@ concatenating properties file ${target-properties} and ${source-properties} - + diff --git a/src/main/environment/104_ci.properties b/src/main/environment/104_ci.properties index 7c54000..441d38b 100644 --- a/src/main/environment/104_ci.properties +++ b/src/main/environment/104_ci.properties @@ -18,4 +18,5 @@ common-url=@env.COMMON_API_BASE_URL@ spring.redis.host=localhost #ELK logging file name -logging.file.name=@env.HELPLINE104_API_LOGGING_FILE_NAME@ \ No newline at end of file +logging.file.name=@env.HELPLINE104_API_LOGGING_FILE_NAME@ +jwt.secret=@env.JWT_SECRET_KEY@ \ No newline at end of file diff --git a/src/main/environment/104_dev.properties b/src/main/environment/104_dev.properties index 3e9aa56..308886a 100644 --- a/src/main/environment/104_dev.properties +++ b/src/main/environment/104_dev.properties @@ -17,4 +17,4 @@ common-url=/commonapi-v1.0 ### Redis IP spring.redis.host=localhost - +jwt.secret= diff --git a/src/main/environment/104_example.properties b/src/main/environment/104_example.properties index 3552f5c..d1fb345 100644 --- a/src/main/environment/104_example.properties +++ b/src/main/environment/104_example.properties @@ -16,4 +16,4 @@ common-url=http://localhost:8080/commonapi-v1.0 ### Redis IP spring.redis.host=localhost - +jwt.secret= diff --git a/src/main/environment/104_test.properties b/src/main/environment/104_test.properties index 2edfe2e..82c660c 100644 --- a/src/main/environment/104_test.properties +++ b/src/main/environment/104_test.properties @@ -17,7 +17,7 @@ common-url=/commonapi-v1.0 ### Redis IP spring.redis.host=localhost - +jwt.secret= diff --git a/src/main/environment/104_uat.properties b/src/main/environment/104_uat.properties index 74cf317..daf1885 100644 --- a/src/main/environment/104_uat.properties +++ b/src/main/environment/104_uat.properties @@ -16,4 +16,4 @@ common-url=/commonapi-v1.0 ### Redis IP spring.redis.host=localhost - +jwt.secret= diff --git a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java index 3ace45a..fe7c0b7 100644 --- a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java +++ b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java @@ -59,4 +59,6 @@ public interface IEMRUserRepositoryCustom extends CrudRepository { @Query("UPDATE M_User u set u.StatusID = 2 where u.UserID = :userId") int updateSetUserStatusActive(@Param("userId") Long userId); + M_User findByUserID(Long UserID); + } diff --git a/src/main/java/com/iemr/helpline104/utils/CookieUtil.java b/src/main/java/com/iemr/helpline104/utils/CookieUtil.java new file mode 100644 index 0000000..a5a19a3 --- /dev/null +++ b/src/main/java/com/iemr/helpline104/utils/CookieUtil.java @@ -0,0 +1,31 @@ +package com.iemr.helpline104.utils; + +import java.util.Arrays; +import java.util.Optional; + +import org.springframework.stereotype.Service; + +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Service +public class CookieUtil { + + public Optional getCookieValue(HttpServletRequest request, String cookieName) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookieName.equals(cookie.getName())) { + return Optional.of(cookie.getValue()); + } + } + } + return Optional.empty(); + } + + public String getJwtTokenFromCookie(HttpServletRequest request) { + return Arrays.stream(request.getCookies()).filter(cookie -> "Jwttoken".equals(cookie.getName())) + .map(Cookie::getValue).findFirst().orElse(null); + } +} diff --git a/src/main/java/com/iemr/helpline104/utils/FilterConfig.java b/src/main/java/com/iemr/helpline104/utils/FilterConfig.java new file mode 100644 index 0000000..1e669b7 --- /dev/null +++ b/src/main/java/com/iemr/helpline104/utils/FilterConfig.java @@ -0,0 +1,19 @@ +package com.iemr.helpline104.utils; + +import org.springframework.boot.web.servlet.FilterRegistrationBean; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; + + +@Configuration +public class FilterConfig { + + @Bean + public FilterRegistrationBean jwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { + FilterRegistrationBean registrationBean = new FilterRegistrationBean<>(); + registrationBean.setFilter(new JwtUserIdValidationFilter(jwtAuthenticationUtil)); + registrationBean.addUrlPatterns("/*"); // Apply filter to all API endpoints + return registrationBean; + } + +} diff --git a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java new file mode 100644 index 0000000..ca4fb91 --- /dev/null +++ b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java @@ -0,0 +1,85 @@ +package com.iemr.helpline104.utils; + +import java.util.Optional; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.http.HttpStatus; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; + +import com.iemr.helpline104.data.users.M_User; +import com.iemr.helpline104.repository.users.IEMRUserRepositoryCustom; +import com.iemr.helpline104.utils.exception.IEMRException; + +import io.jsonwebtoken.Claims; +import jakarta.servlet.http.HttpServletRequest; + +@Component +public class JwtAuthenticationUtil { + + @Autowired + private CookieUtil cookieUtil; + @Autowired + private JwtUtil jwtUtil; + @Autowired + private IEMRUserRepositoryCustom iEMRUserRepositoryCustom; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { + this.cookieUtil = cookieUtil; + this.jwtUtil = jwtUtil; + } + + public ResponseEntity validateJwtToken(HttpServletRequest request) { + Optional jwtTokenOpt = cookieUtil.getCookieValue(request, "Jwttoken"); + + if (jwtTokenOpt.isEmpty()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("Error 401: Unauthorized - JWT Token is not set!"); + } + + String jwtToken = jwtTokenOpt.get(); + + // Validate the token + Claims claims = jwtUtil.validateToken(jwtToken); + if (claims == null) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED).body("Error 401: Unauthorized - Invalid JWT Token!"); + } + + // Extract username from token + String usernameFromToken = claims.getSubject(); + if (usernameFromToken == null || usernameFromToken.isEmpty()) { + return ResponseEntity.status(HttpStatus.UNAUTHORIZED) + .body("Error 401: Unauthorized - Username is missing!"); + } + + // Return the username if valid + return ResponseEntity.ok(usernameFromToken); + } + + public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { + try { + // Validate JWT token and extract claims + Claims claims = jwtUtil.validateToken(jwtToken); + + if (claims == null) { + throw new IEMRException("Invalid JWT token."); + } + + String userId = claims.get("userId", String.class); + + // Fetch user based on userId from the database or cache + M_User user = iEMRUserRepositoryCustom.findByUserID(Long.parseLong(userId)); + if (user == null) { + throw new IEMRException("Invalid User ID."); + } + + return true; // Valid userId and JWT token + } catch (Exception e) { + logger.error("Validation failed: " + e.getMessage(), e); + throw new IEMRException("Validation error: " + e.getMessage(), e); + } + } +} diff --git a/src/main/java/com/iemr/helpline104/utils/JwtUserIdValidationFilter.java b/src/main/java/com/iemr/helpline104/utils/JwtUserIdValidationFilter.java new file mode 100644 index 0000000..540eb6c --- /dev/null +++ b/src/main/java/com/iemr/helpline104/utils/JwtUserIdValidationFilter.java @@ -0,0 +1,114 @@ +package com.iemr.helpline104.utils; + +import java.io.IOException; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.stereotype.Component; + + +import jakarta.servlet.Filter; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.ServletRequest; +import jakarta.servlet.ServletResponse; +import jakarta.servlet.http.Cookie; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JwtUserIdValidationFilter implements Filter { + + private final JwtAuthenticationUtil jwtAuthenticationUtil; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + public JwtUserIdValidationFilter(JwtAuthenticationUtil jwtAuthenticationUtil) { + this.jwtAuthenticationUtil = jwtAuthenticationUtil; + } + + @Override + public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) + throws IOException, ServletException { + HttpServletRequest request = (HttpServletRequest) servletRequest; + HttpServletResponse response = (HttpServletResponse) servletResponse; + + String path = request.getRequestURI(); + String contextPath = request.getContextPath(); + logger.info("JwtUserIdValidationFilter invoked for path: " + path); + + // Log cookies for debugging + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if ("userId".equals(cookie.getName())) { + logger.warn("userId found in cookies! Clearing it..."); + clearUserIdCookie(response); // Explicitly remove userId cookie + } + } + } else { + logger.info("No cookies found in the request"); + } + + + // Log headers for debugging + String jwtTokenFromHeader = request.getHeader("Jwttoken"); + logger.info("JWT token from header: " + jwtTokenFromHeader); + + // Skip login and public endpoints + if (path.equals(contextPath + "/user/userAuthenticate") || + path.equalsIgnoreCase(contextPath + "/user/logOutUserFromConcurrentSession") || + path.startsWith(contextPath + "/public")) { + logger.info("Skipping filter for path: " + path); + filterChain.doFilter(servletRequest, servletResponse); + return; + } + + try { + // Retrieve JWT token from cookies + String jwtTokenFromCookie = getJwtTokenFromCookies(request); + logger.info("JWT token from cookie: " + jwtTokenFromCookie); + + // Determine which token (cookie or header) to validate + String jwtToken = jwtTokenFromCookie != null ? jwtTokenFromCookie : jwtTokenFromHeader; + if (jwtToken == null) { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "JWT token not found in cookies or headers"); + return; + } + + // Validate JWT token and userId + boolean isValid = jwtAuthenticationUtil.validateUserIdAndJwtToken(jwtToken); + + if (isValid) { + // If token is valid, allow the request to proceed + filterChain.doFilter(servletRequest, servletResponse); + } else { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Invalid JWT token"); + } + } catch (Exception e) { + logger.error("Authorization error: ", e); + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Authorization error: " + e.getMessage()); + } + } + + private String getJwtTokenFromCookies(HttpServletRequest request) { + Cookie[] cookies = request.getCookies(); + if (cookies != null) { + for (Cookie cookie : cookies) { + if (cookie.getName().equals("Jwttoken")) { + return cookie.getValue(); + } + } + } + return null; + } + + private void clearUserIdCookie(HttpServletResponse response) { + Cookie cookie = new Cookie("userId", null); + cookie.setPath("/"); + cookie.setHttpOnly(true); + cookie.setSecure(true); + cookie.setMaxAge(0); // Invalidate the cookie + response.addCookie(cookie); + } +} + diff --git a/src/main/java/com/iemr/helpline104/utils/JwtUtil.java b/src/main/java/com/iemr/helpline104/utils/JwtUtil.java new file mode 100644 index 0000000..41f0b10 --- /dev/null +++ b/src/main/java/com/iemr/helpline104/utils/JwtUtil.java @@ -0,0 +1,63 @@ +package com.iemr.helpline104.utils; + +import java.security.Key; +import java.util.Date; +import java.util.function.Function; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.stereotype.Component; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.security.Keys; + +@Component +public class JwtUtil { + + @Value("${jwt.secret}") + private String SECRET_KEY; + + private static final long EXPIRATION_TIME = 24L * 60 * 60 * 1000; // 1 day in milliseconds + + // Generate a key using the secret + private Key getSigningKey() { + if (SECRET_KEY == null || SECRET_KEY.isEmpty()) { + throw new IllegalStateException("JWT secret key is not set in application.properties"); + } + return Keys.hmacShaKeyFor(SECRET_KEY.getBytes()); + } + + // Generate JWT Token + public String generateToken(String username, String userId) { + Date now = new Date(); + Date expiryDate = new Date(now.getTime() + EXPIRATION_TIME); + + // Include the userId in the JWT claims + return Jwts.builder().setSubject(username).claim("userId", userId) // Add userId as a claim + .setIssuedAt(now).setExpiration(expiryDate).signWith(getSigningKey(), SignatureAlgorithm.HS256) + .compact(); + } + + // Validate and parse JWT Token + public Claims validateToken(String token) { + try { + return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody(); + } catch (Exception e) { + return null; // Handle token parsing/validation errors + } + } + + public String extractUsername(String token) { + return extractClaim(token, Claims::getSubject); + } + + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + private Claims extractAllClaims(String token) { + return Jwts.parser().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody(); + } +} From 8e2126f55dcdea9c8561979a3c2981240b6ef1cc Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Mon, 16 Dec 2024 00:06:05 +0530 Subject: [PATCH 2/5] corrected --- .../helpline104/repository/users/IEMRUserRepositoryCustom.java | 3 ++- .../java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java index fe7c0b7..df8d313 100644 --- a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java +++ b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java @@ -59,6 +59,7 @@ public interface IEMRUserRepositoryCustom extends CrudRepository { @Query("UPDATE M_User u set u.StatusID = 2 where u.UserID = :userId") int updateSetUserStatusActive(@Param("userId") Long userId); - M_User findByUserID(Long UserID); + @Query(" SELECT u FROM M_User u WHERE u.userID = :userID AND u.Deleted = false ") + public M_User getUserByUserID(@Param("userID") Long userID); } diff --git a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java index ca4fb91..94b2377 100644 --- a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java @@ -71,7 +71,7 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { String userId = claims.get("userId", String.class); // Fetch user based on userId from the database or cache - M_User user = iEMRUserRepositoryCustom.findByUserID(Long.parseLong(userId)); + M_User user = iEMRUserRepositoryCustom.getUserByUserID(Long.parseLong(userId)); if (user == null) { throw new IEMRException("Invalid User ID."); } From fa0c5c93178f0af18c9dad536d871bb64449f730 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Mon, 16 Dec 2024 00:32:50 +0530 Subject: [PATCH 3/5] repo modified --- .../repository/users/IEMRUserRepositoryCustom.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java index df8d313..84cd04c 100644 --- a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java +++ b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java @@ -59,7 +59,7 @@ public interface IEMRUserRepositoryCustom extends CrudRepository { @Query("UPDATE M_User u set u.StatusID = 2 where u.UserID = :userId") int updateSetUserStatusActive(@Param("userId") Long userId); - @Query(" SELECT u FROM M_User u WHERE u.userID = :userID AND u.Deleted = false ") - public M_User getUserByUserID(@Param("userID") Long userID); + @Query(" SELECT u FROM M_User u WHERE u.UserID = :UserID AND u.Deleted = false ") + public M_User getUserByUserID(@Param("UserID") Long UserID); } From 39e98b9bb3872be6169c66a26ae5e1c387d32e46 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Thu, 19 Dec 2024 12:32:31 +0530 Subject: [PATCH 4/5] use fetch from redis concept --- src/main/java/com/iemr/helpline104/App.java | 37 ++++++++++++------ .../iemr/helpline104/config/RedisConfig.java | 38 +++++++++++++++++++ .../iemr/helpline104/data/users/M_User.java | 5 ++- .../users/IEMRUserRepositoryCustom.java | 3 -- .../utils/JwtAuthenticationUtil.java | 20 ++++++++-- 5 files changed, 84 insertions(+), 19 deletions(-) create mode 100644 src/main/java/com/iemr/helpline104/config/RedisConfig.java diff --git a/src/main/java/com/iemr/helpline104/App.java b/src/main/java/com/iemr/helpline104/App.java index e24eac0..4dd7bfd 100644 --- a/src/main/java/com/iemr/helpline104/App.java +++ b/src/main/java/com/iemr/helpline104/App.java @@ -25,14 +25,16 @@ import org.springframework.boot.autoconfigure.SpringBootApplication; import org.springframework.boot.builder.SpringApplicationBuilder; import org.springframework.boot.web.servlet.support.SpringBootServletInitializer; -import org.springframework.cache.annotation.EnableCaching; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; -import org.springframework.transaction.annotation.EnableTransactionManagement; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.RestController; +import com.iemr.helpline104.data.users.M_User; import com.iemr.helpline104.utils.IEMRApplBeans; import com.iemr.helpline104.utils.config.ConfigProperties; @@ -50,20 +52,18 @@ public class App extends SpringBootServletInitializer { @Bean public ConfigProperties configProperties() { - return new ConfigProperties(); - } - + return new ConfigProperties(); + } + public static void main(String[] args) { SpringApplication.run(applicationClass, args); } - + @Bean - public IEMRApplBeans instantiateBeans() - { + public IEMRApplBeans instantiateBeans() { return new IEMRApplBeans(); } - @Override protected SpringApplicationBuilder configure(SpringApplicationBuilder application) { return application.sources(applicationClass); @@ -75,12 +75,25 @@ protected SpringApplicationBuilder configure(SpringApplicationBuilder applicatio @RestController class HelloController { - @PostMapping(value ="/hello/{name}", produces = MediaType.APPLICATION_JSON) + @PostMapping(value = "/hello/{name}", produces = MediaType.APPLICATION_JSON) public String hello(@PathVariable String name) { return "Hi " + name + " !"; } -} + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + + // Use StringRedisSerializer for keys (userId) + template.setKeySerializer(new StringRedisSerializer()); + + // Use Jackson2JsonRedisSerializer for values (Users objects) + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(M_User.class); + template.setValueSerializer(serializer); + return template; + } +} diff --git a/src/main/java/com/iemr/helpline104/config/RedisConfig.java b/src/main/java/com/iemr/helpline104/config/RedisConfig.java new file mode 100644 index 0000000..755b966 --- /dev/null +++ b/src/main/java/com/iemr/helpline104/config/RedisConfig.java @@ -0,0 +1,38 @@ +package com.iemr.helpline104.config; + +import org.springframework.cache.annotation.EnableCaching; +import org.springframework.context.annotation.Bean; +import org.springframework.context.annotation.Configuration; +import org.springframework.data.redis.connection.RedisConnectionFactory; +import org.springframework.data.redis.core.RedisTemplate; +import org.springframework.data.redis.serializer.Jackson2JsonRedisSerializer; +import org.springframework.data.redis.serializer.StringRedisSerializer; +import org.springframework.session.data.redis.config.ConfigureRedisAction; + +import com.iemr.helpline104.data.users.M_User; + +@Configuration +@EnableCaching +public class RedisConfig { + + @Bean + public ConfigureRedisAction configureRedisAction() { + return ConfigureRedisAction.NO_OP; + } + + @Bean + public RedisTemplate redisTemplate(RedisConnectionFactory factory) { + RedisTemplate template = new RedisTemplate<>(); + template.setConnectionFactory(factory); + + // Use StringRedisSerializer for keys (userId) + template.setKeySerializer(new StringRedisSerializer()); + + // Use Jackson2JsonRedisSerializer for values (Users objects) + Jackson2JsonRedisSerializer serializer = new Jackson2JsonRedisSerializer<>(M_User.class); + template.setValueSerializer(serializer); + + return template; + } + +} diff --git a/src/main/java/com/iemr/helpline104/data/users/M_User.java b/src/main/java/com/iemr/helpline104/data/users/M_User.java index 28d2313..853b147 100644 --- a/src/main/java/com/iemr/helpline104/data/users/M_User.java +++ b/src/main/java/com/iemr/helpline104/data/users/M_User.java @@ -21,6 +21,7 @@ */ package com.iemr.helpline104.data.users; +import java.io.Serializable; import java.sql.Timestamp; import java.util.Set; @@ -35,12 +36,14 @@ import jakarta.persistence.OrderBy; import jakarta.persistence.Transient; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.iemr.helpline104.data.userbeneficiarydata.M_Gender; import com.iemr.helpline104.data.userbeneficiarydata.M_MaritalStatus; import com.iemr.helpline104.data.userbeneficiarydata.M_Status; @Entity -public class M_User { +@JsonIgnoreProperties(ignoreUnknown = true) +public class M_User implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) private Long UserID; diff --git a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java index 84cd04c..3ace45a 100644 --- a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java +++ b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java @@ -59,7 +59,4 @@ public interface IEMRUserRepositoryCustom extends CrudRepository { @Query("UPDATE M_User u set u.StatusID = 2 where u.UserID = :userId") int updateSetUserStatusActive(@Param("userId") Long userId); - @Query(" SELECT u FROM M_User u WHERE u.UserID = :UserID AND u.Deleted = false ") - public M_User getUserByUserID(@Param("UserID") Long UserID); - } diff --git a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java index 94b2377..e416b69 100644 --- a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java @@ -5,6 +5,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.data.redis.core.RedisTemplate; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.stereotype.Component; @@ -24,7 +25,7 @@ public class JwtAuthenticationUtil { @Autowired private JwtUtil jwtUtil; @Autowired - private IEMRUserRepositoryCustom iEMRUserRepositoryCustom; + private RedisTemplate redisTemplate; private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { @@ -70,8 +71,8 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { String userId = claims.get("userId", String.class); - // Fetch user based on userId from the database or cache - M_User user = iEMRUserRepositoryCustom.getUserByUserID(Long.parseLong(userId)); + // Check if user data is present in Redis + M_User user = getUserFromCache(userId); if (user == null) { throw new IEMRException("Invalid User ID."); } @@ -82,4 +83,17 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { throw new IEMRException("Validation error: " + e.getMessage(), e); } } + + private M_User getUserFromCache(String userId) { + String redisKey = "user_" + userId; // The Redis key format + M_User user = (M_User) redisTemplate.opsForValue().get(redisKey); + + if (user == null) { + logger.warn("User not found in Redis."); + } else { + logger.info("User fetched successfully from Redis."); + } + + return user; // Returns null if not found + } } From ccb4c30ef0add58d3466f204429e918be16d961c Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Tue, 24 Dec 2024 13:58:10 +0530 Subject: [PATCH 5/5] user fetch concept modify --- .../users/IEMRUserRepositoryCustom.java | 3 ++ .../utils/JwtAuthenticationUtil.java | 29 ++++++++++++++++++- 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java index 3ace45a..84cd04c 100644 --- a/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java +++ b/src/main/java/com/iemr/helpline104/repository/users/IEMRUserRepositoryCustom.java @@ -59,4 +59,7 @@ public interface IEMRUserRepositoryCustom extends CrudRepository { @Query("UPDATE M_User u set u.StatusID = 2 where u.UserID = :userId") int updateSetUserStatusActive(@Param("userId") Long userId); + @Query(" SELECT u FROM M_User u WHERE u.UserID = :UserID AND u.Deleted = false ") + public M_User getUserByUserID(@Param("UserID") Long UserID); + } diff --git a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java index e416b69..2f255a0 100644 --- a/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/iemr/helpline104/utils/JwtAuthenticationUtil.java @@ -1,6 +1,7 @@ package com.iemr.helpline104.utils; import java.util.Optional; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -26,6 +27,8 @@ public class JwtAuthenticationUtil { private JwtUtil jwtUtil; @Autowired private RedisTemplate redisTemplate; + @Autowired + private IEMRUserRepositoryCustom iEMRUserRepositoryCustom; private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { @@ -73,6 +76,10 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws IEMRException { // Check if user data is present in Redis M_User user = getUserFromCache(userId); + if (user == null) { + // If not in Redis, fetch from DB and cache the result + user = fetchUserFromDB(userId); + } if (user == null) { throw new IEMRException("Invalid User ID."); } @@ -89,11 +96,31 @@ private M_User getUserFromCache(String userId) { M_User user = (M_User) redisTemplate.opsForValue().get(redisKey); if (user == null) { - logger.warn("User not found in Redis."); + logger.warn("User not found in Redis. Will try to fetch from DB."); } else { logger.info("User fetched successfully from Redis."); } return user; // Returns null if not found } + + private M_User fetchUserFromDB(String userId) { + // This method will only be called if the user is not found in Redis. + String redisKey = "user_" + userId; // Redis key format + + // Fetch user from DB + M_User user = iEMRUserRepositoryCustom.getUserByUserID(Long.parseLong(userId)); + + if (user != null) { + // Cache the user in Redis for future requests (cache for 30 minutes) + redisTemplate.opsForValue().set(redisKey, user, 30, TimeUnit.MINUTES); + + // Log that the user has been stored in Redis + logger.info("User stored in Redis with key: " + redisKey); + } else { + logger.warn("User not found for userId: " + userId); + } + + return user; + } }