pamapi/src/main/java/com/pollex/pam/domain/Customer.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
pamapi/src/main/java/com/pollex/pam/repository/CustomerRepository.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
pamapi/src/main/java/com/pollex/pam/security/provider/OtpAuthenticationProvider.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
pamapi/src/main/java/com/pollex/pam/service/CustomerAuthService.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
pamapi/src/main/java/com/pollex/pam/service/CustomerService.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
pamapi/src/main/java/com/pollex/pam/service/OtpTmpService.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
pamapi/src/main/java/com/pollex/pam/web/rest/OtpResource.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 | |
pamapi/src/main/java/com/pollex/pam/web/rest/vm/OtpAccount.java | ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程 |
pamapi/src/main/java/com/pollex/pam/domain/Customer.java
@@ -2,6 +2,7 @@ import java.io.Serializable; import java.time.Instant; import java.util.Optional; import javax.persistence.Column; import javax.persistence.Entity; @@ -14,6 +15,7 @@ import org.springframework.data.annotation.CreatedDate; import org.springframework.data.annotation.LastModifiedDate; import org.springframework.util.StringUtils; import com.fasterxml.jackson.annotation.JsonIgnore; import com.pollex.pam.enums.OtpLoginTypeEnum; @@ -111,6 +113,10 @@ this.contactType = contactType; } public String toAccountString() { return Optional.ofNullable(getPhone()) .filter(StringUtils::hasText) .orElseGet(this::getEmail); } } pamapi/src/main/java/com/pollex/pam/repository/CustomerRepository.java
@@ -10,5 +10,10 @@ @Repository public interface CustomerRepository extends JpaRepository<Customer, Long>{ default Optional<Customer> findOneByEmailEqualsOrPhoneEquals(String emailOrEmail) { return this.findOneByEmailEqualsOrPhoneEquals(emailOrEmail, emailOrEmail); } Optional<Customer> findOneByEmailEqualsOrPhoneEquals(String email, String phone); } pamapi/src/main/java/com/pollex/pam/security/provider/OtpAuthenticationProvider.java
@@ -1,33 +1,22 @@ package com.pollex.pam.security.provider; import com.pollex.pam.config.ApplicationProperties; import com.pollex.pam.domain.Customer; import com.pollex.pam.domain.OtpTmp; import com.pollex.pam.enums.CustomerDetailEnum; import com.pollex.pam.enums.OtpLoginTypeEnum; import com.pollex.pam.enums.OtpTmpStatusEnum; import com.pollex.pam.repository.CustomerRepository; import com.pollex.pam.security.token.OtpAuthenticationToken; import com.pollex.pam.service.OtpTmpService; import com.pollex.pam.service.OtpWebService; import com.pollex.pam.service.dto.OtpResponseDTO; import com.pollex.pam.web.rest.vm.OtpAccount; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.core.Authentication; import org.springframework.security.core.AuthenticationException; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Component; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import com.pollex.pam.domain.Customer; import com.pollex.pam.domain.OtpTmp; import com.pollex.pam.enums.OtpTmpStatusEnum; import com.pollex.pam.repository.CustomerRepository; import com.pollex.pam.security.token.OtpAuthenticationToken; import com.pollex.pam.service.CustomerAuthService; import com.pollex.pam.service.OtpTmpService; import com.pollex.pam.service.OtpUtilService; import com.pollex.pam.web.rest.vm.OtpAccount; @Component public class OtpAuthenticationProvider { @@ -35,16 +24,16 @@ private static final Logger log = LoggerFactory.getLogger(OtpAuthenticationProvider.class); @Autowired ApplicationProperties applicationProperty; @Autowired OtpWebService otpWebService; CustomerAuthService customerAuthService; @Autowired CustomerRepository customerRepository; @Autowired OtpTmpService otpTmpService; @Autowired OtpUtilService otpUtilService; public Authentication authenticate(OtpAuthenticationToken otpAuthenticationToken) throws AuthenticationException { OtpAccount otpAccount = otpAuthenticationToken.getPrincipal(); @@ -52,23 +41,19 @@ String indexKey = otpAccount.getIndexKey(); String otpCode = otpAuthenticationToken.getCredentials(); if(applicationProperty.isMockLogin()){ setVerrifiedOtpTmp(account, indexKey); return getCustomerToken(account, otpCode, indexKey); } otpUtilService.verifyOtp(indexKey, otpCode); setVerrifiedOtpTmp(account, indexKey); Customer customer = customerRepository.findOneByEmailEqualsOrPhoneEquals(account) .orElse(null); if (customer == null) { throw new AuthenticationCredentialsNotFoundException(""); } return customerAuthService.buildCustomerAuthToken(customer, otpCode, indexKey); try { OtpResponseDTO otpResponseDTO = otpWebService.verifyOTP(indexKey, otpCode); if(otpResponseDTO.isSuccess()) { setVerrifiedOtpTmp(account, indexKey); return getCustomerToken(account, otpCode, indexKey); } } catch (Exception e) { log.error("Exception: ", e); throw new AuthenticationCredentialsNotFoundException(""); } throw new AuthenticationCredentialsNotFoundException(""); } private void setVerrifiedOtpTmp(String account, String indexKey) { @@ -77,23 +62,5 @@ otpTmpService.save(otpTmp); } private UsernamePasswordAuthenticationToken getCustomerToken(String account , String otpCode, String indexKey) { // todo 未存在於DB所屬正常現象,需用特殊message告知前端可進行註冊 Customer customer = customerRepository.findOneByEmailEqualsOrPhoneEquals(account, account).orElseThrow(() -> new UsernameNotFoundException("this customer is not in register, account = " + account)); List<GrantedAuthority> grantedAuths = Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(account, otpCode, grantedAuths); Map<String, String> details = new HashMap<>(); details.put(CustomerDetailEnum.ID.getValue(), customer.getId().toString()); details.put(CustomerDetailEnum.NAME.getValue(), customer.getName()); details.put(CustomerDetailEnum.ACCOUNT.getValue(), account); // details.put(CustomerDetailEnum.CONTACT_TYPE.getValue(), customer.getContactType()); authenticationToken.setDetails(details); return authenticationToken; } } pamapi/src/main/java/com/pollex/pam/service/CustomerAuthService.java
@@ -1,34 +1,70 @@ package com.pollex.pam.service; import java.util.Arrays; import java.util.HashMap; import java.util.List; import java.util.Map; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.Authentication; import org.springframework.security.core.GrantedAuthority; import org.springframework.security.core.authority.SimpleGrantedAuthority; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.pollex.pam.domain.Customer; import com.pollex.pam.enums.CustomerDetailEnum; import com.pollex.pam.repository.CustomerRepository; import com.pollex.pam.security.jwt.TokenProvider; import com.pollex.pam.security.token.OtpAuthenticationToken; import com.pollex.pam.web.rest.vm.OtpAccount; @Service @Transactional public class CustomerAuthService { @Autowired AuthenticationManagerBuilder authenticationManagerBuilder; @Autowired CustomerRepository customerRepository; @Autowired TokenProvider tokenProvider; public String authorize(String account, String indexKey, String otpCode) { OtpAccount otpAccount = new OtpAccount(account, indexKey); public String authorize(Customer account, String indexKey, String otpCode) { OtpAccount otpAccount = OtpAccount.createOtpAccount(account, indexKey); OtpAuthenticationToken authenticationToken = new OtpAuthenticationToken( otpAccount, otpCode ); Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken); SecurityContextHolder.getContext().setAuthentication(authenticationToken); Authentication authentication = buildCustomerAuthToken(account, otpCode, indexKey); String jwt = tokenProvider.createToken(authentication, false); return jwt; } public UsernamePasswordAuthenticationToken buildCustomerAuthToken(Customer customer , String otpCode, String indexKey) { List<GrantedAuthority> grantedAuths = Arrays.asList(new SimpleGrantedAuthority("ROLE_USER")); final String account = customer.toAccountString(); UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(account, otpCode, grantedAuths); Map<String, String> details = new HashMap<>(); details.put(CustomerDetailEnum.ID.getValue(), customer.getId().toString()); details.put(CustomerDetailEnum.NAME.getValue(), customer.getName()); details.put(CustomerDetailEnum.ACCOUNT.getValue(), account); // details.put(CustomerDetailEnum.CONTACT_TYPE.getValue(), customer.getContactType()); authenticationToken.setDetails(details); return authenticationToken; } } pamapi/src/main/java/com/pollex/pam/service/CustomerService.java
@@ -5,6 +5,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.security.core.userdetails.UsernameNotFoundException; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.pollex.pam.domain.Customer; import com.pollex.pam.domain.OtpTmp; @@ -15,6 +16,7 @@ import com.pollex.pam.service.mapper.CustomerDTOMapper; @Service @Transactional public class CustomerService { @Autowired @@ -33,7 +35,7 @@ return customerRepository.save(customer); } public String registerCustomer(CustomerRegisterDTO registDTO) { public Customer registerCustomer(CustomerRegisterDTO registDTO) { boolean isCustomerExist = checkCustomerExist(registDTO); if(isCustomerExist) { throw new UsernameAlreadyUsedException(); @@ -45,10 +47,11 @@ if(otpTmp.getStatus() == OtpTmpStatusEnum.VERRIFIED) { Customer customer = customerDTOMapper.toCustomer(registDTO); save(customer); String jwt = customerAuthService.authorize(account, registDTO.getIndexKey(), registDTO.getOtpCode()); return jwt; return customer; }else { throw new UsernameNotFoundException("Otp record not found"); throw new IllegalArgumentException("Invalid indexKey state error. IndexKey: " + registDTO.getIndexKey() + " => status: " + otpTmp.getStatus()); } } pamapi/src/main/java/com/pollex/pam/service/OtpTmpService.java
@@ -2,6 +2,7 @@ import org.springframework.beans.factory.annotation.Autowired; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import com.pollex.pam.domain.OtpTmp; import com.pollex.pam.enums.OtpLoginTypeEnum; @@ -9,6 +10,7 @@ import com.pollex.pam.repository.OtpTmpRepository; @Service @Transactional public class OtpTmpService { @Autowired pamapi/src/main/java/com/pollex/pam/web/rest/OtpResource.java
@@ -1,17 +1,8 @@ package com.pollex.pam.web.rest; import com.pollex.pam.config.ApplicationProperties; import com.pollex.pam.enums.OtpLoginTypeEnum; import com.pollex.pam.security.jwt.JWTFilter; import com.pollex.pam.security.jwt.TokenProvider; import com.pollex.pam.security.token.OtpAuthenticationToken; import com.pollex.pam.service.CustomerAuthService; import com.pollex.pam.service.CustomerService; import com.pollex.pam.service.OtpTmpService; import com.pollex.pam.service.OtpWebService; import com.pollex.pam.service.dto.CustomerRegisterDTO; import com.pollex.pam.service.dto.OtpResponseDTO; import com.pollex.pam.web.rest.vm.*; import java.util.Arrays; import java.util.UUID; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import org.springframework.beans.factory.annotation.Autowired; @@ -19,14 +10,26 @@ import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder; import org.springframework.security.core.Authentication; import org.springframework.security.core.context.SecurityContextHolder; import org.springframework.web.bind.annotation.*; 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 javax.xml.rpc.ServiceException; import java.rmi.RemoteException; import java.util.Arrays; import java.util.UUID; import com.pollex.pam.config.ApplicationProperties; import com.pollex.pam.domain.Customer; import com.pollex.pam.enums.OtpLoginTypeEnum; import com.pollex.pam.repository.CustomerRepository; import com.pollex.pam.security.jwt.JWTFilter; import com.pollex.pam.security.jwt.TokenProvider; import com.pollex.pam.service.CustomerAuthService; import com.pollex.pam.service.CustomerService; import com.pollex.pam.service.OtpTmpService; import com.pollex.pam.service.OtpUtilService; import com.pollex.pam.service.OtpWebService; import com.pollex.pam.service.dto.CustomerRegisterDTO; import com.pollex.pam.service.dto.OtpResponseDTO; import com.pollex.pam.web.rest.vm.OtpLoginVM; import com.pollex.pam.web.rest.vm.VerifyOtpVM; @RestController @RequestMapping("/api/otp") @@ -54,6 +57,12 @@ @Autowired CustomerService customerService; @Autowired OtpUtilService otpUtilService; @Autowired CustomerRepository customerRepository; @PostMapping("/sendOtp") public ResponseEntity<Object> sendOtp(@RequestBody OtpLoginVM login) { @@ -74,7 +83,17 @@ @PostMapping("/verify") public ResponseEntity<UserJWTController.JWTToken> verifyOtp(@RequestBody VerifyOtpVM verifyOtpParam) { String jwt = customerAuthService.authorize(verifyOtpParam.getAccount(), verifyOtpParam.getIndexKey(), verifyOtpParam.getOtpCode()); otpUtilService.verifyOtp(verifyOtpParam.getIndexKey(), verifyOtpParam.getOtpCode()); Customer customer = customerRepository .findOneByEmailEqualsOrPhoneEquals(verifyOtpParam.getAccount()) .orElse(null); if (customer == null) { return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build(); } String jwt = customerAuthService.authorize(customer, verifyOtpParam.getIndexKey(), verifyOtpParam.getOtpCode()); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer" + jwt); return new ResponseEntity<>(new UserJWTController.JWTToken(jwt), httpHeaders, HttpStatus.OK); @@ -87,9 +106,12 @@ @PostMapping("/register") public ResponseEntity<UserJWTController.JWTToken> registerAccount(@RequestBody CustomerRegisterDTO registDTO) { String jwt = customerService.registerCustomer(registDTO); Customer account = customerService.registerCustomer(registDTO); String jwt = customerAuthService.authorize(account, registDTO.getIndexKey(), registDTO.getOtpCode()); HttpHeaders httpHeaders = new HttpHeaders(); httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer" + jwt); return new ResponseEntity<>(new UserJWTController.JWTToken(jwt), httpHeaders, HttpStatus.OK); } } pamapi/src/main/java/com/pollex/pam/web/rest/vm/OtpAccount.java
@@ -1,5 +1,13 @@ package com.pollex.pam.web.rest.vm; import java.util.Optional; import org.apache.http.util.Asserts; import org.springframework.util.Assert; import org.springframework.util.StringUtils; import com.pollex.pam.domain.Customer; public class OtpAccount { private String account; private String indexKey; @@ -24,4 +32,12 @@ public void setIndexKey(String indexKey) { this.indexKey = indexKey; } public static OtpAccount createOtpAccount(Customer customerAcct, String indexKey) { String acct = customerAcct.toAccountString(); Assert.hasText(acct, "Customer phone or email must not null"); return new OtpAccount(acct, indexKey); } }