保誠-保戶業務員媒合平台
Jack
2021-11-26 bdcaac32492b5e6223fef4304f4d86403e877022
[UPDATE] 調整註冊和OTP登入的流程
修改8個檔案
237 ■■■■■ 已變更過的檔案
pamapi/src/main/java/com/pollex/pam/domain/Customer.java 8 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/repository/CustomerRepository.java 5 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/security/provider/OtpAuthenticationProvider.java 87 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/service/CustomerAuthService.java 44 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/service/CustomerService.java 11 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/service/OtpTmpService.java 2 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/web/rest/OtpResource.java 64 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/web/rest/vm/OtpAccount.java 16 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
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);
    }
}