From 6f53dedbe1b15b9d0f7c301352719d5ce6224287 Mon Sep 17 00:00:00 2001 From: Lincpay Tech Date: Wed, 26 Nov 2025 17:17:04 +0530 Subject: [PATCH 1/6] added login with otp and verify otp --- .../bbps/controller/AuthController.java | 51 +++++ .../bbps/controller/PaymentController.java | 2 + .../bbps/dto/auth/AuthResponse.java | 51 +++++ .../bbps/dto/auth/LoginRequest.java | 19 ++ .../bbps/dto/auth/OtpSendResponse.java | 29 +++ .../bbps/dto/auth/RegisterRequest.java | 14 ++ .../bbps/dto/auth/UserDto.java | 20 ++ .../bbps/dto/auth/VerifyOtpRequest.java | 30 +++ .../bbps/dto/request/TransactionHistory.java | 5 + .../bbps/entites/UserEntity.java | 42 ++++ .../bbps/repository/UserRepository.java | 13 ++ .../bbps/service/AuthService.java | 15 ++ .../bbps/serviceImpl/AgentServiceImpl.java | 4 +- .../bbps/serviceImpl/AuthServiceImpl.java | 89 +++++++++ .../billpaymentservice/bbps/util/Helper.java | 12 ++ .../bbps/util/OtpClient.java | 186 ++++++++++++++++++ .../resources/application-local.properties | 12 +- src/main/resources/application.properties | 6 + 18 files changed, 595 insertions(+), 5 deletions(-) create mode 100644 src/main/java/com/billpaymentservice/bbps/controller/AuthController.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java create mode 100644 src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java create mode 100644 src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java create mode 100644 src/main/java/com/billpaymentservice/bbps/service/AuthService.java create mode 100644 src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java create mode 100644 src/main/java/com/billpaymentservice/bbps/util/OtpClient.java diff --git a/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java new file mode 100644 index 0000000..56c7367 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java @@ -0,0 +1,51 @@ +package com.billpaymentservice.bbps.controller; + +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.validation.annotation.Validated; +import org.springframework.web.bind.annotation.CrossOrigin; +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; + +import com.billpaymentservice.bbps.dto.auth.AuthResponse; +import com.billpaymentservice.bbps.dto.auth.LoginRequest; +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; +import com.billpaymentservice.bbps.dto.auth.VerifyOtpRequest; +import com.billpaymentservice.bbps.service.AuthService; + +import lombok.extern.slf4j.Slf4j; + +@RestController +@RequestMapping("/auth") +@CrossOrigin(origins = "*") +@Slf4j +public class AuthController { + + private final AuthService authService; + + public AuthController(AuthService authService) { + this.authService = authService; + } + + @PostMapping(value = "/sendOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendOtp(@Validated @RequestBody LoginRequest request) { + log.info("Received sendOtp request for mobile: {}", request.getMobile()); + OtpSendResponse resp = authService.sendOtp(request); + return ResponseEntity.ok(resp); + } + + @PostMapping(value = "/verifyOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity verifyOtp(@Validated @RequestBody VerifyOtpRequest request) { + AuthResponse resp = authService.verifyOtp(request); + return ResponseEntity.ok(resp); + } + + @PostMapping(value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity register(@Validated @RequestBody RegisterRequest request) { + AuthResponse resp = authService.registerUser(request); + return ResponseEntity.ok(resp); + } +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java b/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java index decc81c..fdfaf84 100644 --- a/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java +++ b/src/main/java/com/billpaymentservice/bbps/controller/PaymentController.java @@ -54,11 +54,13 @@ public class PaymentController { return ResponseEntity.ok(response); } + @PostMapping(value="/callback/paymentIntiate", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) public ResponseEntity handleBillValidateCallback(@RequestBody TransactionStatusResponse transactionStatusResponse) { ResponseModel genralResp=paymentService.handlePaymentIntiateCallback(transactionStatusResponse); // Return a response indicating successful receipt return ResponseEntity.ok(genralResp); } + } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java new file mode 100644 index 0000000..a88d366 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java @@ -0,0 +1,51 @@ +package com.billpaymentservice.bbps.dto.auth; + +import com.billpaymentservice.bbps.dto.auth.UserDto; + +public class AuthResponse { + private boolean success; + private String message; + private boolean userExists; + private UserDto user; + + public AuthResponse() {} + + public AuthResponse(boolean success, String message, boolean userExists, UserDto user) { + this.success = success; + this.message = message; + this.userExists = userExists; + this.user = user; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } + + public boolean isUserExists() { + return userExists; + } + + public void setUserExists(boolean userExists) { + this.userExists = userExists; + } + + public UserDto getUser() { + return user; + } + + public void setUser(UserDto user) { + this.user = user; + } +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java new file mode 100644 index 0000000..8d8a65a --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/LoginRequest.java @@ -0,0 +1,19 @@ +package com.billpaymentservice.bbps.dto.auth; + +public class LoginRequest { + private String mobile; + + public LoginRequest() {} + + public LoginRequest(String mobile) { + this.mobile = mobile; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java new file mode 100644 index 0000000..67dc6ff --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/OtpSendResponse.java @@ -0,0 +1,29 @@ +package com.billpaymentservice.bbps.dto.auth; + +public class OtpSendResponse { + private boolean success; + private String message; + + public OtpSendResponse() {} + + public OtpSendResponse(boolean success, String message) { + this.success = success; + this.message = message; + } + + public boolean isSuccess() { + return success; + } + + public void setSuccess(boolean success) { + this.success = success; + } + + public String getMessage() { + return message; + } + + public void setMessage(String message) { + this.message = message; + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java new file mode 100644 index 0000000..ee156a1 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java @@ -0,0 +1,14 @@ +package com.billpaymentservice.bbps.dto.auth; + +import lombok.Getter; +import lombok.Setter; + +@Getter +@Setter +public class RegisterRequest { + private String mobile; + private String name; + private String email; + private int age; + +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java new file mode 100644 index 0000000..1c35570 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java @@ -0,0 +1,20 @@ +package com.billpaymentservice.bbps.dto.auth; + +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +public class UserDto { + private Long id; + private String mobile; + private String name; + private String email; + private int age; + + +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java new file mode 100644 index 0000000..a52c072 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/VerifyOtpRequest.java @@ -0,0 +1,30 @@ +package com.billpaymentservice.bbps.dto.auth; + +public class VerifyOtpRequest { + private String mobile; + private String otp; + + public VerifyOtpRequest() { + } + + public VerifyOtpRequest(String mobile, String otp) { + this.mobile = mobile; + this.otp = otp; + } + + public String getMobile() { + return mobile; + } + + public void setMobile(String mobile) { + this.mobile = mobile; + } + + public String getOtp() { + return otp; + } + + public void setOtp(String otp) { + this.otp = otp; + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java b/src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java new file mode 100644 index 0000000..a879f88 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/TransactionHistory.java @@ -0,0 +1,5 @@ +package com.billpaymentservice.bbps.dto.request; + +public class TransactionHistory { + +} diff --git a/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java b/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java new file mode 100644 index 0000000..ab454eb --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java @@ -0,0 +1,42 @@ +package com.billpaymentservice.bbps.entites; + +import com.billpaymentservice.bbps.audit.Auditable; + +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.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Entity +@Table(name = "users") +@Getter +@Setter +@AllArgsConstructor +@NoArgsConstructor +public class UserEntity extends Auditable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + private Long id; + + @Column(name = "mobile", nullable = false, unique = true, length = 20) + private String mobile; + + @Column(name = "name", length = 150) + private String name; + + @Column(name = "email", length = 150) + private String email; + + @Column(name = "age") + private int age; + + + +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java b/src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java new file mode 100644 index 0000000..54c7362 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/repository/UserRepository.java @@ -0,0 +1,13 @@ +package com.billpaymentservice.bbps.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.billpaymentservice.bbps.entites.UserEntity; + +@Repository +public interface UserRepository extends JpaRepository { + Optional findByMobile(String mobile); +} diff --git a/src/main/java/com/billpaymentservice/bbps/service/AuthService.java b/src/main/java/com/billpaymentservice/bbps/service/AuthService.java new file mode 100644 index 0000000..32e832e --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/service/AuthService.java @@ -0,0 +1,15 @@ +package com.billpaymentservice.bbps.service; + +import com.billpaymentservice.bbps.dto.auth.AuthResponse; +import com.billpaymentservice.bbps.dto.auth.LoginRequest; +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; +import com.billpaymentservice.bbps.dto.auth.VerifyOtpRequest; +import com.billpaymentservice.bbps.entites.UserEntity; + +public interface AuthService { + OtpSendResponse sendOtp(LoginRequest request); + AuthResponse verifyOtp(VerifyOtpRequest request); + AuthResponse registerUser(RegisterRequest request); + UserEntity findByMobile(String mobile); +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java index 271bf91..a22994f 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AgentServiceImpl.java @@ -270,7 +270,7 @@ public class AgentServiceImpl implements AgentService { String apiName = BBPSConstant.API_INITIATE_BILL_VALIDATE; String reqId = fetchBillValidateRequest.getReqId(); String mid = fetchBillValidateRequest.getMid(); - LOGGER.info("[{}] START | reqId={} | mid={} | billerId={}", apiName, fetchBillValidateRequest, mid, + LOGGER.info("[{}] START | reqId={} | mid={} | billerId={}", apiName, fetchBillValidateRequest.getReqId(), mid, fetchBillValidateRequest.getBillerId()); String txnId = helper.generateTxnId(15); String fullUrl = agentDtaUrl + BBPSConstant.BILLER_VALIDATE_URL; @@ -395,8 +395,6 @@ public class AgentServiceImpl implements AgentService { helper.updateInboundLogSuccess(inboundLog, responseData, generalResp.getStatus()); System.out.println("responseWrapper:" + responseWrapper); mapperHelper.saveBillValidation(responseWrapper, billRequest); - LOGGER.info("Bill data saved successfully for billId: {}", billId); - return new ResponseModel(generalResp.getMessage(), generalResp.getStatus(), Integer.parseInt(generalResp.getStatusCode()), responseWrapper); } catch (JsonProcessingException e) { diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java new file mode 100644 index 0000000..861bcd7 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java @@ -0,0 +1,89 @@ +package com.billpaymentservice.bbps.serviceImpl; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.stereotype.Service; +import org.springframework.transaction.annotation.Transactional; + +import com.billpaymentservice.bbps.dto.auth.AuthResponse; +import com.billpaymentservice.bbps.dto.auth.LoginRequest; +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; +import com.billpaymentservice.bbps.dto.auth.UserDto; +import com.billpaymentservice.bbps.dto.auth.VerifyOtpRequest; +import com.billpaymentservice.bbps.entites.UserEntity; +import com.billpaymentservice.bbps.repository.UserRepository; +import com.billpaymentservice.bbps.service.AuthService; +import com.billpaymentservice.bbps.util.Helper; +import com.billpaymentservice.bbps.util.OtpClient; + +import java.util.Optional; + +@Service +public class AuthServiceImpl implements AuthService { + + private static final Logger LOGGER = LoggerFactory.getLogger(AuthServiceImpl.class); + + private final UserRepository userRepository; + private final OtpClient otpClient; + private final Helper helper ; + + @Autowired + public AuthServiceImpl(UserRepository userRepository, OtpClient otpClient,Helper helper) { + this.userRepository = userRepository; + this.otpClient = otpClient; + this.helper = helper; + } + + @Override + public OtpSendResponse sendOtp(LoginRequest request) { + Optional existing = userRepository.findByMobile(request.getMobile()); + + if (existing.isPresent()) { + UserEntity u = existing.get(); + UserDto dto = new UserDto(u.getId(), u.getMobile(), u.getName(), u.getEmail(),u.getAge()); + return null; + } + // delegate to external OTP provider + return otpClient.sendOtp(request.getMobile()); + } + + @Override + public AuthResponse verifyOtp(VerifyOtpRequest request) { + boolean ok = otpClient.verifyOtp(request.getMobile(), request.getOtp()); + if (!ok) { + return new AuthResponse(false, "Invalid OTP", false, null); + } + + Optional userOpt = userRepository.findByMobile(request.getMobile()); + if (userOpt.isPresent()) { + UserEntity user = userOpt.get(); + UserDto dto = new UserDto(user.getId(), user.getMobile(), user.getName(), user.getEmail(),user.getAge()); + return new AuthResponse(true, "Login successful", true, dto); + } else { + return new AuthResponse(true, "OTP verified; user not found - proceed to registration", false, null); + } + } + + @Override + @Transactional + public AuthResponse registerUser(RegisterRequest request) { + Optional existing = userRepository.findByMobile(request.getMobile()); + if (existing.isPresent()) { + UserEntity u = existing.get(); + UserDto dto = new UserDto(u.getId(), u.getMobile(), u.getName(), u.getEmail(),u.getAge()); + return new AuthResponse(false, "User already exists", true, dto); + } + + UserEntity user = helper.createNewUser(request); + user = userRepository.save(user); + UserDto dto = new UserDto(user.getId(), user.getMobile(), user.getName(), user.getEmail(),user.getAge()); + return new AuthResponse(true, "Registration successful", true, dto); + } + + @Override + public UserEntity findByMobile(String mobile) { + return userRepository.findByMobile(mobile).orElse(null); + } +} \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/util/Helper.java b/src/main/java/com/billpaymentservice/bbps/util/Helper.java index 9949670..74a4d3f 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/Helper.java +++ b/src/main/java/com/billpaymentservice/bbps/util/Helper.java @@ -8,9 +8,11 @@ import org.springframework.http.HttpHeaders; import org.springframework.http.MediaType; import org.springframework.stereotype.Component; +import com.billpaymentservice.bbps.dto.auth.RegisterRequest; import com.billpaymentservice.bbps.entites.BBPSMastersData; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; +import com.billpaymentservice.bbps.entites.UserEntity; import com.billpaymentservice.bbps.entites.BharatConnectMaster; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BBPSMasterDataRepo; @@ -166,4 +168,14 @@ public class Helper { return headers; } + public UserEntity createNewUser(RegisterRequest request) { + UserEntity user = new UserEntity(); + + user.setMobile(request.getMobile()); + user.setName(request.getName()); + user.setEmail(request.getEmail()); + user.setAge(request.getAge()); + return user; + } + } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java b/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java new file mode 100644 index 0000000..758ced5 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java @@ -0,0 +1,186 @@ +package com.billpaymentservice.bbps.util; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.http.HttpEntity; +import org.springframework.http.HttpHeaders; +import org.springframework.http.HttpMethod; +import org.springframework.http.HttpStatus; +import org.springframework.http.MediaType; +import org.springframework.http.ResponseEntity; +import org.springframework.stereotype.Component; +import org.springframework.web.client.RestTemplate; + +import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; + +import java.util.HashMap; +import java.util.Map; +import java.util.Collections; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.fasterxml.jackson.databind.ObjectMapper; + +@Component +public class OtpClient { + + private static final Logger logger = LoggerFactory.getLogger(OtpClient.class); + + private final RestTemplate restTemplate = new RestTemplate(); + + @Value("${ekyc.mobile}") + private String sendUrl; + + @Value("${ekyc.mobile.verify.otp}") + private String verifyUrl; + + // New config properties for eKYC-style OTP API + @Value("${ekyc.mobile}") + private String ekycMobileUrl; + + @Value("${ekyc.apikey}") + private String apiKey; + + @Value("${ekyc.secreteKey}") + private String secretKey; + + + /** + * Calls external API to send OTP. The implementation assumes a POST with JSON {"mobile":"..."} + * Modify headers/body as per your external API. Updated to support eKYC OTP generation logic. + */ + public OtpSendResponse sendOtp(String mobile) { + try { + logger.info("Initiating OTP send process for mobile: {}", mobile); + + logger.info("eKYC Mobile URL: {}", ekycMobileUrl); + logger.info("API Key: {}", apiKey != null && !apiKey.isEmpty()); + logger.info("Secret Key: {}", secretKey != null && !secretKey.isEmpty()); + logger.info("Send URL: {}", sendUrl); + logger.info("Verify URL: {}", verifyUrl); + logger.info("Mobile Number: {}", mobile); + + // If explicit eKYC config present, use that flow + if (ekycMobileUrl != null && !ekycMobileUrl.isEmpty()) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + + // Build JSON body string as in user's snippet + String jsonBody = "{\"mobileNumber\":\"" + mobile + "\", \"apiKey\":\"" + apiKey + + "\", \"secretKey\":\"" + secretKey + "\"}"; + + HttpEntity request = new HttpEntity<>(jsonBody, headers); + + try { + ResponseEntity response = restTemplate.exchange(ekycMobileUrl, HttpMethod.POST, request, + String.class); + logger.info("eKYC OTP generation API response status: {}", response.getStatusCode()); + + if (response.getStatusCode() == HttpStatus.OK) { + logger.info("OTP generated successfully for mobile: {}", mobile); + return new OtpSendResponse(true, "OTP generated successfully"); + + } else { + logger.error("Failed to call eKYC OTP generation API: {}", response.getStatusCode()); + return new OtpSendResponse(false, "Failed to call OTP generation service"); + } + } catch (Exception e) { + logger.error("Error calling eKYC OTP generation API: {}", e.getMessage(), e); + return new OtpSendResponse(false, "Error while generating OTP: " + e.getMessage()); + } + } + + // Fallback to previously configured generic sendUrl behavior + if (sendUrl == null || sendUrl.isEmpty()) { + return new OtpSendResponse(true, "(stub) OTP sent to " + mobile); + } + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + Map body = new HashMap<>(); + body.put("mobile", mobile); + HttpEntity> req = new HttpEntity<>(body, headers); + // expecting external API returns {"success":true,"message":"..."} + Map resp = restTemplate.postForObject(sendUrl, req, Map.class); + boolean success = resp != null && Boolean.TRUE.equals(resp.get("success")); + String message = resp == null ? "no response" : String.valueOf(resp.get("message")); + return new OtpSendResponse(success, message); + } catch (Exception e) { + logger.error("Unexpected error in sendOtp: {}", e.getMessage(), e); + return new OtpSendResponse(false, "Failed to call OTP send: " + e.getMessage()); + } + } + + /** + * Calls external API to verify OTP. Returns true if OTP valid. + */ + public boolean verifyOtp(String mobile, String otp) { + try { + // basic input validation + if (mobile == null || mobile.isEmpty() || otp == null || otp.isEmpty()) { + logger.debug("verifyOtp called with empty mobile or otp"); + return false; + } + + logger.info("Verifying Mobile OTP for mobile: {}", mobile); + + // If an eKYC verify endpoint is configured, use it + if (verifyUrl != null && !verifyUrl.isEmpty()) { + HttpHeaders headers = new HttpHeaders(); + headers.setContentType(MediaType.APPLICATION_JSON); + headers.setAccept(Collections.singletonList(MediaType.APPLICATION_JSON)); + + Map requestBody = new HashMap<>(); + requestBody.put("mobileNumber", mobile); + requestBody.put("apiKey", apiKey); + requestBody.put("secretKey", secretKey); + requestBody.put("otp", otp); + + HttpEntity> requestEntity = new HttpEntity<>(requestBody, headers); + try { + ResponseEntity response = restTemplate.exchange(verifyUrl, HttpMethod.POST, + requestEntity, String.class); + + logger.info("Mobile OTP verification API response: status={}, body={}", response.getStatusCode(), + response.getBody()); + + if (response.getStatusCode() == HttpStatus.OK) { + String respBody = response.getBody(); + if (respBody != null) { + // try to parse JSON and look for common verification keys + ObjectMapper mapper = new ObjectMapper(); + try { + Map respMap = mapper.readValue(respBody, Map.class); + if (respMap.containsKey("verified")) { + return Boolean.TRUE.equals(respMap.get("verified")); + } + if (respMap.containsKey("success")) { + return Boolean.TRUE.equals(respMap.get("success")); + } + if (respMap.containsKey("status") && "OK".equalsIgnoreCase(String.valueOf(respMap.get("status")))) { + return true; + } + } catch (Exception e) { + logger.debug("Unable to parse verification response body to JSON: {}", e.getMessage()); + // fall through to treat 200 as success + } + } + // fallback: treat HTTP 200 as successful verification + return true; + } else { + logger.warn("OTP verification endpoint returned non-OK status: {}", response.getStatusCode()); + return false; + } + } catch (Exception e) { + logger.error("Error calling eKYC OTP verify API: {}", e.getMessage(), e); + return false; + } + } + + // stub behaviour when no verify URL configured: accept OTP "123456" + return false; + } catch (Exception e) { + logger.error("Unexpected error in verifyOtp: {}", e.getMessage(), e); + return false; + } + } +} diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 17c421e..4eaafbc 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -20,12 +20,20 @@ swagger.server.description=Local Development Server # DataSource spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS spring.datasource.username=postgres -spring.datasource.password=UAT@DB_2025 +#spring.datasource.password=UAT@DB_2025 -#spring.datasource.password=himanshu@123 +spring.datasource.password=himanshu@123 spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.type=com.zaxxer.hikari.HikariDataSource +ekyc.apikey=key_live_823fb2b5ba984ea293b6695331f83788 +ekyc.secreteKey= secret_live_b2acae6e1fd54d6faa148b08af8ae098 +ekyc.mobile=https://ekyc.lincpay.in/EKYC/ekyc/mobile/generate-otp +ekyc.mobile.verify.otp=https://ekyc.lincpay.in/EKYC/ekyc/verify-mobile-otp + + + +enc.key=lincpay # HikariCP settings spring.datasource.hikari.connection-timeout=10000 diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c652768..3d857c5 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -46,6 +46,12 @@ agent.data.url=https://bbps-staging.digiledge.in/agent/bill-payment-new payment.data.url=https://bbps-staging.digiledge.in/couapp complaint.data.url=https://bbps-staging.digiledge.in + +ekyc.apikey=key_live_823fb2b5ba984ea293b6695331f83788 +ekyc.secreteKey= secret_live_b2acae6e1fd54d6faa148b08af8ae098 +ekyc.mobile=https://ekyc.lincpay.in/EKYC/ekyc/mobile/generate-otp +ekyc.mobile.verify.otp=https://ekyc.lincpay.in/EKYC/ekyc/verify-mobile-otp + # throw NoHandlerFoundException for 404s spring.mvc.throw-exception-if-no-handler-found=true From 2991349f8b82f8555f2e97b0eba6ae3c5dde4926 Mon Sep 17 00:00:00 2001 From: Mohd-Arham Date: Wed, 26 Nov 2025 18:01:36 +0530 Subject: [PATCH 2/6] add security --- pom.xml | 42 ++++++-- .../bbps/config/CustomUserDetailsService.java | 37 +++++++ .../config/JwtAuthenticationEntryPoint.java | 22 ++++ .../bbps/config/JwtFilter.java | 72 +++++++++++++ .../bbps/config/JwtUtil.java | 102 ++++++++++++++++++ .../bbps/config/SecurityConfig.java | 36 +++++++ .../bbps/controller/MasterDataController.java | 12 +++ .../bbps/dto/UserDetailsDTO.java | 23 ++++ .../bbps/dto/request/ComplaintRequestDTO.java | 4 +- .../bbps/dto/request/LoginRequest.java | 18 ++++ .../bbps/dto/response/AuthResponse.java | 43 ++++++++ .../bbps/entites/UsersDetails.java | 38 +++++++ .../repository/UsersDetailsRepository.java | 15 +++ .../bbps/service/MasterDataService.java | 4 + .../bbps/serviceImpl/ComplainServiceImpl.java | 19 +++- .../serviceImpl/MasterDataServiceImpl.java | 56 +++++++++- .../bbps/swagger/SwaggerConfig.java | 19 ++-- .../bbps/util/BillerMapperHelper.java | 3 - src/main/resources/application.properties | 7 +- 19 files changed, 542 insertions(+), 30 deletions(-) create mode 100644 src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java create mode 100644 src/main/java/com/billpaymentservice/bbps/config/JwtAuthenticationEntryPoint.java create mode 100644 src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java create mode 100644 src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/request/LoginRequest.java create mode 100644 src/main/java/com/billpaymentservice/bbps/dto/response/AuthResponse.java create mode 100644 src/main/java/com/billpaymentservice/bbps/entites/UsersDetails.java create mode 100644 src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java diff --git a/pom.xml b/pom.xml index a690489..a2207ca 100644 --- a/pom.xml +++ b/pom.xml @@ -2,7 +2,7 @@ - + 4.0.0 @@ -29,11 +29,11 @@ org.springframework.boot spring-boot-starter - - - org.springframework.boot - spring-boot-starter-validation - + + + org.springframework.boot + spring-boot-starter-validation + org.springframework.boot spring-boot-starter-web @@ -62,6 +62,11 @@ provided + + org.springframework.boot + spring-boot-starter-security + + org.postgresql @@ -133,7 +138,26 @@ org.springdoc springdoc-openapi-starter-webmvc-ui - 2.5.0 + 2.2.0 + + + + + io.jsonwebtoken + jjwt-api + 0.11.5 + + + io.jsonwebtoken + jjwt-impl + 0.11.5 + runtime + + + io.jsonwebtoken + jjwt-jackson + 0.11.5 + runtime @@ -172,8 +196,8 @@ org.springframework.boot spring-boot-maven-plugin - - + + BBPS diff --git a/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java b/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java new file mode 100644 index 0000000..fb26179 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java @@ -0,0 +1,37 @@ +package com.billpaymentservice.bbps.config; + +import java.util.ArrayList; +import java.util.Optional; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.core.userdetails.User; +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; + +import com.billpaymentservice.bbps.entites.UsersDetails; +import com.billpaymentservice.bbps.repository.UsersDetailsRepository; + +@Service +public class CustomUserDetailsService implements UserDetailsService { + + @Autowired + private UsersDetailsRepository userRepo; + + @Override + public UserDetails loadUserByUsername(String userMobNo) throws UsernameNotFoundException { + + String normalizedEmail = userMobNo; + + Optional adminOptional = userRepo.findByUserMobNo(normalizedEmail); + + if (adminOptional.isPresent()) { + UsersDetails user = adminOptional.get(); + return new User(user.getUserEmailId(), user.getUserMobNo(), new ArrayList<>()); + } else { + throw new UsernameNotFoundException("User not found with MobNo: " + userMobNo); + } + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtAuthenticationEntryPoint.java b/src/main/java/com/billpaymentservice/bbps/config/JwtAuthenticationEntryPoint.java new file mode 100644 index 0000000..82a3c80 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtAuthenticationEntryPoint.java @@ -0,0 +1,22 @@ +package com.billpaymentservice.bbps.config; + +import java.io.IOException; + +import org.springframework.security.core.AuthenticationException; +import org.springframework.security.web.AuthenticationEntryPoint; +import org.springframework.stereotype.Component; + +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JwtAuthenticationEntryPoint implements AuthenticationEntryPoint { + + @Override + public void commence(HttpServletRequest request, HttpServletResponse response, + AuthenticationException authException) throws IOException, ServletException { + response.sendError(HttpServletResponse.SC_UNAUTHORIZED, "Access denied"); + + } +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java b/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java new file mode 100644 index 0000000..fa06986 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java @@ -0,0 +1,72 @@ +package com.billpaymentservice.bbps.config; + +import java.io.IOException; + +import org.springframework.beans.factory.annotation.Autowired; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.security.web.authentication.WebAuthenticationDetailsSource; +import org.springframework.stereotype.Component; +import org.springframework.web.filter.OncePerRequestFilter; +import io.jsonwebtoken.ExpiredJwtException; +import io.jsonwebtoken.MalformedJwtException; +import jakarta.servlet.FilterChain; +import jakarta.servlet.ServletException; +import jakarta.servlet.http.HttpServletRequest; +import jakarta.servlet.http.HttpServletResponse; + +@Component +public class JwtFilter extends OncePerRequestFilter { + + @Autowired + private JwtUtil jwtUtil; + + @Autowired + private CustomUserDetailsService userDetailsService; + + @Override + protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) + throws ServletException, IOException { + + final String authorizationHeader = request.getHeader("Authentication"); + + String email = null; + String jwt = null; + + if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { + jwt = authorizationHeader.substring(7); + try { + email = jwtUtil.extractUsername(jwt); + } catch (IllegalArgumentException e) { + System.out.println("unable to get jwt tokken"); + } catch (ExpiredJwtException e) { + System.out.println("Jwt Exception jwt tokken"); + } catch (MalformedJwtException e) { + System.out.println("invelid jwt token"); + } + } + + if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) { + + UserDetails userDetails = this.userDetailsService.loadUserByUsername(email); + + + if (jwtUtil.validateToken(jwt, userDetails)) { + + UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( + userDetails, null, userDetails.getAuthorities()); + authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request)); + SecurityContextHolder.getContext().setAuthentication(authentication); + + } else { + System.out.println("JWT Filter: Token validation failed for user - " + email); + + } + } + + filterChain.doFilter(request, response); + + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java b/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java new file mode 100644 index 0000000..1111b3e --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java @@ -0,0 +1,102 @@ +package com.billpaymentservice.bbps.config; + +import java.security.Key; +import java.util.Date; +import java.util.HashMap; +import java.util.Map; +import java.util.function.Function; + +import org.springframework.beans.factory.annotation.Value; +import org.springframework.security.core.userdetails.UserDetails; +import org.springframework.stereotype.Service; + +import io.jsonwebtoken.Claims; +import io.jsonwebtoken.Jwts; +import io.jsonwebtoken.SignatureAlgorithm; +import io.jsonwebtoken.io.Decoders; +import io.jsonwebtoken.security.Keys; + +@Service +public class JwtUtil { + + @Value("${jwt.secret}") + private String secret; + + private Key getSigningKey() { + byte[] keyBytes = Decoders.BASE64.decode(secret); + return Keys.hmacShaKeyFor(keyBytes); + } + + // Access Token - 2 Hours + private final long jwtExpirationInMs = 1000 * 60 * 60 * 2; // 2 hours + + // Refresh Token - 7 Days + private final long refreshExpirationDateInMs = 1000L * 60 * 60 * 24 * 7; // 7 days + + private final Map tokenBlacklist = new HashMap<>(); + + public String doGenerateRefreshToken(Map claims, String subject) { + return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + refreshExpirationDateInMs)) + .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); + } + + public String extractUsername(String token) { + return extractClaim(token, Claims::getSubject); + } + + public Date extractExpiration(String token) { + return extractClaim(token, Claims::getExpiration); + } + + public T extractClaim(String token, Function claimsResolver) { + final Claims claims = extractAllClaims(token); + return claimsResolver.apply(claims); + } + + private Claims extractAllClaims(String token) { + return Jwts.parserBuilder().setSigningKey(getSigningKey()).build().parseClaimsJws(token).getBody(); + } + + private Boolean isTokenExpired(String token) { + return extractExpiration(token).before(new Date()); + } + + public String generateToken(String username, String mid) { + Map claims = new HashMap<>(); + claims.put("mid", mid); + claims.put("expiryTime", new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10).toString()); + return createToken(claims, username.toUpperCase()); + } + + private String createToken(Map claims, String subject) { + return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) + .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); + } + + private String createToken1(String subject) { + return Jwts.builder().setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) + .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); + } + + public Boolean validateToken(String token, UserDetails userDetails) { + final String username = extractUsername(token); + return true; + } + + public void invalidateToken(String token) { + tokenBlacklist.put(token, new Date()); + } + + public boolean isTokenBlacklisted(String token) { + Date invalidationTime = tokenBlacklist.get(token); + return invalidationTime != null && invalidationTime.before(new Date()); + } + + public String generateToken(String mobileNo) { + return createToken1(mobileNo); + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java b/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java index ebe19d9..891013d 100644 --- a/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java +++ b/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java @@ -2,16 +2,52 @@ package com.billpaymentservice.bbps.config; import java.util.Arrays; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; +import org.springframework.http.HttpMethod; +import org.springframework.security.config.annotation.web.builders.HttpSecurity; +import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; +import org.springframework.security.config.http.SessionCreationPolicy; +import org.springframework.security.web.SecurityFilterChain; +import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.CorsConfigurationSource; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @Configuration +@EnableWebSecurity public class SecurityConfig { + @Autowired + private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + + @Autowired + private JwtFilter jwtFilter; + + @Bean + public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { + + http.csrf(csrf -> csrf.disable()).cors(cors -> cors.configurationSource(corsConfigurationSource())) + .authorizeHttpRequests(auth -> auth + .requestMatchers("/masterData/**", + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html", + "/swagger-resources/**", + "/webjars/**", + "/error") + .permitAll().requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // <-- Correct way + .anyRequest().authenticated()) + .exceptionHandling(ex -> ex.authenticationEntryPoint(jwtAuthenticationEntryPoint)) + .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); + + http.addFilterBefore(jwtFilter, UsernamePasswordAuthenticationFilter.class); + + return http.build(); + } + @Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration config = new CorsConfiguration(); diff --git a/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java b/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java index 8f94d77..0d011eb 100644 --- a/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java +++ b/src/main/java/com/billpaymentservice/bbps/controller/MasterDataController.java @@ -16,9 +16,11 @@ import com.billpaymentservice.bbps.dto.request.BillerDetailRequest; import com.billpaymentservice.bbps.dto.request.ContactMasterRequest; import com.billpaymentservice.bbps.dto.request.CustomParamRequest; import com.billpaymentservice.bbps.dto.request.DispositionRequest; +import com.billpaymentservice.bbps.dto.request.LoginRequest; import com.billpaymentservice.bbps.dto.request.MasterCategoryRequest; import com.billpaymentservice.bbps.dto.request.MasterRequest; import com.billpaymentservice.bbps.dto.request.PlanRequest; +import com.billpaymentservice.bbps.dto.response.AuthResponse; import com.billpaymentservice.bbps.service.MasterDataService; import jakarta.validation.Valid; @@ -146,4 +148,14 @@ public class MasterDataController { return ResponseEntity.ok(masterDataService.fetchPlanByCategories(requestModel)); } + @PostMapping("/loginWithoutDecryption") + public ResponseEntity login(@RequestBody LoginRequest loginRequest) { + try { + AuthResponse authResponse = masterDataService.authenticateUser(loginRequest); + return ResponseEntity.ok(authResponse); + } catch (Exception e) { + return ResponseEntity.status(500).body(AuthResponse.builder().status("Unauthorized") + .message("An unexpected error occurred").statusCode(500).build()); + } + } } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java b/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java new file mode 100644 index 0000000..46575e1 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java @@ -0,0 +1,23 @@ +package com.billpaymentservice.bbps.dto; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Builder +public class UserDetailsDTO { + + private Long id; + + private String userEmailId; + + private String userMobNo; + + private String userName; + + private String userAge; +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java b/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java index ed90f62..ee5b04e 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/ComplaintRequestDTO.java @@ -11,7 +11,5 @@ public class ComplaintRequestDTO extends BaseClass { private String ticketDisposition; // Complaint disposition private String ticketDispositionCode; // Type of complaint private String txnId; // Transaction ID (optional) - private String billerId; // Client Req ID (optional); - private String billerName; - + } diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/LoginRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/request/LoginRequest.java new file mode 100644 index 0000000..4023a6e --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/LoginRequest.java @@ -0,0 +1,18 @@ +package com.billpaymentservice.bbps.dto.request; + +import jakarta.validation.constraints.NotBlank; +import jakarta.validation.constraints.Pattern; +import lombok.Data; +import lombok.Getter; +import lombok.Setter; + +@Data +@Getter +@Setter +public class LoginRequest { + + @NotBlank(message = "Mobile number is required") + @Pattern(regexp = "^[6-9]\\d{9}$", message = "Invalid mobile number. It must be 10 digits and start with 6, 7, 8, or 9.") + private String mobileNumber; + +} diff --git a/src/main/java/com/billpaymentservice/bbps/dto/response/AuthResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/response/AuthResponse.java new file mode 100644 index 0000000..f508f46 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/dto/response/AuthResponse.java @@ -0,0 +1,43 @@ +package com.billpaymentservice.bbps.dto.response; + +import lombok.AllArgsConstructor; +import lombok.Builder; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@AllArgsConstructor +@NoArgsConstructor +@Builder +public class AuthResponse { + + private String token; + + private String status; + + private String message; + + private int statusCode; + + private Object data; + + private String anotherData; + + // Constructor + public AuthResponse(String status, String message, int statusCode, String token) { + + this.status = status; + this.message = message; + this.statusCode = statusCode; + this.token = token; + } + + public AuthResponse(String token, String status, String message, int statusCode, Object data) { + this.token = token; + this.status = status; + this.message = message; + this.statusCode = statusCode; + this.data = data; + } + +} diff --git a/src/main/java/com/billpaymentservice/bbps/entites/UsersDetails.java b/src/main/java/com/billpaymentservice/bbps/entites/UsersDetails.java new file mode 100644 index 0000000..96b9e50 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/entites/UsersDetails.java @@ -0,0 +1,38 @@ +package com.billpaymentservice.bbps.entites; + +import com.billpaymentservice.bbps.audit.Auditable; +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.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@Entity +@Table(name = "user_details") +public class UsersDetails extends Auditable { + + @Id + @GeneratedValue(strategy = GenerationType.IDENTITY) + @Column(name = "id") + private Long id; + + @Column(name = "user_email_id") + private String userEmailId; + + @Column(name = "user_mob_no") + private String userMobNo; + + @Column(name = "user_name") + private String userName; + + @Column(name = "user_age") + private String userAge; + +} diff --git a/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java b/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java new file mode 100644 index 0000000..2f6a983 --- /dev/null +++ b/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java @@ -0,0 +1,15 @@ +package com.billpaymentservice.bbps.repository; + +import java.util.Optional; + +import org.springframework.data.jpa.repository.JpaRepository; +import org.springframework.stereotype.Repository; + +import com.billpaymentservice.bbps.entites.UsersDetails; + +@Repository +public interface UsersDetailsRepository extends JpaRepository { + + Optional findByUserMobNo(String userMobNo); + +} diff --git a/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java b/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java index 19da574..74660e7 100644 --- a/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java +++ b/src/main/java/com/billpaymentservice/bbps/service/MasterDataService.java @@ -5,9 +5,11 @@ import com.billpaymentservice.bbps.dto.request.BillerDetailRequest; import com.billpaymentservice.bbps.dto.request.ContactMasterRequest; import com.billpaymentservice.bbps.dto.request.CustomParamRequest; import com.billpaymentservice.bbps.dto.request.DispositionRequest; +import com.billpaymentservice.bbps.dto.request.LoginRequest; import com.billpaymentservice.bbps.dto.request.MasterCategoryRequest; import com.billpaymentservice.bbps.dto.request.MasterRequest; import com.billpaymentservice.bbps.dto.request.PlanRequest; +import com.billpaymentservice.bbps.dto.response.AuthResponse; public interface MasterDataService { @@ -35,4 +37,6 @@ public interface MasterDataService { public ResponseModel getTicketDispositions(DispositionRequest dispositionDetailRequest); + public AuthResponse authenticateUser(LoginRequest loginRequest); + } diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java index 4b69980..5ae05b2 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java @@ -3,6 +3,7 @@ package com.billpaymentservice.bbps.serviceImpl; import java.util.List; import java.util.Map; +import java.util.Optional; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -31,10 +32,12 @@ import com.billpaymentservice.bbps.entites.BharatConnectMaster; import com.billpaymentservice.bbps.entites.ComplaintStatusOptionsMaster; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; +import com.billpaymentservice.bbps.entites.TransactionMaster; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BharatConnectMasterRepository; import com.billpaymentservice.bbps.repository.ComplainRepository; import com.billpaymentservice.bbps.repository.ComplaintOptionsStatusMasterRepository; +import com.billpaymentservice.bbps.repository.TransactionMasterRepository; import com.billpaymentservice.bbps.service.ComplainService; import com.billpaymentservice.bbps.util.BBPSConstant; import com.billpaymentservice.bbps.util.BillerMapperHelper; @@ -61,6 +64,7 @@ public class ComplainServiceImpl implements ComplainService { private final BillerMapperHelper mapperHelper; private final ComplainRepository complainRepository; private final ComplaintOptionsStatusMasterRepository complaintStatusMasterRepository; + private final TransactionMasterRepository transactionMasterRepository; // moved to class-level private final ObjectMapper objectMapper; @@ -69,7 +73,8 @@ public class ComplainServiceImpl implements ComplainService { public ComplainServiceImpl(RestClient restClient, HttpService httpService, Helper helper, BharatConnectMasterRepository beneficiaryDetailsRepository, BillerMapperHelper mapperHelper, ComplainRepository complainRepository, - ComplaintOptionsStatusMasterRepository complaintStatusMasterRepository) { + ComplaintOptionsStatusMasterRepository complaintStatusMasterRepository, + TransactionMasterRepository transactionMasterRepository) { this.restClient = restClient; this.httpService = httpService; this.helper = helper; @@ -77,7 +82,7 @@ public class ComplainServiceImpl implements ComplainService { this.mapperHelper = mapperHelper; this.complainRepository = complainRepository; this.complaintStatusMasterRepository = complaintStatusMasterRepository; - + this.transactionMasterRepository = transactionMasterRepository; // initialize shared ObjectMapper once this.objectMapper = new ObjectMapper(); this.objectMapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); @@ -110,10 +115,20 @@ public class ComplainServiceImpl implements ComplainService { BBPSConstant.HTTP_POST, null); try { + + Optional dataById = transactionMasterRepository.findById(complainRequestDTO.getTxnId()); + if (dataById == null || dataById.isEmpty()) { + LOGGER.warn("Master Data By Id is null"); + throw new CustomException("Master Data is required", "FAILED", BBPSConstant.BADREQUEST, null); + } + + TransactionMaster transData = dataById.get(); // Inject tenantId + agentId into request JSON ObjectNode root = (ObjectNode) objectMapper.readTree(forwardJson); root.put("tenantId", headersData.getTenantId()); root.put("agentId", headersData.getAgentId()); + root.put("billerId", transData.getBillerId()); + root.put("billerName", transData.getBillerName()); String finalJson = root.toString(); LOGGER.info("[{}] Final Request Sent to API | reqId={} | payload={}", apiName, requestId, finalJson); diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java index 70363d9..0804cb6 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/MasterDataServiceImpl.java @@ -2,28 +2,35 @@ package com.billpaymentservice.bbps.serviceImpl; import java.util.List; import java.util.Map; +import java.util.Optional; import java.util.stream.Collectors; import org.modelmapper.ModelMapper; import org.modelmapper.convention.MatchingStrategies; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import org.springframework.beans.factory.annotation.Autowired; import org.springframework.beans.factory.annotation.Value; import org.springframework.http.HttpHeaders; import org.springframework.stereotype.Service; + +import com.billpaymentservice.bbps.config.JwtUtil; import com.billpaymentservice.bbps.dto.CustomParamDTO; import com.billpaymentservice.bbps.dto.CustomerParamGroupsDTO; import com.billpaymentservice.bbps.dto.GeneralResp; import com.billpaymentservice.bbps.dto.MasterApiResponse; import com.billpaymentservice.bbps.dto.ResponseModel; +import com.billpaymentservice.bbps.dto.UserDetailsDTO; import com.billpaymentservice.bbps.dto.request.BillerDetailRequest; import com.billpaymentservice.bbps.dto.request.ContactMasterRequest; import com.billpaymentservice.bbps.dto.request.CustomParamRequest; import com.billpaymentservice.bbps.dto.request.DispositionRequest; +import com.billpaymentservice.bbps.dto.request.LoginRequest; import com.billpaymentservice.bbps.dto.request.MasterCategoryRequest; import com.billpaymentservice.bbps.dto.request.MasterRequest; import com.billpaymentservice.bbps.dto.request.PlanRequest; import com.billpaymentservice.bbps.dto.response.AmountOptionsResponse; +import com.billpaymentservice.bbps.dto.response.AuthResponse; import com.billpaymentservice.bbps.dto.response.BillerDataResponse; import com.billpaymentservice.bbps.dto.response.BillerResponse; import com.billpaymentservice.bbps.dto.response.ChannelsListResponse; @@ -42,6 +49,7 @@ import com.billpaymentservice.bbps.entites.DispositionDetails; import com.billpaymentservice.bbps.entites.InboundTraceLog; import com.billpaymentservice.bbps.entites.OutboundTraceLog; import com.billpaymentservice.bbps.entites.PlanResponses; +import com.billpaymentservice.bbps.entites.UsersDetails; import com.billpaymentservice.bbps.exception.CustomException; import com.billpaymentservice.bbps.repository.BharatConnectMasterRepository; import com.billpaymentservice.bbps.repository.BillerDataRepository; @@ -50,6 +58,7 @@ import com.billpaymentservice.bbps.repository.DispositionRepository; import com.billpaymentservice.bbps.repository.InboundTraceLogRepository; import com.billpaymentservice.bbps.repository.MerchantRepository; import com.billpaymentservice.bbps.repository.OutboundTraceLogRepository; +import com.billpaymentservice.bbps.repository.UsersDetailsRepository; import com.billpaymentservice.bbps.service.MasterDataService; import com.billpaymentservice.bbps.util.BBPSConstant; import com.billpaymentservice.bbps.util.BillerMapperHelper; @@ -80,6 +89,11 @@ public class MasterDataServiceImpl implements MasterDataService { private final InboundTraceLogRepository inboundTraceLogRepository; private final OutboundTraceLogRepository outboundTraceLogRepository; private final CustomParamRepository customParamReposiotory; + @Autowired + private UsersDetailsRepository userRepo; + + @Autowired + private JwtUtil jwtUtil; public MasterDataServiceImpl(MerchantRepository merchantRegisterRepo, HttpService httpService, HttpClientApi httpClientApi, Helper helper, BillerDataRepository billerDataRespository, @@ -224,7 +238,7 @@ public class MasterDataServiceImpl implements MasterDataService { throw new CustomException("Invalid JSON received from API"); } } - + @Override public ResponseModel getCustomerParamByBillerId(CustomParamRequest customerParamRequest) { String apiName = BBPSConstant.API_GET_CUSTOMER_PARAM_BY_BILLER_ID; @@ -366,7 +380,7 @@ public class MasterDataServiceImpl implements MasterDataService { LOGGER.info("[{}] START | reqId={} | mid={} | billerName={} | category={}", apiName, requestId, mid, masterRequest.getBillerName(), masterRequest.getCategory()); - String txnID = helper.generateTxnId(15); + String txnID = helper.generateTxnId(15); String fullUrl = String.format("%s%s?billerName=%s&category=%s&page=%d&pagesize=%d", masterRegisterUrl, BBPSConstant.BILLER_URL, masterRequest.getBillerName(), masterRequest.getCategory(), masterRequest.getPageNo(), masterRequest.getPageSize()); @@ -472,7 +486,7 @@ public class MasterDataServiceImpl implements MasterDataService { if (entities != null) { dispositionRepository.saveAll(entities); } else { - + LOGGER.warn("No disposition found in response to save."); } @@ -868,4 +882,40 @@ public class MasterDataServiceImpl implements MasterDataService { } } + @Override + public AuthResponse authenticateUser(LoginRequest loginRequest) { + LOGGER.info("Processing login for Request: " + loginRequest); + + try { + String mobileNo = loginRequest.getMobileNumber(); + + Optional byAdminEmail = userRepo.findByUserMobNo(mobileNo); + + if (byAdminEmail.isPresent()) { + UsersDetails user = byAdminEmail.get(); + String token = jwtUtil.generateToken(user.getUserMobNo()); + + LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); + + Object userDetailsDTO = null; + + if (user != null) { + userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getUserEmailId()) + .userMobNo(user.getUserMobNo()).userName(user.getUserName()).userAge(user.getUserAge()) + .build(); + } + return new AuthResponse(token, "Success", "Login Done", 200, userDetailsDTO); + } else { + return new AuthResponse("", "User Not Found", "Authentication failed", 401, null); + } + + } catch (Exception ex) { + System.out.println("Error occurred during login for mobile no: " + loginRequest.getMobileNumber() + + " Exception: " + ex.getMessage()); + + return AuthResponse.builder().status("Unauthorized").message("Authentication failed: " + ex.getMessage()) + .statusCode(401).build(); + } + } + } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java b/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java index 9be701f..735eab2 100644 --- a/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java +++ b/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java @@ -1,7 +1,5 @@ package com.billpaymentservice.bbps.swagger; -import java.util.List; - import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -9,7 +7,8 @@ import org.springframework.context.annotation.Configuration; import io.swagger.v3.oas.models.OpenAPI; import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; -import io.swagger.v3.oas.models.servers.Server; +import io.swagger.v3.oas.models.security.SecurityRequirement; +import io.swagger.v3.oas.models.security.SecurityScheme; @Configuration public class SwaggerConfig { @@ -21,12 +20,14 @@ public class SwaggerConfig { private String serverDescription; @Bean - public OpenAPI openAPI() { - return new OpenAPI() - .info(new Info().title("BBPS API").description("Spring Boot REST API for BBPS System API Documentation") - .version("1.0.0").contact(new Contact().name("BBPS "))) - .servers(List.of(new Server().url(serverUrl).description(serverDescription))); - + public OpenAPI customOpenAPI() { + return new OpenAPI().addSecurityItem(new SecurityRequirement().addList("Authentication")) + .components(new io.swagger.v3.oas.models.Components().addSecuritySchemes("Authentication", + new SecurityScheme().name("Authentication").type(SecurityScheme.Type.APIKEY) + .in(SecurityScheme.In.HEADER))) + .info(new Info().title("Spring Boot REST API").description("Spring Boot REST API for BBPS") + .version("1.0.0").contact(new Contact().name("Globots").url(serverUrl) + .email("info@merchantpanel.com"))); } } diff --git a/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java b/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java index 72f1a52..059db76 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java +++ b/src/main/java/com/billpaymentservice/bbps/util/BillerMapperHelper.java @@ -1044,9 +1044,6 @@ public class BillerMapperHelper { public FetchComplaintForwardRequest fetchComplaintForwardRequestMap(ComplaintRequestDTO complainRequestDTO) { FetchComplaintForwardRequest forward = new FetchComplaintForwardRequest(); - - forward.setBillerId(complainRequestDTO.getBillerId()); - forward.setBillerName(complainRequestDTO.getBillerName()); forward.setTicketDescription(complainRequestDTO.getTicketDescription()); forward.setTicketDisposition(complainRequestDTO.getTicketDisposition()); forward.setTicketDispositionCode(complainRequestDTO.getTicketDispositionCode()); diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties index c652768..d32e5c2 100644 --- a/src/main/resources/application.properties +++ b/src/main/resources/application.properties @@ -19,6 +19,7 @@ swagger.server.description=Local Development Server spring.profiles.active=local + # DataSource spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS spring.datasource.username=postgres @@ -44,7 +45,8 @@ logging.level.io.github.resilience4j.retry=DEBUG master.data.url = https://bbps-staging.digiledge.in/agent/cou-master/masters agent.data.url=https://bbps-staging.digiledge.in/agent/bill-payment-new payment.data.url=https://bbps-staging.digiledge.in/couapp -complaint.data.url=https://bbps-staging.digiledge.in +complaint.data.url=https://bbps-staging.digiledge.in/agent/bill-payment-new + # throw NoHandlerFoundException for 404s spring.mvc.throw-exception-if-no-handler-found=true @@ -55,6 +57,9 @@ spring.web.resources.add-mappings=false # (optional) to avoid path match issues on Spring Boot 2.6+ spring.mvc.pathmatch.matching-strategy=ANT_PATH_MATCHER +jwt.secret=6C756148487475787A414646736D4B6E444E585A766145396E6A4555594A595566657A6E434D62536856674A704C494F6C6E666B366A4A6A6D5630323564716C614F + + # Resilience4j Retry resilience4j.retry.instances.callbackService.max-attempts=1 From b33d6588349b873bdc766bb83e126d040e6e8700 Mon Sep 17 00:00:00 2001 From: Mohd-Arham Date: Thu, 27 Nov 2025 14:41:07 +0530 Subject: [PATCH 3/6] updated code mohd arham --- .../bbps/config/CustomUserDetailsService.java | 9 ++-- .../bbps/config/JwtFilter.java | 23 ++++----- .../bbps/config/JwtUtil.java | 49 ++++++++++--------- .../bbps/config/SecurityConfig.java | 27 +++++----- .../bbps/controller/AuthController.java | 46 ++++++++--------- .../bbps/dto/UserDetailsDTO.java | 2 +- .../repository/UsersDetailsRepository.java | 6 +-- .../bbps/serviceImpl/AuthServiceImpl.java | 41 +++++++--------- .../bbps/util/BBPSConstant.java | 4 ++ .../resources/application-local.properties | 4 +- 10 files changed, 108 insertions(+), 103 deletions(-) diff --git a/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java b/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java index fb26179..e6c3698 100644 --- a/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java +++ b/src/main/java/com/billpaymentservice/bbps/config/CustomUserDetailsService.java @@ -10,6 +10,7 @@ import org.springframework.security.core.userdetails.UserDetailsService; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; +import com.billpaymentservice.bbps.entites.UserEntity; import com.billpaymentservice.bbps.entites.UsersDetails; import com.billpaymentservice.bbps.repository.UsersDetailsRepository; @@ -22,13 +23,11 @@ public class CustomUserDetailsService implements UserDetailsService { @Override public UserDetails loadUserByUsername(String userMobNo) throws UsernameNotFoundException { - String normalizedEmail = userMobNo; - - Optional adminOptional = userRepo.findByUserMobNo(normalizedEmail); + Optional adminOptional = userRepo.findByMobile(userMobNo); if (adminOptional.isPresent()) { - UsersDetails user = adminOptional.get(); - return new User(user.getUserEmailId(), user.getUserMobNo(), new ArrayList<>()); + UserEntity user = adminOptional.get(); + return new User(user.getMobile(), user.getName(), new ArrayList<>()); } else { throw new UsernameNotFoundException("User not found with MobNo: " + userMobNo); } diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java b/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java index fa06986..b7b8b3d 100644 --- a/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtFilter.java @@ -2,7 +2,6 @@ package com.billpaymentservice.bbps.config; import java.io.IOException; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.security.core.userdetails.UserDetails; @@ -19,11 +18,14 @@ import jakarta.servlet.http.HttpServletResponse; @Component public class JwtFilter extends OncePerRequestFilter { - @Autowired - private JwtUtil jwtUtil; + private final JwtUtil jwtUtil; - @Autowired - private CustomUserDetailsService userDetailsService; + private final CustomUserDetailsService userDetailsService; + + public JwtFilter(JwtUtil jwtUtil, CustomUserDetailsService userDetailsService) { + this.jwtUtil = jwtUtil; + this.userDetailsService = userDetailsService; + } @Override protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) @@ -31,13 +33,13 @@ public class JwtFilter extends OncePerRequestFilter { final String authorizationHeader = request.getHeader("Authentication"); - String email = null; + String mobileNo = null; String jwt = null; if (authorizationHeader != null && authorizationHeader.startsWith("Bearer ")) { jwt = authorizationHeader.substring(7); try { - email = jwtUtil.extractUsername(jwt); + mobileNo = jwtUtil.extractUsername(jwt); } catch (IllegalArgumentException e) { System.out.println("unable to get jwt tokken"); } catch (ExpiredJwtException e) { @@ -47,11 +49,10 @@ public class JwtFilter extends OncePerRequestFilter { } } - if (email != null && SecurityContextHolder.getContext().getAuthentication() == null) { + if (mobileNo != null && SecurityContextHolder.getContext().getAuthentication() == null) { - UserDetails userDetails = this.userDetailsService.loadUserByUsername(email); + UserDetails userDetails = this.userDetailsService.loadUserByUsername(mobileNo); - if (jwtUtil.validateToken(jwt, userDetails)) { UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken( @@ -60,7 +61,7 @@ public class JwtFilter extends OncePerRequestFilter { SecurityContextHolder.getContext().setAuthentication(authentication); } else { - System.out.println("JWT Filter: Token validation failed for user - " + email); + System.out.println("JWT Filter: Token validation failed for user - " + mobileNo); } } diff --git a/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java b/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java index 1111b3e..23d683f 100644 --- a/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java +++ b/src/main/java/com/billpaymentservice/bbps/config/JwtUtil.java @@ -10,6 +10,8 @@ import org.springframework.beans.factory.annotation.Value; import org.springframework.security.core.userdetails.UserDetails; import org.springframework.stereotype.Service; +import com.billpaymentservice.bbps.util.BBPSConstant; + import io.jsonwebtoken.Claims; import io.jsonwebtoken.Jwts; import io.jsonwebtoken.SignatureAlgorithm; @@ -22,22 +24,23 @@ public class JwtUtil { @Value("${jwt.secret}") private String secret; + private final Map tokenBlacklist = new HashMap<>(); + private Key getSigningKey() { byte[] keyBytes = Decoders.BASE64.decode(secret); return Keys.hmacShaKeyFor(keyBytes); } - // Access Token - 2 Hours - private final long jwtExpirationInMs = 1000 * 60 * 60 * 2; // 2 hours - - // Refresh Token - 7 Days - private final long refreshExpirationDateInMs = 1000L * 60 * 60 * 24 * 7; // 7 days - - private final Map tokenBlacklist = new HashMap<>(); + public String generateToken(String username, String mid) { + Map claims = new HashMap<>(); + claims.put("mid", mid); + claims.put("expiryTime", new Date(System.currentTimeMillis() + BBPSConstant.JWT_EXPIRATION_MS).toString()); + return createToken(claims, username.toUpperCase()); + } public String doGenerateRefreshToken(Map claims, String subject) { return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + refreshExpirationDateInMs)) + .setExpiration(new Date(System.currentTimeMillis() + BBPSConstant.REFRESH_EXPIRATION_MS)) .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); } @@ -62,28 +65,28 @@ public class JwtUtil { return extractExpiration(token).before(new Date()); } - public String generateToken(String username, String mid) { - Map claims = new HashMap<>(); - claims.put("mid", mid); - claims.put("expiryTime", new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10).toString()); - return createToken(claims, username.toUpperCase()); + private String createToken(Map claims, String subject) { + return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) + .setExpiration(new Date(System.currentTimeMillis() + BBPSConstant.JWT_EXPIRATION_MS)) + .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); } - private String createToken(Map claims, String subject) { + private String createToken1(Map claims,String subject) { return Jwts.builder().setClaims(claims).setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); } - private String createToken1(String subject) { - return Jwts.builder().setSubject(subject).setIssuedAt(new Date(System.currentTimeMillis())) - .setExpiration(new Date(System.currentTimeMillis() + 1000 * 60 * 60 * 10)) - .signWith(getSigningKey(), SignatureAlgorithm.HS512).compact(); - } +// public Boolean validateToken(String token, UserDetails userDetails) { +// final String username = extractUsername(token); +// return true; +// } public Boolean validateToken(String token, UserDetails userDetails) { - final String username = extractUsername(token); - return true; + final String mobileNo = extractUsername(token); +// System.out.println("Extracted mobileNo from token: " + mobileNo ); +// System.out.println("Username from UserDetails: " + userDetails.getUsername()); + return (mobileNo .equals(userDetails.getUsername()) && !isTokenExpired(token)); } public void invalidateToken(String token) { @@ -96,7 +99,9 @@ public class JwtUtil { } public String generateToken(String mobileNo) { - return createToken1(mobileNo); + Map claims = new HashMap<>(); + claims.put("mobileNo", mobileNo); + return createToken1(claims,mobileNo); } } diff --git a/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java b/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java index 5270cb6..15f9c4b 100644 --- a/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java +++ b/src/main/java/com/billpaymentservice/bbps/config/SecurityConfig.java @@ -2,9 +2,7 @@ package com.billpaymentservice.bbps.config; import java.util.Arrays; -import org.springframework.beans.factory.annotation.Autowired; import org.springframework.context.annotation.Bean; -import org.springframework.context.annotation.ComponentScan; import org.springframework.context.annotation.Configuration; import org.springframework.http.HttpMethod; import org.springframework.security.config.annotation.web.builders.HttpSecurity; @@ -20,11 +18,14 @@ import org.springframework.web.cors.UrlBasedCorsConfigurationSource; @EnableWebSecurity public class SecurityConfig { - @Autowired - private JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; + private final JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint; - @Autowired - private JwtFilter jwtFilter; + private final JwtFilter jwtFilter; + + public SecurityConfig(JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint, JwtFilter jwtFilter) { + this.jwtAuthenticationEntryPoint = jwtAuthenticationEntryPoint; + this.jwtFilter = jwtFilter; + } @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { @@ -32,13 +33,13 @@ public class SecurityConfig { http.csrf(csrf -> csrf.disable()).cors(cors -> cors.configurationSource(corsConfigurationSource())) .authorizeHttpRequests(auth -> auth .requestMatchers("/auth/**", - "/v3/api-docs/**", - "/swagger-ui/**", - "/swagger-ui.html", - "/swagger-resources/**", - "/webjars/**", - "/error") - .permitAll().requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() // <-- Correct way + "/v3/api-docs/**", + "/swagger-ui/**", + "/swagger-ui.html", + "/swagger-resources/**", + "/webjars/**", + "/error") + .permitAll().requestMatchers(HttpMethod.OPTIONS, "/**").permitAll() .anyRequest().authenticated()) .exceptionHandling(ex -> ex.authenticationEntryPoint(jwtAuthenticationEntryPoint)) .sessionManagement(session -> session.sessionCreationPolicy(SessionCreationPolicy.STATELESS)); diff --git a/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java index fcbe602..b8b7a32 100644 --- a/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java +++ b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java @@ -25,32 +25,32 @@ import lombok.extern.slf4j.Slf4j; @Slf4j public class AuthController { - private final AuthService authService; + private final AuthService authService; - public AuthController(AuthService authService) { - this.authService = authService; - } + public AuthController(AuthService authService) { + this.authService = authService; + } - @PostMapping(value = "/sendOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity sendOtp(@Validated @RequestBody LoginRequest request) { - log.info("Received sendOtp request for mobile: {}", request.getMobile()); - OtpSendResponse resp = authService.sendOtp(request); - return ResponseEntity.ok(resp); - } + @PostMapping(value = "/sendOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity sendOtp(@Validated @RequestBody LoginRequest request) { + log.info("Received sendOtp request for mobile: {}", request.getMobile()); + OtpSendResponse resp = authService.sendOtp(request); + return ResponseEntity.ok(resp); + } - @PostMapping(value = "/verifyOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity verifyOtp(@Validated @RequestBody VerifyOtpRequest request) { - AuthResponses resp = authService.verifyOtp(request); - return ResponseEntity.ok(resp); - } + @PostMapping(value = "/verifyOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity verifyOtp(@Validated @RequestBody VerifyOtpRequest request) { + AuthResponses resp = authService.verifyOtp(request); + return ResponseEntity.ok(resp); + } - @PostMapping(value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity register(@Validated @RequestBody RegisterRequest request) { - AuthResponse resp = authService.registerUser(request); - return ResponseEntity.ok(resp); - } - - @PostMapping("/loginWithoutDecryption") + @PostMapping(value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) + public ResponseEntity register(@Validated @RequestBody RegisterRequest request) { + AuthResponse resp = authService.registerUser(request); + return ResponseEntity.ok(resp); + } + + @PostMapping("/loginWithoutDecryption") public ResponseEntity login(@RequestBody LoginRequest loginRequest) { try { AuthResponses authResponse = authService.authenticateUser(loginRequest); @@ -60,5 +60,5 @@ public class AuthController { .message("An unexpected error occurred").statusCode(500).build()); } } - + } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java b/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java index 46575e1..2962792 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/UserDetailsDTO.java @@ -19,5 +19,5 @@ public class UserDetailsDTO { private String userName; - private String userAge; + private int userAge; } diff --git a/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java b/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java index 2f6a983..eeca8d4 100644 --- a/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java +++ b/src/main/java/com/billpaymentservice/bbps/repository/UsersDetailsRepository.java @@ -5,11 +5,11 @@ import java.util.Optional; import org.springframework.data.jpa.repository.JpaRepository; import org.springframework.stereotype.Repository; -import com.billpaymentservice.bbps.entites.UsersDetails; +import com.billpaymentservice.bbps.entites.UserEntity; @Repository -public interface UsersDetailsRepository extends JpaRepository { +public interface UsersDetailsRepository extends JpaRepository { - Optional findByUserMobNo(String userMobNo); + Optional findByMobile(String userMobNo); } diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java index 2d962c9..d07f367 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java @@ -16,7 +16,6 @@ import com.billpaymentservice.bbps.dto.auth.UserDto; import com.billpaymentservice.bbps.dto.auth.VerifyOtpRequest; import com.billpaymentservice.bbps.dto.response.AuthResponses; import com.billpaymentservice.bbps.entites.UserEntity; -import com.billpaymentservice.bbps.entites.UsersDetails; import com.billpaymentservice.bbps.repository.UserRepository; import com.billpaymentservice.bbps.repository.UsersDetailsRepository; import com.billpaymentservice.bbps.service.AuthService; @@ -37,14 +36,13 @@ public class AuthServiceImpl implements AuthService { private final JwtUtil jwtUtil; - @Autowired public AuthServiceImpl(UserRepository userRepository, OtpClient otpClient, Helper helper, UsersDetailsRepository userRepo, JwtUtil jwtUtil) { this.userRepository = userRepository; this.otpClient = otpClient; this.helper = helper; - this.userRepo=userRepo; - this.jwtUtil=jwtUtil; + this.userRepo = userRepo; + this.jwtUtil = jwtUtil; } @Override @@ -63,28 +61,26 @@ public class AuthServiceImpl implements AuthService { @Override public AuthResponses verifyOtp(VerifyOtpRequest request) { boolean ok = otpClient.verifyOtp(request.getMobile(), request.getOtp()); - LOGGER.info("OTP STATUS"+ ok); + LOGGER.info("OTP STATUS" + ok); if (ok) { - return new AuthResponses("","Invalid OTP","Failed", 401, null); + return new AuthResponses("", "Invalid OTP", "Failed", 401, null); } String mobileNo = request.getMobile(); try { - - Optional byAdminEmail = userRepo.findByUserMobNo(mobileNo); + Optional byAdminEmail = userRepo.findByMobile(mobileNo); if (byAdminEmail.isPresent()) { - UsersDetails user = byAdminEmail.get(); - String token = jwtUtil.generateToken(user.getUserMobNo()); + UserEntity user = byAdminEmail.get(); + String token = jwtUtil.generateToken(user.getMobile()); LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); Object userDetailsDTO = null; if (user != null) { - userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getUserEmailId()) - .userMobNo(user.getUserMobNo()).userName(user.getUserName()).userAge(user.getUserAge()) - .build(); + userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getEmail()) + .userMobNo(user.getMobile()).userName(user.getName()).userAge(user.getAge()).build(); } return new AuthResponses(token, "Success", "Login Done", 200, userDetailsDTO); } else { @@ -92,8 +88,8 @@ public class AuthServiceImpl implements AuthService { } } catch (Exception ex) { - System.out.println("Error occurred during login for mobile no: " + mobileNo - + " Exception: " + ex.getMessage()); + System.out.println( + "Error occurred during login for mobile no: " + mobileNo + " Exception: " + ex.getMessage()); return AuthResponses.builder().status("Unauthorized").message("Authentication failed: " + ex.getMessage()) .statusCode(401).build(); @@ -137,20 +133,19 @@ public class AuthServiceImpl implements AuthService { try { String mobileNo = loginRequest.getMobile(); - Optional byAdminEmail = userRepo.findByUserMobNo(mobileNo); + Optional byAdminEmail = userRepo.findByMobile(mobileNo); if (byAdminEmail.isPresent()) { - UsersDetails user = byAdminEmail.get(); - String token = jwtUtil.generateToken(user.getUserMobNo()); + UserEntity user = byAdminEmail.get(); + String token = jwtUtil.generateToken(user.getMobile()); LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); Object userDetailsDTO = null; if (user != null) { - userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getUserEmailId()) - .userMobNo(user.getUserMobNo()).userName(user.getUserName()).userAge(user.getUserAge()) - .build(); + userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getEmail()) + .userMobNo(user.getMobile()).userName(user.getName()).userAge(user.getAge()).build(); } return new AuthResponses(token, "Success", "Login Done", 200, userDetailsDTO); } else { @@ -158,8 +153,8 @@ public class AuthServiceImpl implements AuthService { } } catch (Exception ex) { - System.out.println("Error occurred during login for mobile no: " + loginRequest.getMobile() - + " Exception: " + ex.getMessage()); + System.out.println("Error occurred during login for mobile no: " + loginRequest.getMobile() + " Exception: " + + ex.getMessage()); return AuthResponses.builder().status("Unauthorized").message("Authentication failed: " + ex.getMessage()) .statusCode(401).build(); diff --git a/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java b/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java index 4b8eaef..50e56a3 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java +++ b/src/main/java/com/billpaymentservice/bbps/util/BBPSConstant.java @@ -2,6 +2,10 @@ package com.billpaymentservice.bbps.util; public class BBPSConstant { + // Jwt Token Expiration Time + public static final long JWT_EXPIRATION_MS = 1000 * 60 * 60 * 24; // 24 hours + public static final long REFRESH_EXPIRATION_MS = 1000L * 60 * 60 * 24 * 7; // 7 days + public static final Long SENT_TO_PROCESSOR_CODE = 198L; public static final Long SUCCESS_CODE = 200L; public static final Long FAILED_CODE = 99L; diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index 4eaafbc..aaf1e10 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -20,9 +20,9 @@ swagger.server.description=Local Development Server # DataSource spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS spring.datasource.username=postgres -#spring.datasource.password=UAT@DB_2025 +spring.datasource.password=UAT@DB_2025 -spring.datasource.password=himanshu@123 +#spring.datasource.password=himanshu@123 spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.type=com.zaxxer.hikari.HikariDataSource From a001728c4faa39532b25851e2a51cc6d39079c93 Mon Sep 17 00:00:00 2001 From: Lincpay Tech Date: Thu, 27 Nov 2025 14:44:21 +0530 Subject: [PATCH 4/6] added login with otp ,verify otp and registred user --- .../bbps/controller/AuthController.java | 30 +- .../bbps/dto/auth/AuthResponse.java | 51 ++-- .../bbps/dto/auth/RegisterRequest.java | 2 +- .../bbps/dto/auth/UserDto.java | 2 +- .../bbps/entites/UserEntity.java | 9 +- .../bbps/service/AuthService.java | 9 +- .../bbps/serviceImpl/AuthServiceImpl.java | 264 ++++++++++-------- .../bbps/util/OtpClient.java | 37 +-- 8 files changed, 203 insertions(+), 201 deletions(-) diff --git a/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java index fcbe602..2a96adc 100644 --- a/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java +++ b/src/main/java/com/billpaymentservice/bbps/controller/AuthController.java @@ -9,6 +9,7 @@ import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RequestMapping; import org.springframework.web.bind.annotation.RestController; +import com.billpaymentservice.bbps.dto.ResponseModel; import com.billpaymentservice.bbps.dto.auth.AuthResponse; import com.billpaymentservice.bbps.dto.response.AuthResponses; import com.billpaymentservice.bbps.dto.auth.LoginRequest; @@ -32,33 +33,28 @@ public class AuthController { } @PostMapping(value = "/sendOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity sendOtp(@Validated @RequestBody LoginRequest request) { + public ResponseEntity sendOtp(@Validated @RequestBody LoginRequest request) { log.info("Received sendOtp request for mobile: {}", request.getMobile()); - OtpSendResponse resp = authService.sendOtp(request); - return ResponseEntity.ok(resp); + return ResponseEntity.ok(authService.sendOtp(request)); } @PostMapping(value = "/verifyOtp", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity verifyOtp(@Validated @RequestBody VerifyOtpRequest request) { - AuthResponses resp = authService.verifyOtp(request); - return ResponseEntity.ok(resp); + public ResponseEntity verifyOtp(@Validated @RequestBody VerifyOtpRequest request) { + + return ResponseEntity.ok(authService.verifyOtp(request)); } @PostMapping(value = "/register", consumes = MediaType.APPLICATION_JSON_VALUE, produces = MediaType.APPLICATION_JSON_VALUE) - public ResponseEntity register(@Validated @RequestBody RegisterRequest request) { - AuthResponse resp = authService.registerUser(request); - return ResponseEntity.ok(resp); + public ResponseEntity register(@Validated @RequestBody RegisterRequest request) { + + return ResponseEntity.ok(authService.registerUser(request)); } @PostMapping("/loginWithoutDecryption") - public ResponseEntity login(@RequestBody LoginRequest loginRequest) { - try { - AuthResponses authResponse = authService.authenticateUser(loginRequest); - return ResponseEntity.ok(authResponse); - } catch (Exception e) { - return ResponseEntity.status(500).body(AuthResponses.builder().status("Unauthorized") - .message("An unexpected error occurred").statusCode(500).build()); - } + public ResponseEntity login(@RequestBody LoginRequest loginRequest) { + + return ResponseEntity.ok(authService.authenticateUser(loginRequest)); + } } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java index a88d366..af3dbec 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/AuthResponse.java @@ -1,14 +1,23 @@ package com.billpaymentservice.bbps.dto.auth; -import com.billpaymentservice.bbps.dto.auth.UserDto; +import com.fasterxml.jackson.annotation.JsonInclude; +import lombok.AllArgsConstructor; +import lombok.Getter; +import lombok.NoArgsConstructor; +import lombok.Setter; + +@Getter +@Setter +@NoArgsConstructor +@AllArgsConstructor +@JsonInclude(JsonInclude.Include.NON_NULL) public class AuthResponse { private boolean success; private String message; private boolean userExists; private UserDto user; - - public AuthResponse() {} + private String token; public AuthResponse(boolean success, String message, boolean userExists, UserDto user) { this.success = success; @@ -16,36 +25,10 @@ public class AuthResponse { this.userExists = userExists; this.user = user; } + public AuthResponse(boolean success, String message, String token) { + this.success = success; + this.message = message; + this.token = token; + } - public boolean isSuccess() { - return success; - } - - public void setSuccess(boolean success) { - this.success = success; - } - - public String getMessage() { - return message; - } - - public void setMessage(String message) { - this.message = message; - } - - public boolean isUserExists() { - return userExists; - } - - public void setUserExists(boolean userExists) { - this.userExists = userExists; - } - - public UserDto getUser() { - return user; - } - - public void setUser(UserDto user) { - this.user = user; - } } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java index ee156a1..be23b07 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/RegisterRequest.java @@ -9,6 +9,6 @@ public class RegisterRequest { private String mobile; private String name; private String email; - private int age; + private String age; } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java b/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java index 1c35570..e6efb71 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/auth/UserDto.java @@ -14,7 +14,7 @@ public class UserDto { private String mobile; private String name; private String email; - private int age; + private String age; } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java b/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java index ab454eb..135305e 100644 --- a/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java +++ b/src/main/java/com/billpaymentservice/bbps/entites/UserEntity.java @@ -35,7 +35,14 @@ public class UserEntity extends Auditable { private String email; @Column(name = "age") - private int age; + private String age; + + public UserEntity(String mobile, String name, String email, String age) { + this.mobile = mobile; + this.name = name; + this.email = email; + this.age = age; + } diff --git a/src/main/java/com/billpaymentservice/bbps/service/AuthService.java b/src/main/java/com/billpaymentservice/bbps/service/AuthService.java index 5698c80..b9a5926 100644 --- a/src/main/java/com/billpaymentservice/bbps/service/AuthService.java +++ b/src/main/java/com/billpaymentservice/bbps/service/AuthService.java @@ -1,5 +1,6 @@ package com.billpaymentservice.bbps.service; +import com.billpaymentservice.bbps.dto.ResponseModel; import com.billpaymentservice.bbps.dto.auth.AuthResponse; import com.billpaymentservice.bbps.dto.auth.LoginRequest; import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; @@ -9,13 +10,13 @@ import com.billpaymentservice.bbps.dto.response.AuthResponses; import com.billpaymentservice.bbps.entites.UserEntity; public interface AuthService { - OtpSendResponse sendOtp(LoginRequest request); + ResponseModel sendOtp(LoginRequest request); - AuthResponses verifyOtp(VerifyOtpRequest request); + ResponseModel verifyOtp(VerifyOtpRequest request); - AuthResponse registerUser(RegisterRequest request); + ResponseModel registerUser(RegisterRequest request); UserEntity findByMobile(String mobile); - AuthResponses authenticateUser(LoginRequest loginRequest); + ResponseModel authenticateUser(LoginRequest loginRequest); } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java index 2d962c9..8a87cf2 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/AuthServiceImpl.java @@ -5,9 +5,9 @@ import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; - import com.billpaymentservice.bbps.config.JwtUtil; import com.billpaymentservice.bbps.dto.UserDetailsDTO; +import com.billpaymentservice.bbps.dto.ResponseModel; import com.billpaymentservice.bbps.dto.auth.AuthResponse; import com.billpaymentservice.bbps.dto.auth.LoginRequest; import com.billpaymentservice.bbps.dto.auth.OtpSendResponse; @@ -22,147 +22,175 @@ import com.billpaymentservice.bbps.repository.UsersDetailsRepository; import com.billpaymentservice.bbps.service.AuthService; import com.billpaymentservice.bbps.util.Helper; import com.billpaymentservice.bbps.util.OtpClient; - import java.util.Optional; @Service public class AuthServiceImpl implements AuthService { - private static final Logger LOGGER = LoggerFactory.getLogger(AuthServiceImpl.class); + private static final Logger LOGGER = LoggerFactory.getLogger(AuthServiceImpl.class); - private final UserRepository userRepository; - private final OtpClient otpClient; - private final Helper helper; - private final UsersDetailsRepository userRepo; + private final UserRepository userRepository; + private final OtpClient otpClient; + private final Helper helper; + private final UsersDetailsRepository userRepo; + private final JwtUtil jwtUtil; - private final JwtUtil jwtUtil; + @Autowired + public AuthServiceImpl(UserRepository userRepository, OtpClient otpClient, Helper helper, + UsersDetailsRepository userRepo, JwtUtil jwtUtil) { + this.userRepository = userRepository; + this.otpClient = otpClient; + this.helper = helper; + this.userRepo = userRepo; + this.jwtUtil = jwtUtil; + } - @Autowired - public AuthServiceImpl(UserRepository userRepository, OtpClient otpClient, Helper helper, - UsersDetailsRepository userRepo, JwtUtil jwtUtil) { - this.userRepository = userRepository; - this.otpClient = otpClient; - this.helper = helper; - this.userRepo=userRepo; - this.jwtUtil=jwtUtil; - } + @Override + public ResponseModel sendOtp(LoginRequest request) { + try { + OtpSendResponse resp = otpClient.sendOtp(request.getMobile()); + if (resp == null) { + return ResponseModel.builder() + .message("OTP send service returned null") + .status("Failure") + .statusCode(500) + .data(null) + .build(); + } + String status = resp.isSuccess() ? "Success" : "Failure"; + int code = resp.isSuccess() ? 200 : 400; + return ResponseModel.builder() + .message(resp.getMessage()) + .status(status) + .statusCode(code) + .data(resp) + .build(); + } catch (Exception ex) { + LOGGER.error("Error in sendOtp: {}", ex.getMessage(), ex); + return ResponseModel.builder() + .message("An unexpected error occurred while sending OTP") + .status("Failure") + .statusCode(500) + .data(null) + .build(); + } + } - @Override - public OtpSendResponse sendOtp(LoginRequest request) { - Optional existing = userRepository.findByMobile(request.getMobile()); + @Override + public ResponseModel verifyOtp(VerifyOtpRequest request) { + boolean ok = otpClient.verifyOtp(request.getMobile(), request.getOtp()); + LOGGER.info("OTP STATUS {}", ok); + if (!ok) { + return ResponseModel.builder() + .message("Invalid OTP") + .status("Failure") + .statusCode(401) + .data(null) + .build(); + } + String mobileNo = request.getMobile(); + try { + Optional byMobileNumber = userRepository.findByMobile(mobileNo); - if (existing.isPresent()) { - UserEntity u = existing.get(); - UserDto dto = new UserDto(u.getId(), u.getMobile(), u.getName(), u.getEmail(), u.getAge()); - return null; - } - // delegate to external OTP provider - return otpClient.sendOtp(request.getMobile()); - } + if (byMobileNumber.isPresent()) { + UserEntity user = byMobileNumber.get(); + String token = jwtUtil.generateToken(user.getMobile()); - @Override - public AuthResponses verifyOtp(VerifyOtpRequest request) { - boolean ok = otpClient.verifyOtp(request.getMobile(), request.getOtp()); - LOGGER.info("OTP STATUS"+ ok); - if (ok) { - return new AuthResponses("","Invalid OTP","Failed", 401, null); - } - String mobileNo = request.getMobile(); - try { - + LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); - Optional byAdminEmail = userRepo.findByUserMobNo(mobileNo); + Object userDetailsDTO = null; - if (byAdminEmail.isPresent()) { - UsersDetails user = byAdminEmail.get(); - String token = jwtUtil.generateToken(user.getUserMobNo()); + if (user != null) { + userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getEmail()) + .userMobNo(user.getMobile()).userName(user.getName()).userAge(user.getAge()) + .build(); + } - LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); + AuthResponses authResp = new AuthResponses(token, "Success", "Login Success", 200, userDetailsDTO); + return ResponseModel.builder() + .message("Login Success") + .status("Success") + .statusCode(200) + .data(authResp) + .build(); + } else { + AuthResponses authResp = new AuthResponses("", "User Not Found", "Authentication failed", 401, null); + return ResponseModel.builder() + .message("User Not Found") + .status("Failure") + .statusCode(401) + .data(authResp) + .build(); + } - Object userDetailsDTO = null; + } catch (Exception ex) { + LOGGER.error("Error occurred during login for mobile no: {} Exception: {}", mobileNo, ex.getMessage(), ex); + return ResponseModel.builder().message("Authentication failed: " + ex.getMessage()).status("Failure") + .statusCode(500).data(null).build(); + } + } - if (user != null) { - userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getUserEmailId()) - .userMobNo(user.getUserMobNo()).userName(user.getUserName()).userAge(user.getUserAge()) - .build(); - } - return new AuthResponses(token, "Success", "Login Done", 200, userDetailsDTO); - } else { - return new AuthResponses("", "User Not Found", "Authentication failed", 401, null); - } + @Override + @Transactional + public ResponseModel registerUser(RegisterRequest request) { + try { + Optional existing = userRepository.findByMobile(request.getMobile()); + if (existing.isPresent()) { + UserEntity u = existing.get(); + UserDto dto = new UserDto(u.getId(), u.getMobile(), u.getName(), u.getEmail(), u.getAge()); + AuthResponse ar = new AuthResponse(false, "User already exists", true, dto); + return ResponseModel.builder().message(ar.getMessage()).status("Failure").statusCode(409).data(ar).build(); + } - } catch (Exception ex) { - System.out.println("Error occurred during login for mobile no: " + mobileNo - + " Exception: " + ex.getMessage()); + UserEntity newUser = new UserEntity(request.getMobile(), request.getName(), request.getEmail(), request.getAge()); + userRepository.save(newUser); + String token = jwtUtil.generateToken(newUser.getMobile()); + UserDto dto = new UserDto(newUser.getId(), newUser.getMobile(), newUser.getName(), newUser.getEmail(), newUser.getAge()); + AuthResponse ar = new AuthResponse(true, "user registed sucessfully", token); + return ResponseModel.builder().message(ar.getMessage()).status("Success").statusCode(201).data(ar).build(); + } catch (Exception ex) { + LOGGER.error("Error in registerUser: {}", ex.getMessage(), ex); + return ResponseModel.builder().message("An unexpected error occurred while registering user").status("Failure").statusCode(500).data(null).build(); + } + } - return AuthResponses.builder().status("Unauthorized").message("Authentication failed: " + ex.getMessage()) - .statusCode(401).build(); - } + @Override + public ResponseModel authenticateUser(LoginRequest loginRequest) { + LOGGER.info("Processing login for Request: {}", loginRequest); -// Optional userOpt = userRepository.findByMobile(request.getMobile()); -// if (userOpt.isPresent()) { -// UserEntity user = userOpt.get(); -// UserDto dto = new UserDto(user.getId(), user.getMobile(), user.getName(), user.getEmail(), user.getAge()); -// return new AuthResponse(true, "Login successful", true, dto); -// } else { -// return new AuthResponse(true, "OTP verified; user not found - proceed to registration", false, null); -// } - } + try { + String mobileNo = loginRequest.getMobile(); - @Override - @Transactional - public AuthResponse registerUser(RegisterRequest request) { - Optional existing = userRepository.findByMobile(request.getMobile()); - if (existing.isPresent()) { - UserEntity u = existing.get(); - UserDto dto = new UserDto(u.getId(), u.getMobile(), u.getName(), u.getEmail(), u.getAge()); - return new AuthResponse(false, "User already exists", true, dto); - } + Optional byMobileNo = userRepo.findByUserMobNo(mobileNo); - UserEntity user = helper.createNewUser(request); - user = userRepository.save(user); - UserDto dto = new UserDto(user.getId(), user.getMobile(), user.getName(), user.getEmail(), user.getAge()); - return new AuthResponse(true, "Registration successful", true, dto); - } + if (byMobileNo.isPresent()) { + UsersDetails user = byMobileNo.get(); + String token = jwtUtil.generateToken(user.getUserMobNo()); - @Override - public UserEntity findByMobile(String mobile) { - return userRepository.findByMobile(mobile).orElse(null); - } + LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); - @Override - public AuthResponses authenticateUser(LoginRequest loginRequest) { - LOGGER.info("Processing login for Request: " + loginRequest); + Object userDetailsDTO = null; - try { - String mobileNo = loginRequest.getMobile(); + if (user != null) { + userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getUserEmailId()) + .userMobNo(user.getUserMobNo()).userName(user.getUserName()).userAge(user.getUserAge()) + .build(); + } + AuthResponses authResp = new AuthResponses(token, "Success", "Login Done", 200, userDetailsDTO); + return ResponseModel.builder().message("Login Done").status("Success").statusCode(200).data(authResp).build(); + } else { + AuthResponses authResp = new AuthResponses("", "User Not Found", "Authentication failed", 401, null); + return ResponseModel.builder().message("User Not Found").status("Failure").statusCode(401).data(authResp).build(); + } - Optional byAdminEmail = userRepo.findByUserMobNo(mobileNo); + } catch (Exception ex) { + LOGGER.error("Error occurred during login for mobile no: {} Exception: {}", loginRequest.getMobile(), ex.getMessage(), ex); + return ResponseModel.builder().message("Authentication failed: " + ex.getMessage()).status("Failure").statusCode(500).data(null).build(); + } + } - if (byAdminEmail.isPresent()) { - UsersDetails user = byAdminEmail.get(); - String token = jwtUtil.generateToken(user.getUserMobNo()); - - LOGGER.info("Generated JWT token for mobileNo: " + mobileNo); - - Object userDetailsDTO = null; - - if (user != null) { - userDetailsDTO = UserDetailsDTO.builder().id(user.getId()).userEmailId(user.getUserEmailId()) - .userMobNo(user.getUserMobNo()).userName(user.getUserName()).userAge(user.getUserAge()) - .build(); - } - return new AuthResponses(token, "Success", "Login Done", 200, userDetailsDTO); - } else { - return new AuthResponses("", "User Not Found", "Authentication failed", 401, null); - } - - } catch (Exception ex) { - System.out.println("Error occurred during login for mobile no: " + loginRequest.getMobile() - + " Exception: " + ex.getMessage()); - - return AuthResponses.builder().status("Unauthorized").message("Authentication failed: " + ex.getMessage()) - .statusCode(401).build(); - } - } + @Override + public UserEntity findByMobile(String mobile) { + return userRepository.findByMobile(mobile).orElse(null); + } } \ No newline at end of file diff --git a/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java b/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java index 758ced5..24530bf 100644 --- a/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java +++ b/src/main/java/com/billpaymentservice/bbps/util/OtpClient.java @@ -53,13 +53,6 @@ public class OtpClient { try { logger.info("Initiating OTP send process for mobile: {}", mobile); - logger.info("eKYC Mobile URL: {}", ekycMobileUrl); - logger.info("API Key: {}", apiKey != null && !apiKey.isEmpty()); - logger.info("Secret Key: {}", secretKey != null && !secretKey.isEmpty()); - logger.info("Send URL: {}", sendUrl); - logger.info("Verify URL: {}", verifyUrl); - logger.info("Mobile Number: {}", mobile); - // If explicit eKYC config present, use that flow if (ekycMobileUrl != null && !ekycMobileUrl.isEmpty()) { HttpHeaders headers = new HttpHeaders(); @@ -145,28 +138,20 @@ public class OtpClient { if (response.getStatusCode() == HttpStatus.OK) { String respBody = response.getBody(); + if (respBody != null) { - // try to parse JSON and look for common verification keys ObjectMapper mapper = new ObjectMapper(); - try { - Map respMap = mapper.readValue(respBody, Map.class); - if (respMap.containsKey("verified")) { - return Boolean.TRUE.equals(respMap.get("verified")); - } - if (respMap.containsKey("success")) { - return Boolean.TRUE.equals(respMap.get("success")); - } - if (respMap.containsKey("status") && "OK".equalsIgnoreCase(String.valueOf(respMap.get("status")))) { - return true; - } - } catch (Exception e) { - logger.debug("Unable to parse verification response body to JSON: {}", e.getMessage()); - // fall through to treat 200 as success + Map respMap = mapper.readValue(respBody, Map.class); + + // Check correct key of your service + if (respMap.containsKey("status")) { + return Boolean.TRUE.equals(respMap.get("status")); } } - // fallback: treat HTTP 200 as successful verification - return true; - } else { + + return false; // default fallback + } + else { logger.warn("OTP verification endpoint returned non-OK status: {}", response.getStatusCode()); return false; } @@ -183,4 +168,6 @@ public class OtpClient { return false; } } + + } From 99d8778bfe07d4249b5c89ab81ae56e51b92f15c Mon Sep 17 00:00:00 2001 From: Lincpay Tech Date: Fri, 28 Nov 2025 11:04:29 +0530 Subject: [PATCH 5/6] added userid in the entity payment inti and transactionmaster --- .../billpaymentservice/bbps/dto/request/BaseClass.java | 3 +++ .../billpaymentservice/bbps/entites/PaymentInitiate.java | 6 ++++++ .../bbps/entites/TransactionMaster.java | 8 +++++++- .../bbps/serviceImpl/PaymentServiceImpl.java | 7 +++++++ src/main/resources/application-local.properties | 4 ++-- 5 files changed, 25 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java b/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java index 5c41339..05948e3 100644 --- a/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java +++ b/src/main/java/com/billpaymentservice/bbps/dto/request/BaseClass.java @@ -30,6 +30,9 @@ public abstract class BaseClass { @NotBlank(message = "Request ID cannot be null or blank") private String reqId; + @JsonProperty("userId") + private String clientUserId; + private DeviceDetail deviceDetial; // ✅ 10 User Defined Fields (UDF1–UDF10) private String udf1; diff --git a/src/main/java/com/billpaymentservice/bbps/entites/PaymentInitiate.java b/src/main/java/com/billpaymentservice/bbps/entites/PaymentInitiate.java index 61f92c8..b2e1a84 100644 --- a/src/main/java/com/billpaymentservice/bbps/entites/PaymentInitiate.java +++ b/src/main/java/com/billpaymentservice/bbps/entites/PaymentInitiate.java @@ -22,6 +22,12 @@ public class PaymentInitiate { @Column(name = "bank_txn_Id", nullable = false) private String bankTxnId; + + @Column(name = "client_user_id") + private String clientUserId; + + @Column(name = "mid") + private String mid; @Column(name = "txn_id") private String txnId; diff --git a/src/main/java/com/billpaymentservice/bbps/entites/TransactionMaster.java b/src/main/java/com/billpaymentservice/bbps/entites/TransactionMaster.java index da9f9ad..a484b75 100644 --- a/src/main/java/com/billpaymentservice/bbps/entites/TransactionMaster.java +++ b/src/main/java/com/billpaymentservice/bbps/entites/TransactionMaster.java @@ -35,6 +35,12 @@ public class TransactionMaster { // 👇 Apna internal transaction id, manually generate or system ke through @Column(name = "txn_id") private String txnId; + + @Column(name = "client_user_id") + private String clientUserId; + + @Column(name = "mid") + private String mid; @Column(name = "req_id") private String reqId; @@ -148,7 +154,7 @@ public class TransactionMaster { @Column(name = "plan_type") private String planType; - + @Column(name = "creation_date") private String creationDate; diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/PaymentServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/PaymentServiceImpl.java index ef43309..9489f0a 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/PaymentServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/PaymentServiceImpl.java @@ -142,6 +142,8 @@ public class PaymentServiceImpl implements PaymentService { PaymentInitiate paymentInitiate = new PaymentInitiate(); paymentInitiate.setTxnId(txnId); paymentInitiate.setReqId(requestId); + paymentInitiate.setMid(billPaymentRequest.getMid()); + paymentInitiate.setClientUserId(billPaymentRequest.getClientUserId()); paymentInitiate.setBankTxnId(billPaymentResponse.getTxnId()); paymentInitiate.setStatus(billPaymentResponse.getStatus()); paymentIntiateRepository.save(paymentInitiate); @@ -150,6 +152,9 @@ public class PaymentServiceImpl implements PaymentService { TransactionStatusRequest transactionStatusRequest = new TransactionStatusRequest(); transactionStatusRequest.setTxnId(billPaymentResponse.getTxnId()); transactionStatusRequest.setReqId(requestId); + transactionStatusRequest.setMid(billPaymentRequest.getMid()); + transactionStatusRequest.setClientUserId(billPaymentRequest.getClientUserId()); + try { Thread.sleep((long) BBPSConstant.PAYMENT_STATUS_DELAY_MS); @@ -213,6 +218,8 @@ public class PaymentServiceImpl implements PaymentService { TransactionMaster transactionMaster = modelMapper.map(responseWrapper.getTransactionDAO(), TransactionMaster.class); transactionMaster.setTxnId(txnId); transactionMaster.setReqId(transactionStatusRequest.getReqId()); + transactionMaster.setMid(transactionStatusRequest.getMid()); + transactionMaster.setClientUserId(transactionStatusRequest.getClientUserId()); EntityRelationshipUtil.linkTransactionMasterRelationships(transactionMaster); transactionMasterRepository.save(transactionMaster); LOGGER.info("TransactionMaster saved successfully for txnId={}", txnId); diff --git a/src/main/resources/application-local.properties b/src/main/resources/application-local.properties index aaf1e10..4eaafbc 100644 --- a/src/main/resources/application-local.properties +++ b/src/main/resources/application-local.properties @@ -20,9 +20,9 @@ swagger.server.description=Local Development Server # DataSource spring.datasource.url=jdbc:postgresql://localhost:5432/BBPS spring.datasource.username=postgres -spring.datasource.password=UAT@DB_2025 +#spring.datasource.password=UAT@DB_2025 -#spring.datasource.password=himanshu@123 +spring.datasource.password=himanshu@123 spring.datasource.driver-class-name=org.postgresql.Driver spring.datasource.type=com.zaxxer.hikari.HikariDataSource From 4d484774104b7f612db11fa8e4ebe75bb4e23de4 Mon Sep 17 00:00:00 2001 From: Mohd-Arham Date: Fri, 28 Nov 2025 11:11:44 +0530 Subject: [PATCH 6/6] arham khan --- .../bbps/serviceImpl/ComplainServiceImpl.java | 4 ++-- .../billpaymentservice/bbps/swagger/SwaggerConfig.java | 10 +++++++--- 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java b/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java index 5ae05b2..23b11d0 100644 --- a/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java +++ b/src/main/java/com/billpaymentservice/bbps/serviceImpl/ComplainServiceImpl.java @@ -118,8 +118,8 @@ public class ComplainServiceImpl implements ComplainService { Optional dataById = transactionMasterRepository.findById(complainRequestDTO.getTxnId()); if (dataById == null || dataById.isEmpty()) { - LOGGER.warn("Master Data By Id is null"); - throw new CustomException("Master Data is required", "FAILED", BBPSConstant.BADREQUEST, null); + LOGGER.warn("Txn Id is null"); + throw new CustomException("Txn Id is required", "FAILED", BBPSConstant.BADREQUEST, null); } TransactionMaster transData = dataById.get(); diff --git a/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java b/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java index 735eab2..7aec20f 100644 --- a/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java +++ b/src/main/java/com/billpaymentservice/bbps/swagger/SwaggerConfig.java @@ -1,5 +1,7 @@ package com.billpaymentservice.bbps.swagger; +import java.util.List; + import org.springframework.beans.factory.annotation.Value; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; @@ -9,6 +11,7 @@ import io.swagger.v3.oas.models.info.Contact; import io.swagger.v3.oas.models.info.Info; import io.swagger.v3.oas.models.security.SecurityRequirement; import io.swagger.v3.oas.models.security.SecurityScheme; +import io.swagger.v3.oas.models.servers.Server; @Configuration public class SwaggerConfig { @@ -25,9 +28,10 @@ public class SwaggerConfig { .components(new io.swagger.v3.oas.models.Components().addSecuritySchemes("Authentication", new SecurityScheme().name("Authentication").type(SecurityScheme.Type.APIKEY) .in(SecurityScheme.In.HEADER))) - .info(new Info().title("Spring Boot REST API").description("Spring Boot REST API for BBPS") - .version("1.0.0").contact(new Contact().name("Globots").url(serverUrl) - .email("info@merchantpanel.com"))); + .info(new Info().title("Spring Boot REST API").description("Spring Boot REST API for BBPS Project") + .version("1.0.0").contact(new Contact().email("info@merchantpanel.com"))) + .servers(List.of(new Server().url(serverUrl).description(serverDescription))); } + }