From bc626843d381ae5379a76b827431eebba28cd833 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Tue, 10 Dec 2024 20:18:16 +0530 Subject: [PATCH 1/5] jwt implementation changes --- pom.xml | 40 +++++-- src/main/environment/common_ci.properties | 3 +- src/main/environment/common_dev.properties | 1 + .../environment/common_example.properties | 1 + src/main/environment/common_test.properties | 1 + .../java/com/wipro/fhir/data/users/User.java | 74 ++++++++++++ .../wipro/fhir/repo/user/UserRepository.java | 11 ++ .../service/common/CommonServiceImpl.java | 81 ++++++++----- .../java/com/wipro/fhir/utils/CookieUtil.java | 41 +++++++ .../com/wipro/fhir/utils/FilterConfig.java | 19 +++ .../fhir/utils/JwtAuthenticationUtil.java | 91 +++++++++++++++ .../fhir/utils/JwtUserIdValidationFilter.java | 109 ++++++++++++++++++ .../java/com/wipro/fhir/utils/JwtUtil.java | 68 +++++++++++ 13 files changed, 499 insertions(+), 41 deletions(-) create mode 100644 src/main/java/com/wipro/fhir/data/users/User.java create mode 100644 src/main/java/com/wipro/fhir/repo/user/UserRepository.java create mode 100644 src/main/java/com/wipro/fhir/utils/CookieUtil.java create mode 100644 src/main/java/com/wipro/fhir/utils/FilterConfig.java create mode 100644 src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java create mode 100644 src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java create mode 100644 src/main/java/com/wipro/fhir/utils/JwtUtil.java diff --git a/pom.xml b/pom.xml index 57f1585..1250077 100644 --- a/pom.xml +++ b/pom.xml @@ -58,10 +58,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 @@ -189,8 +189,7 @@ spring-boot-starter-mail - + ca.uhn.hapi.fhir hapi-fhir-structures-r4 @@ -198,8 +197,7 @@ - + ca.uhn.hapi.fhir org.hl7.fhir.utilities @@ -235,6 +233,27 @@ json-path 2.9.0 + + + io.jsonwebtoken + jjwt-api + 0.12.6 + + + + io.jsonwebtoken + jjwt-impl + 0.12.6 + runtime + + + + io.jsonwebtoken + jjwt-jackson + 0.12.6 + runtime + + @@ -250,7 +269,7 @@ HTML nvd - + org.apache.maven.plugins @@ -329,8 +348,7 @@ ${target-properties} and ${source-properties} - diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index 440eeea..f2e3955 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -95,4 +95,5 @@ logging.level.com.iemr=DEBUG logging.level.org.springframework=INFO #ELK logging file name -logging.file.name=@env.FHIR_API_LOGGING_FILE_NAME@ \ No newline at end of file +logging.file.name=@env.FHIR_API_LOGGING_FILE_NAME@ +jwt.secret=@JWT_SECRET_KEY@ \ No newline at end of file diff --git a/src/main/environment/common_dev.properties b/src/main/environment/common_dev.properties index f7484b6..6b5ba85 100644 --- a/src/main/environment/common_dev.properties +++ b/src/main/environment/common_dev.properties @@ -93,3 +93,4 @@ logging.level.org.springframework.web=INFO logging.level.org.hibernate=INFO logging.level.com.iemr=DEBUG logging.level.org.springframework=INFO +jwt.secret=@JWT_SECRET_KEY@ diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index dee5c20..502c64e 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -93,3 +93,4 @@ logging.level.org.springframework.web=INFO logging.level.org.hibernate=INFO logging.level.com.iemr=DEBUG logging.level.org.springframework=INFO +jwt.secret=@JWT_SECRET_KEY@ diff --git a/src/main/environment/common_test.properties b/src/main/environment/common_test.properties index f7484b6..6b5ba85 100644 --- a/src/main/environment/common_test.properties +++ b/src/main/environment/common_test.properties @@ -93,3 +93,4 @@ logging.level.org.springframework.web=INFO logging.level.org.hibernate=INFO logging.level.com.iemr=DEBUG logging.level.org.springframework=INFO +jwt.secret=@JWT_SECRET_KEY@ diff --git a/src/main/java/com/wipro/fhir/data/users/User.java b/src/main/java/com/wipro/fhir/data/users/User.java new file mode 100644 index 0000000..b37e3b2 --- /dev/null +++ b/src/main/java/com/wipro/fhir/data/users/User.java @@ -0,0 +1,74 @@ +package com.wipro.fhir.data.users; + +import java.sql.Timestamp; + +import com.google.gson.annotations.Expose; + +import jakarta.persistence.Column; +import jakarta.persistence.Entity; +import jakarta.persistence.GeneratedValue; +import jakarta.persistence.GenerationType; +import jakarta.persistence.Id; +import jakarta.persistence.Table; +import lombok.Data; + +@Entity +@Table(name = "m_user") +@Data +public class User { + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Expose + @Column(name = "UserID") + private Long userID; + + @Expose + @Column(name = "TitleID") + private Integer titleID; + @Expose + @Column(name = "FirstName") + private String firstName; + @Expose + @Column(name = "MiddleName") + private String middleName; + @Expose + @Column(name = "LastName") + private String lastName; + + @Expose + @Column(name = "GenderID") + private Integer genderID; + + @Expose + @Column(name = "MaritalStatusID") + private Integer maritalStatusID; + + @Expose + @Column(name = "StatusID") + private Integer statusID; + + @Expose + @Column(name = "DOB") + private Timestamp dOB; + @Expose + @Column(name = "DOJ") + private Timestamp dOJ; + @Expose + @Column(name = "QualificationID") + private Integer qualificationID; + @Expose + @Column(name = "userName") + private String userName; + @Expose + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; + @Expose + @Column(name = "CreatedBy") + private String createdBy; + @Column(name = "CreatedDate", insertable = false, updatable = false) + private Timestamp createdDate; + @Column(name = "ModifiedBy") + private String modifiedBy; + @Column(name = "LastModDate", insertable = false, updatable = false) + private Timestamp lastModDate; +} diff --git a/src/main/java/com/wipro/fhir/repo/user/UserRepository.java b/src/main/java/com/wipro/fhir/repo/user/UserRepository.java new file mode 100644 index 0000000..0379062 --- /dev/null +++ b/src/main/java/com/wipro/fhir/repo/user/UserRepository.java @@ -0,0 +1,11 @@ +package com.wipro.fhir.repo.user; + +import org.springframework.data.repository.CrudRepository; + +import com.wipro.fhir.data.users.User; + +public interface UserRepository extends CrudRepository { + + User findByUserID(Long userID); + +} diff --git a/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java b/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java index 24c51c8..ac4fcef 100644 --- a/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java +++ b/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java @@ -65,6 +65,7 @@ import com.wipro.fhir.data.patient_data_handler.PatientDemographicModel_NDHM_Patient_Profile; import com.wipro.fhir.data.request_handler.PatientEligibleForResourceCreation; import com.wipro.fhir.data.request_handler.ResourceRequestHandler; +import com.wipro.fhir.data.users.User; import com.wipro.fhir.repo.common.PatientEligibleForResourceCreationRepo; import com.wipro.fhir.repo.healthID.BenHealthIDMappingRepo; import com.wipro.fhir.repo.mongo.amrit_resource.AMRIT_ResourceMongoRepo; @@ -72,6 +73,7 @@ import com.wipro.fhir.repo.mongo.amrit_resource.TempCollectionRepo; import com.wipro.fhir.repo.mongo.ndhm_response.NDHMResponseRepo; import com.wipro.fhir.repo.patient_data_handler.PatientDemographicModel_NDHM_Patient_Profile_Repo; +import com.wipro.fhir.repo.user.UserRepository; import com.wipro.fhir.service.api_channel.APIChannel; import com.wipro.fhir.service.ndhm.Common_NDHMService; import com.wipro.fhir.service.ndhm.GenerateSession_NDHMService; @@ -96,16 +98,16 @@ public class CommonServiceImpl implements CommonService { @Value("${patient-search-page-size}") private String patient_search_page_size; - + @Value("${abhaMode}") private String abhaMode; private static String authKey; private UUID uuid; - //public static String NDHM_AUTH_TOKEN; - //public static Long NDHM_TOKEN_EXP; - //public static String NDHM_OTP_TOKEN; + // public static String NDHM_AUTH_TOKEN; + // public static Long NDHM_TOKEN_EXP; + // public static String NDHM_OTP_TOKEN; @Value("${clientID}") private String clientID; @@ -127,7 +129,6 @@ public class CommonServiceImpl implements CommonService { private APIChannel aPIChannel; @Autowired private AMRIT_ResourceMongoRepo aMRIT_ResourceMongoRepo; - @Autowired private PatientCareContextsMongoRepo patientCareContextsMongoRepo; @@ -148,7 +149,7 @@ public class CommonServiceImpl implements CommonService { @Autowired private PatientDataGatewayService patientDataGatewayService; - + @Autowired private MongoTemplate mongoTemplate; @@ -159,16 +160,19 @@ public class CommonServiceImpl implements CommonService { private PatientDemographic patientDemographic; @Autowired private Common_NDHMService common_NDHMService; - + @Autowired private BenHealthIDMappingRepo benHealthIDMappingRepo; + @Autowired + private UserRepository userRepository; @Override public String processResourceOperation() throws FHIRException { String response = null; // list of patient eligible for resource creation List pList = getPatientListForResourceEligible(); - logger.info("No of records available to create FHIR in last 2 dagetPatientListForResourceEligibleys : " + pList.size()); + logger.info("No of records available to create FHIR in last 2 dagetPatientListForResourceEligibleys : " + + pList.size()); ResourceRequestHandler resourceRequestHandler; for (PatientEligibleForResourceCreation p : pList) { @@ -196,10 +200,11 @@ public String processResourceOperation() throws FHIRException { if (patientDemographicOBJ.getPreferredPhoneNo() != null) sendAbdmAdvSMS(patientDemographicOBJ.getPreferredPhoneNo()); else - throw new FHIRException("Advertisement sms could not be sent as beneficiary phone no not found"); - } - else - throw new FHIRException("Beneficiary not found, benRegId = " +resourceRequestHandler.getBeneficiaryRegID()); + throw new FHIRException( + "Advertisement sms could not be sent as beneficiary phone no not found"); + } else + throw new FHIRException( + "Beneficiary not found, benRegId = " + resourceRequestHandler.getBeneficiaryRegID()); } catch (Exception e) { logger.error(e.getMessage()); @@ -324,28 +329,28 @@ public int addCareContextToMongo(PatientDemographic pDemo, PatientEligibleForRes // get benid // if (benRegID != null) // benID = benHealthIDMappingRepo.getBenID(benRegID); - - // fetch abdm facility id - logger.info("********t_benvisistData fetch request pvisit data :" , pVisit); + + // fetch abdm facility id + logger.info("********t_benvisistData fetch request pvisit data :", pVisit); List res = benHealthIDMappingRepo.getAbdmFacilityAndlinkedDate(pVisit.getVisitCode()); - + // check care context record in mongo against beneficiaryID ArrayList ccList = new ArrayList<>(); CareContexts cc = new CareContexts(); - + logger.info("********t_benvisistData fetch response : {}", res); cc.setReferenceNumber(pVisit.getVisitCode() != null ? pVisit.getVisitCode().toString() : null); - cc.setDisplay(pVisit.getVisitCategory() != null ? pVisit.getVisitCategory().toString() : null); + cc.setDisplay(pVisit.getVisitCategory() != null ? pVisit.getVisitCategory().toString() : null); Object[] resData = null; if (res.get(0) != null) { resData = res.get(0); - cc.setAbdmFacilityId(resData[0] != null ? resData[0].toString() : null ); - cc.setCareContextLinkedDate(resData[1] != null ? resData[1].toString() : null); + cc.setAbdmFacilityId(resData[0] != null ? resData[0].toString() : null); + cc.setCareContextLinkedDate(resData[1] != null ? resData[1].toString() : null); } - - logger.info("********data to be saved in mongo :" , cc); + + logger.info("********data to be saved in mongo :", cc); PatientCareContexts pcc; PatientCareContexts resultSet; @@ -357,7 +362,7 @@ public int addCareContextToMongo(PatientDemographic pDemo, PatientEligibleForRes ccList.add(cc); pcc.setCareContextsList(ccList); resultSet = patientCareContextsMongoRepo.save(pcc); - + } else { pcc = new PatientCareContexts(); pcc.setCaseReferenceNumber(pDemo.getBeneficiaryID().toString()); @@ -423,7 +428,7 @@ public String ndhmUserAuthenticate() throws FHIRException { JsonParser jsnParser = new JsonParser(); JsonElement jsnElmnt = jsnParser.parse(responseStrLogin); jsnOBJ = jsnElmnt.getAsJsonObject(); - //NDHM_AUTH_TOKEN = "Bearer" + " " + jsnOBJ.get("accessToken").getAsString(); + // NDHM_AUTH_TOKEN = "Bearer" + " " + jsnOBJ.get("accessToken").getAsString(); Integer expiry = jsnOBJ.get("expiresIn").getAsInt(); double time = expiry / 60; Date date = new Date(); @@ -431,7 +436,7 @@ public String ndhmUserAuthenticate() throws FHIRException { Calendar ndhmCalendar = Calendar.getInstance(); ndhmCalendar.setTime(sqlDate); ndhmCalendar.add(Calendar.MINUTE, (int) time); - + res = "success"; } else res = "Error while accessing authenticate API"; @@ -477,7 +482,7 @@ public List fetchTempResourceFromMongo(ResourceRequestHandler re * @author SH20094090 * @return * - * get the UUID and isoTimestamp for NDMH API's + * get the UUID and isoTimestamp for NDMH API's */ @Deprecated @Override @@ -541,7 +546,7 @@ public String getMongoNDHMResponse(String requestID) throws FHIRException { * @param reqID * @return * - * hitting MongoDB + * hitting MongoDB */ @Deprecated NDHMResponse getResponseMongo(String reqID) { @@ -628,8 +633,8 @@ public void sendAbdmAdvSMS(String phone) throws FHIRException { SMSNotify smsNotify = new SMSNotify(obj.getRequestId(), obj.getTimestamp(), notification); String requestOBJ = new Gson().toJson(smsNotify); logger.info("NDHM_FHIR Generate Notify SMS request Obj: " + requestOBJ); - if(abhaMode !=null && !(abhaMode.equalsIgnoreCase("abdm") || abhaMode.equalsIgnoreCase("sbx"))) - abhaMode="sbx"; + if (abhaMode != null && !(abhaMode.equalsIgnoreCase("abdm") || abhaMode.equalsIgnoreCase("sbx"))) + abhaMode = "sbx"; HttpHeaders headers = common_NDHMService.getHeaders(ndhmAuthToken, abhaMode); ResponseEntity responseEntity = httpUtils.postWithResponseEntity(generateABDM_NotifySMS, requestOBJ, headers); @@ -646,4 +651,22 @@ public void sendAbdmAdvSMS(String phone) throws FHIRException { } + public User getUserById(Long userId) throws Exception { + try { + // Fetch user from custom repository by userId + User user = userRepository.findByUserID(userId); + + // Check if user is found + if (user == null) { + throw new Exception("User not found with ID: " + userId); + } + + return user; + } catch (Exception e) { + // Log and throw custom exception in case of errors + logger.error("Error fetching user with ID: " + userId, e); + throw new Exception("Error fetching user with ID: " + userId, e); + } + } + } diff --git a/src/main/java/com/wipro/fhir/utils/CookieUtil.java b/src/main/java/com/wipro/fhir/utils/CookieUtil.java new file mode 100644 index 0000000..53e5eee --- /dev/null +++ b/src/main/java/com/wipro/fhir/utils/CookieUtil.java @@ -0,0 +1,41 @@ +package com.wipro.fhir.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 void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response) { + // Create a new cookie with the JWT token + Cookie cookie = new Cookie("Jwttoken", Jwttoken); + cookie.setHttpOnly(true); // Prevent JavaScript access for security + cookie.setSecure(true); // Ensure the cookie is sent only over HTTPS + cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time + cookie.setPath("/"); // Make the cookie available for the entire application + response.addCookie(cookie); // Add the cookie to the response + } + + 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/wipro/fhir/utils/FilterConfig.java b/src/main/java/com/wipro/fhir/utils/FilterConfig.java new file mode 100644 index 0000000..5a7ef36 --- /dev/null +++ b/src/main/java/com/wipro/fhir/utils/FilterConfig.java @@ -0,0 +1,19 @@ +package com.wipro.fhir.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/wipro/fhir/utils/JwtAuthenticationUtil.java b/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java new file mode 100644 index 0000000..a424c97 --- /dev/null +++ b/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java @@ -0,0 +1,91 @@ +package com.wipro.fhir.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.wipro.fhir.data.users.User; +import com.wipro.fhir.service.common.CommonServiceImpl; + +import io.jsonwebtoken.Claims; +import jakarta.servlet.http.HttpServletRequest; + +@Component +public class JwtAuthenticationUtil { + + @Autowired + private CookieUtil cookieUtil; + @Autowired + private JwtUtil jwtUtil; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); + + @Autowired + private CommonServiceImpl commonServiceImpl; + + 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 Exception { + try { + // Validate JWT token and extract claims + Claims claims = jwtUtil.validateToken(jwtToken); + + if (claims == null) { + throw new Exception("Invalid JWT token."); + } + + String userId = claims.get("userId", String.class); + String tokenUsername = jwtUtil.extractUsername(jwtToken); + + // Fetch user based on userId from the database or cache + User user = commonServiceImpl.getUserById(Long.parseLong(userId)); + if (user == null) { + throw new Exception("Invalid User ID."); + } + + // Check if the token's username matches the user retrieved by userId + if (!user.getUserName().equalsIgnoreCase(tokenUsername)) { + throw new Exception("JWT token and User ID mismatch."); + } + + return true; // Valid userId and JWT token + } catch (Exception e) { + logger.error("Validation failed: " + e.getMessage(), e); + throw new Exception("Validation error: " + e.getMessage(), e); + } + } +} diff --git a/src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java b/src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java new file mode 100644 index 0000000..ba8b4cc --- /dev/null +++ b/src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java @@ -0,0 +1,109 @@ +package com.wipro.fhir.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: "); + + // 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: "); + + // 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.setMaxAge(0); // Invalidate the cookie + response.addCookie(cookie); + } +} diff --git a/src/main/java/com/wipro/fhir/utils/JwtUtil.java b/src/main/java/com/wipro/fhir/utils/JwtUtil.java new file mode 100644 index 0000000..7f4cdf0 --- /dev/null +++ b/src/main/java/com/wipro/fhir/utils/JwtUtil.java @@ -0,0 +1,68 @@ +package com.wipro.fhir.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 = 24 * 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 { + // Use the JwtParserBuilder correctly in version 0.12.6 + return Jwts.parser() // Correct method in 0.12.6 to get JwtParserBuilder + .setSigningKey(getSigningKey()) // Set the signing key + .build() // Build the JwtParser + .parseClaimsJws(token) // Parse and validate the 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 43d52e99a4b5fa8a21ca45b59ccad7071d4463c8 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Sat, 14 Dec 2024 12:50:53 +0530 Subject: [PATCH 2/5] fixed issues --- src/main/environment/common_ci.properties | 2 +- src/main/environment/common_dev.properties | 2 +- .../environment/common_example.properties | 2 +- src/main/environment/common_test.properties | 2 +- .../java/com/wipro/fhir/data/users/User.java | 53 ------------------- .../java/com/wipro/fhir/utils/CookieUtil.java | 10 ---- .../fhir/utils/JwtAuthenticationUtil.java | 6 --- .../fhir/utils/JwtUserIdValidationFilter.java | 2 + .../java/com/wipro/fhir/utils/JwtUtil.java | 2 +- 9 files changed, 7 insertions(+), 74 deletions(-) diff --git a/src/main/environment/common_ci.properties b/src/main/environment/common_ci.properties index f2e3955..929bdc9 100644 --- a/src/main/environment/common_ci.properties +++ b/src/main/environment/common_ci.properties @@ -96,4 +96,4 @@ logging.level.org.springframework=INFO #ELK logging file name logging.file.name=@env.FHIR_API_LOGGING_FILE_NAME@ -jwt.secret=@JWT_SECRET_KEY@ \ No newline at end of file +jwt.secret=@env.JWT_SECRET_KEY@ \ No newline at end of file diff --git a/src/main/environment/common_dev.properties b/src/main/environment/common_dev.properties index 6b5ba85..5e9c99b 100644 --- a/src/main/environment/common_dev.properties +++ b/src/main/environment/common_dev.properties @@ -93,4 +93,4 @@ logging.level.org.springframework.web=INFO logging.level.org.hibernate=INFO logging.level.com.iemr=DEBUG logging.level.org.springframework=INFO -jwt.secret=@JWT_SECRET_KEY@ +jwt.secret= diff --git a/src/main/environment/common_example.properties b/src/main/environment/common_example.properties index 502c64e..e08be75 100644 --- a/src/main/environment/common_example.properties +++ b/src/main/environment/common_example.properties @@ -93,4 +93,4 @@ logging.level.org.springframework.web=INFO logging.level.org.hibernate=INFO logging.level.com.iemr=DEBUG logging.level.org.springframework=INFO -jwt.secret=@JWT_SECRET_KEY@ +jwt.secret= diff --git a/src/main/environment/common_test.properties b/src/main/environment/common_test.properties index 6b5ba85..5e9c99b 100644 --- a/src/main/environment/common_test.properties +++ b/src/main/environment/common_test.properties @@ -93,4 +93,4 @@ logging.level.org.springframework.web=INFO logging.level.org.hibernate=INFO logging.level.com.iemr=DEBUG logging.level.org.springframework=INFO -jwt.secret=@JWT_SECRET_KEY@ +jwt.secret= diff --git a/src/main/java/com/wipro/fhir/data/users/User.java b/src/main/java/com/wipro/fhir/data/users/User.java index b37e3b2..a93bbba 100644 --- a/src/main/java/com/wipro/fhir/data/users/User.java +++ b/src/main/java/com/wipro/fhir/data/users/User.java @@ -1,9 +1,5 @@ package com.wipro.fhir.data.users; -import java.sql.Timestamp; - -import com.google.gson.annotations.Expose; - import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -18,57 +14,8 @@ public class User { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) - @Expose @Column(name = "UserID") private Long userID; - - @Expose - @Column(name = "TitleID") - private Integer titleID; - @Expose - @Column(name = "FirstName") - private String firstName; - @Expose - @Column(name = "MiddleName") - private String middleName; - @Expose - @Column(name = "LastName") - private String lastName; - - @Expose - @Column(name = "GenderID") - private Integer genderID; - - @Expose - @Column(name = "MaritalStatusID") - private Integer maritalStatusID; - - @Expose - @Column(name = "StatusID") - private Integer statusID; - - @Expose - @Column(name = "DOB") - private Timestamp dOB; - @Expose - @Column(name = "DOJ") - private Timestamp dOJ; - @Expose - @Column(name = "QualificationID") - private Integer qualificationID; - @Expose @Column(name = "userName") private String userName; - @Expose - @Column(name = "Deleted", insertable = false, updatable = true) - private Boolean deleted; - @Expose - @Column(name = "CreatedBy") - private String createdBy; - @Column(name = "CreatedDate", insertable = false, updatable = false) - private Timestamp createdDate; - @Column(name = "ModifiedBy") - private String modifiedBy; - @Column(name = "LastModDate", insertable = false, updatable = false) - private Timestamp lastModDate; } diff --git a/src/main/java/com/wipro/fhir/utils/CookieUtil.java b/src/main/java/com/wipro/fhir/utils/CookieUtil.java index 53e5eee..3ccec9d 100644 --- a/src/main/java/com/wipro/fhir/utils/CookieUtil.java +++ b/src/main/java/com/wipro/fhir/utils/CookieUtil.java @@ -24,16 +24,6 @@ public Optional getCookieValue(HttpServletRequest request, String cookie return Optional.empty(); } - public void addJwtTokenToCookie(String Jwttoken, HttpServletResponse response) { - // Create a new cookie with the JWT token - Cookie cookie = new Cookie("Jwttoken", Jwttoken); - cookie.setHttpOnly(true); // Prevent JavaScript access for security - cookie.setSecure(true); // Ensure the cookie is sent only over HTTPS - cookie.setMaxAge(60 * 60 * 24); // 1 day expiration time - cookie.setPath("/"); // Make the cookie available for the entire application - response.addCookie(cookie); // Add the cookie to the response - } - 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/wipro/fhir/utils/JwtAuthenticationUtil.java b/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java index a424c97..20465d0 100644 --- a/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java @@ -69,7 +69,6 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { } String userId = claims.get("userId", String.class); - String tokenUsername = jwtUtil.extractUsername(jwtToken); // Fetch user based on userId from the database or cache User user = commonServiceImpl.getUserById(Long.parseLong(userId)); @@ -77,11 +76,6 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { throw new Exception("Invalid User ID."); } - // Check if the token's username matches the user retrieved by userId - if (!user.getUserName().equalsIgnoreCase(tokenUsername)) { - throw new Exception("JWT token and User ID mismatch."); - } - return true; // Valid userId and JWT token } catch (Exception e) { logger.error("Validation failed: " + e.getMessage(), e); diff --git a/src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java b/src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java index ba8b4cc..09ae81f 100644 --- a/src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java +++ b/src/main/java/com/wipro/fhir/utils/JwtUserIdValidationFilter.java @@ -103,6 +103,8 @@ private String getJwtTokenFromCookies(HttpServletRequest request) { 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/wipro/fhir/utils/JwtUtil.java b/src/main/java/com/wipro/fhir/utils/JwtUtil.java index 7f4cdf0..6f22eb7 100644 --- a/src/main/java/com/wipro/fhir/utils/JwtUtil.java +++ b/src/main/java/com/wipro/fhir/utils/JwtUtil.java @@ -18,7 +18,7 @@ public class JwtUtil { @Value("${jwt.secret}") private String SECRET_KEY; - private static final long EXPIRATION_TIME = 24 * 60 * 60 * 1000; // 1 day in milliseconds + private static final long EXPIRATION_TIME = 24L * 60 * 60 * 1000; // 1 day in milliseconds // Generate a key using the secret private Key getSigningKey() { From ae83d017708961e7e45ce59134c3b5bc66b69841 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Sun, 15 Dec 2024 22:43:08 +0530 Subject: [PATCH 3/5] fixed issue --- src/main/java/com/wipro/fhir/data/users/User.java | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/main/java/com/wipro/fhir/data/users/User.java b/src/main/java/com/wipro/fhir/data/users/User.java index a93bbba..9ebe6f5 100644 --- a/src/main/java/com/wipro/fhir/data/users/User.java +++ b/src/main/java/com/wipro/fhir/data/users/User.java @@ -18,4 +18,6 @@ public class User { private Long userID; @Column(name = "userName") private String userName; + @Column(name = "Deleted", insertable = false, updatable = true) + private Boolean deleted; } From c629a18f2bf5931570558824a230af0c9ef56453 Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Thu, 19 Dec 2024 12:30:38 +0530 Subject: [PATCH 4/5] user fetch from redis concept --- .../com/wipro/fhir/FhirApiApplication.java | 21 ++++++++++ .../com/wipro/fhir/config/RedisConfig.java | 40 +++++++++++++++++++ .../java/com/wipro/fhir/data/users/User.java | 7 +++- .../wipro/fhir/repo/user/UserRepository.java | 11 ----- .../service/common/CommonServiceImpl.java | 21 ---------- .../fhir/utils/JwtAuthenticationUtil.java | 23 ++++++++--- 6 files changed, 85 insertions(+), 38 deletions(-) create mode 100644 src/main/java/com/wipro/fhir/config/RedisConfig.java delete mode 100644 src/main/java/com/wipro/fhir/repo/user/UserRepository.java diff --git a/src/main/java/com/wipro/fhir/FhirApiApplication.java b/src/main/java/com/wipro/fhir/FhirApiApplication.java index 0395010..d732a3f 100644 --- a/src/main/java/com/wipro/fhir/FhirApiApplication.java +++ b/src/main/java/com/wipro/fhir/FhirApiApplication.java @@ -26,6 +26,12 @@ import org.springframework.context.annotation.Bean; import org.springframework.data.mongodb.core.MongoTemplate; import org.springframework.data.mongodb.core.SimpleMongoClientDatabaseFactory; +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 com.wipro.fhir.data.users.User; @SpringBootApplication public class FhirApiApplication { @@ -33,4 +39,19 @@ public class FhirApiApplication { public static void main(String[] args) { SpringApplication.run(FhirApiApplication.class, args); } + + @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<>(User.class); + template.setValueSerializer(serializer); + + return template; + } } diff --git a/src/main/java/com/wipro/fhir/config/RedisConfig.java b/src/main/java/com/wipro/fhir/config/RedisConfig.java new file mode 100644 index 0000000..d29e7c3 --- /dev/null +++ b/src/main/java/com/wipro/fhir/config/RedisConfig.java @@ -0,0 +1,40 @@ +package com.wipro.fhir.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.wipro.fhir.data.users.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<>(User.class); + template.setValueSerializer(serializer); + + return template; + } + +} + + diff --git a/src/main/java/com/wipro/fhir/data/users/User.java b/src/main/java/com/wipro/fhir/data/users/User.java index 9ebe6f5..c31049e 100644 --- a/src/main/java/com/wipro/fhir/data/users/User.java +++ b/src/main/java/com/wipro/fhir/data/users/User.java @@ -1,5 +1,9 @@ package com.wipro.fhir.data.users; +import java.io.Serializable; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; + import jakarta.persistence.Column; import jakarta.persistence.Entity; import jakarta.persistence.GeneratedValue; @@ -11,7 +15,8 @@ @Entity @Table(name = "m_user") @Data -public class User { +@JsonIgnoreProperties(ignoreUnknown = true) +public class User implements Serializable { @Id @GeneratedValue(strategy = GenerationType.IDENTITY) @Column(name = "UserID") diff --git a/src/main/java/com/wipro/fhir/repo/user/UserRepository.java b/src/main/java/com/wipro/fhir/repo/user/UserRepository.java deleted file mode 100644 index 0379062..0000000 --- a/src/main/java/com/wipro/fhir/repo/user/UserRepository.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.wipro.fhir.repo.user; - -import org.springframework.data.repository.CrudRepository; - -import com.wipro.fhir.data.users.User; - -public interface UserRepository extends CrudRepository { - - User findByUserID(Long userID); - -} diff --git a/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java b/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java index ac4fcef..257e6d2 100644 --- a/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java +++ b/src/main/java/com/wipro/fhir/service/common/CommonServiceImpl.java @@ -73,7 +73,6 @@ import com.wipro.fhir.repo.mongo.amrit_resource.TempCollectionRepo; import com.wipro.fhir.repo.mongo.ndhm_response.NDHMResponseRepo; import com.wipro.fhir.repo.patient_data_handler.PatientDemographicModel_NDHM_Patient_Profile_Repo; -import com.wipro.fhir.repo.user.UserRepository; import com.wipro.fhir.service.api_channel.APIChannel; import com.wipro.fhir.service.ndhm.Common_NDHMService; import com.wipro.fhir.service.ndhm.GenerateSession_NDHMService; @@ -163,8 +162,6 @@ public class CommonServiceImpl implements CommonService { @Autowired private BenHealthIDMappingRepo benHealthIDMappingRepo; - @Autowired - private UserRepository userRepository; @Override public String processResourceOperation() throws FHIRException { @@ -651,22 +648,4 @@ public void sendAbdmAdvSMS(String phone) throws FHIRException { } - public User getUserById(Long userId) throws Exception { - try { - // Fetch user from custom repository by userId - User user = userRepository.findByUserID(userId); - - // Check if user is found - if (user == null) { - throw new Exception("User not found with ID: " + userId); - } - - return user; - } catch (Exception e) { - // Log and throw custom exception in case of errors - logger.error("Error fetching user with ID: " + userId, e); - throw new Exception("Error fetching user with ID: " + userId, e); - } - } - } diff --git a/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java b/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java index 20465d0..7880e9d 100644 --- a/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/wipro/fhir/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; @@ -22,10 +23,9 @@ public class JwtAuthenticationUtil { private CookieUtil cookieUtil; @Autowired private JwtUtil jwtUtil; - private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); - @Autowired - private CommonServiceImpl commonServiceImpl; + private RedisTemplate redisTemplate; + private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { this.cookieUtil = cookieUtil; @@ -70,8 +70,8 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { String userId = claims.get("userId", String.class); - // Fetch user based on userId from the database or cache - User user = commonServiceImpl.getUserById(Long.parseLong(userId)); + // Check if user data is present in Redis + User user = getUserFromCache(userId); if (user == null) { throw new Exception("Invalid User ID."); } @@ -82,4 +82,17 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { throw new Exception("Validation error: " + e.getMessage(), e); } } + + private User getUserFromCache(String userId) { + String redisKey = "user_" + userId; // The Redis key format + User user = (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 20c42e7b4c9bd9458d055618f5a269c1b740bddf Mon Sep 17 00:00:00 2001 From: IN40068837 Date: Tue, 24 Dec 2024 13:57:37 +0530 Subject: [PATCH 5/5] user fetch concept modify --- .../wipro/fhir/repo/user/UserLoginRepo.java | 16 ++++++++++ .../fhir/utils/JwtAuthenticationUtil.java | 31 +++++++++++++++++-- 2 files changed, 45 insertions(+), 2 deletions(-) create mode 100644 src/main/java/com/wipro/fhir/repo/user/UserLoginRepo.java diff --git a/src/main/java/com/wipro/fhir/repo/user/UserLoginRepo.java b/src/main/java/com/wipro/fhir/repo/user/UserLoginRepo.java new file mode 100644 index 0000000..1267ab6 --- /dev/null +++ b/src/main/java/com/wipro/fhir/repo/user/UserLoginRepo.java @@ -0,0 +1,16 @@ +package com.wipro.fhir.repo.user; + +import org.springframework.data.jpa.repository.Query; +import org.springframework.data.repository.CrudRepository; +import org.springframework.data.repository.query.Param; +import org.springframework.stereotype.Repository; + +import com.wipro.fhir.data.users.User; + +@Repository +public interface UserLoginRepo extends CrudRepository { + + @Query(" SELECT u FROM User u WHERE u.userID = :userID AND u.deleted = false ") + public User getUserByUserID(@Param("userID") Long userID); + +} diff --git a/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java b/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java index 7880e9d..61cdc90 100644 --- a/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java +++ b/src/main/java/com/wipro/fhir/utils/JwtAuthenticationUtil.java @@ -1,6 +1,7 @@ package com.wipro.fhir.utils; import java.util.Optional; +import java.util.concurrent.TimeUnit; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -11,7 +12,7 @@ import org.springframework.stereotype.Component; import com.wipro.fhir.data.users.User; -import com.wipro.fhir.service.common.CommonServiceImpl; +import com.wipro.fhir.repo.user.UserLoginRepo; import io.jsonwebtoken.Claims; import jakarta.servlet.http.HttpServletRequest; @@ -25,6 +26,8 @@ public class JwtAuthenticationUtil { private JwtUtil jwtUtil; @Autowired private RedisTemplate redisTemplate; + @Autowired + private UserLoginRepo userLoginRepo; private final Logger logger = LoggerFactory.getLogger(this.getClass().getName()); public JwtAuthenticationUtil(CookieUtil cookieUtil, JwtUtil jwtUtil) { @@ -72,6 +75,10 @@ public boolean validateUserIdAndJwtToken(String jwtToken) throws Exception { // Check if user data is present in Redis 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 Exception("Invalid User ID."); } @@ -88,11 +95,31 @@ private User getUserFromCache(String userId) { User user = (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 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 + User user = userLoginRepo.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; + } }