保誠-保戶業務員媒合平台
Jack
2021-11-23 6e64ed2a204dc2679579d118602067382e6ebec6
Merge branch 'master' of ssh://192.168.0.10:29418/pcalife/PAM
修改12個檔案
新增3個檔案
374 ■■■■■ 已變更過的檔案
PAMapp/assets/scss/vendors/_elementUI.scss 1 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/scss/vendors/elementUI/_messageBox.scss 28 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/api/consultant.ts 15 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/api/share.ts 46 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/models/ConsultantLoginInfo.ts 5 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/ts/models/enum/Role.ts 5 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/BackActionBar.vue 7 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/components/NavBar.vue 15 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/consultantLogin/index.vue 100 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/pages/login/index.vue 34 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/store/localStorage.ts 4 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/security/provider/EServiceAuthenticationProvider.java 16 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/java/com/pollex/pam/web/rest/TestLoginResource.java 75 ●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/resources/config/application-sit.yml 2 ●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
pamapi/src/main/resources/logback-spring.xml 21 ●●●●● 修補檔 | 檢視 | 原始 | 究查 | 歷程
PAMapp/assets/scss/vendors/_elementUI.scss
@@ -10,3 +10,4 @@
@import './elementUI/tag';
@import './elementUI/pagination';
@import './elementUI/dialog';
@import './elementUI/messageBox';
PAMapp/assets/scss/vendors/elementUI/_messageBox.scss
¤ñ¹ï·sÀÉ®×
@@ -0,0 +1,28 @@
.el-message-box__wrapper{
    display: flex;
    align-items: center;
    justify-content: center;
    .pam-message-box.el-message-box{
        display: flex;
        flex-direction: column;
        justify-content: space-between;
        width:300px;
        height: 150px;
        .el-message-box__content{
            padding: 15px;
            .el-message-box__message p{
                text-align: center;
                color: $PRIMARY_BLACK;
                letter-spacing: 2px;
                font-size: 20px;
            }
        }
        .el-message-box__btns{
            text-align: center;
        }
        .el-button.el-button--primary{
            color: $PRIMARY_WHITE;
        }
    }
}
PAMapp/assets/ts/api/consultant.ts
@@ -1,6 +1,7 @@
import { service } from '~/assets/ts/api/share';
import { AxiosResponse } from 'axios';
import { AppointmentDetail } from '../models/AppointmentDetail';
import { ConsultantLoginInfo } from '../models/ConsultantLoginInfo';
// é¡§å®¢ç™»å…¥(TODO: OTP認證開發前 æš«æ™‚使用)
export function login(user: any) {
@@ -76,13 +77,8 @@
}
// é¡§å•ç™»å…¥
export function logInToConsultant(consultantDto:ConsultantLoginInfo):Promise<boolean>{
    console.log('consultantDto',consultantDto);
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            resolve(true);
        },1000)
    })
export function logInToConsultant(consultantDto:ConsultantLoginInfo):Promise<AxiosResponse<RequestOfLoginSuccess>>{
    return service.post('/eService/authenticate',consultantDto);
}
// å–得預約單細節
@@ -91,11 +87,6 @@
        Authorization: 'Bearer ' + localStorage.getItem('id_token')
    }
    return service.get('/appointment/getDetail/'+apointmentId, {headers})
}
export interface ConsultantLoginInfo{
    account:string,
    password:string,
    verificationCode:string,
}
export interface Consultants {
    agentNo: string,
PAMapp/assets/ts/api/share.ts
@@ -1,31 +1,47 @@
import axios from 'axios';
import { AxiosRequestConfig, AxiosError, AxiosResponse } from 'axios';
import { AxiosRequestConfig, AxiosError, AxiosResponse } from 'axios';
import { MessageBox } from 'element-ui';
export const service = axios.create({
    baseURL: process.env.BASE_URL
})
service.interceptors.request.use(function (config: AxiosRequestConfig) {
  loadingStart();
service.interceptors.request.use(
  (config:AxiosRequestConfig)=>{
    loadingStart();
    return config;
}, function (error: AxiosError) {
  loadingFinish();
    return Promise.reject(error);
});
  }
);
service.interceptors.response.use(function (response: AxiosResponse) {
  loadingFinish();
    return response;
}, function (error: AxiosError) {
  loadingFinish();
service.interceptors.response.use(
  (response:AxiosResponse)=>{
    loadingFinish();
    return response;  // maybe can use response.data
  },
  (error:AxiosError)=>{
    loadingFinish();
    openErrorMessage();
    return Promise.reject(error);
});
  }
);
function loadingStart(): void {
  setTimeout(() => {
    window.$nuxt.$loading.start();
  });
}
function loadingFinish(): void {
    window.$nuxt.$loading.finish();
}
function openErrorMessage():void{
  MessageBox({
    message: '系統發生錯誤',
    showClose:false,
    showConfirmButton:true,
    confirmButtonText:'確認',
    customClass:'pam-message-box',
    closeOnClickModal:false,
  });
}
PAMapp/assets/ts/models/ConsultantLoginInfo.ts
¤ñ¹ï·sÀÉ®×
@@ -0,0 +1,5 @@
export interface ConsultantLoginInfo {
    username: string;
    password: string;
    verificationCode: string;
}
PAMapp/assets/ts/models/enum/Role.ts
¤ñ¹ï·sÀÉ®×
@@ -0,0 +1,5 @@
export enum Role{
    ADMIN = 'admin',
    USER = 'user',
    NOT_LOGIN = ''
}
PAMapp/components/BackActionBar.vue
@@ -9,12 +9,13 @@
<script lang="ts">
import { namespace } from 'nuxt-property-decorator';
import { Vue, Component,} from 'vue-property-decorator';
import { Role } from '~/assets/ts/models/enum/Role';
import * as _ from 'lodash';
import { Role } from './NavBar.vue';
const localStorage = namespace('localStorage');
const roleStorage = namespace('localStorage');
@Component
export default class UiCarousel extends Vue {
  @localStorage.Getter currentRole!:string;
  @roleStorage.Getter currentRole!:string;
  get label(): string {
    if (this.$route.name) {
      const routeName = this.$route.name.split('-')[0];
PAMapp/components/NavBar.vue
@@ -34,13 +34,15 @@
<script lang="ts">
  import { Vue, Component } from 'vue-property-decorator';
  import { namespace } from 'nuxt-property-decorator';
  import { Role } from '~/assets/ts/models/enum/Role';
  import * as _ from 'lodash';
  const localStorage = namespace('localStorage');
  const roleStorage = namespace('localStorage');
  @Component
  export default class NavBar extends Vue {
    @localStorage.Mutation storageClear!: () => void;
    @localStorage.Getter idToken!: string | null;
    @localStorage.Getter currentRole!: string | null;
    @roleStorage.Mutation storageClear!: () => void;
    @roleStorage.Getter idToken!: string | null;
    @roleStorage.Getter currentRole!: string | null;
    navBarList = [{
        authorityOfRoleList: [Role.NOT_LOGIN],
@@ -99,11 +101,6 @@
      this.storageClear();
      _.isEqual(this.$route.name, 'index') ? location.reload() : this.$router.push('/');
    }
  }
  export enum Role {
    USER = 'user',
    ADMIN = 'admin',
    NOT_LOGIN = '',
  }
</script>
PAMapp/pages/consultantLogin/index.vue
@@ -6,11 +6,11 @@
        <div class="pam-consultant-login__title">帳號</div>
        <div class="position-r mt-10">
          <input type="text"
            v-model="consultantDto.account"
            v-model="consultantDto.username"
            class="pam-consultant-login__input"
            placeholder="輸入eService帳號">
          <div class="pam-consultant-login__inputIcon text--primary cursor--pointer"
            @click="recordAccount">
          <div class="pam-consultant-login__inputIcon text--primary cursor--pointer fix-chrome-click--issue"
            @click="isRemember = !isRemember">
            <i :class="[isRemember ? 'icon-checkbox-1' : 'icon-checkbox','pr-5']"></i>
            è¨˜ä½
          </div>
@@ -19,7 +19,7 @@
      <div class="pam-paragraph">
        <div class="pam-consultant-login__title ">
          <div>密碼</div>
          <a class="pam-consultant-login__forgot-password cursor--pointer"
          <a class="pam-consultant-login__forgot-password cursor--pointer fix-chrome-click--issue"
            :href="forgotPasswordLink" 
            target="_blank" 
            rel="保誠人壽">
@@ -31,16 +31,16 @@
            v-model="consultantDto.password"
            class="pam-consultant-login__input"
            placeholder="輸入eService密碼">
          <div class="pam-consultant-login__inputIcon cursor--pointer"
          <div class="pam-consultant-login__inputIcon cursor--pointer fix-chrome-click--issue"
            @click="isShowPassword = !isShowPassword">
            <i :class="[isShowPassword ? 'icon-eye-1 fs-25' : 'icon-eye' , 'text--primary']"></i>
            <i :class="[isShowPassword ? 'icon-eye':'icon-eye-1 fs-25', 'text--primary']"></i>
          </div>
        </div>
      </div>
      <div class="pam-paragraph">
        <div class="pam-consultant-login__title">
          <div>驗證碼</div>
          <div class="text--dark-blue fs-16 cursor--pointer"
          <div class="text--dark-blue fs-16 cursor--pointer fix-chrome-click--issue"
            @click="regenerateCode">重新產生</div>
        </div>
        <div class="pam-consultant-login__verifyBlock mt-10">
@@ -50,13 +50,14 @@
              class="pam-consultant-login__input">
          </div>
          <div class="pam-consultant-login__verifyImg">
            <img src="~/assets/images/logo.png" alt="驗證碼">
            <img src="~/assets/images/logo.png"
              alt="驗證碼">
          </div>
        </div>
      </div>
      <div class="pam-consultant-login__confirmBlock pam-paragraph">
        <button class="pam-consultant-login__confirm cursor--pointer"
          @click="fakeLogin">送出</button>
        <button class="pam-consultant-login__confirm cursor--pointer fix-chrome-click--issue"
          @click="loginWithConsultant">送出</button>
      </div>
    </div>
  </div>
@@ -64,70 +65,73 @@
<script lang="ts">
  import { namespace } from 'nuxt-property-decorator';
  import { Vue, Component} from 'vue-property-decorator';
  import { getForgotPasswordLink , getVerificationCodeImg , login } from '~/assets/ts/api/consultant';
  import { Role } from '../../components/NavBar.vue';
  import { Role } from '~/assets/ts/models/enum/Role';
  import { Vue, Component } from 'vue-property-decorator';
  import { getForgotPasswordLink, getVerificationCodeImg, logInToConsultant } from '~/assets/ts/api/consultant';
  const localStorage = namespace('localStorage');
  const roleStorage = namespace('localStorage');
  @Component({
    layout: 'home'
  })
  export default class ConsultantLogin extends Vue {
    @localStorage.Mutation storageIdToken!: (token:string) => void;
    @localStorage.Mutation storageRole!: (role:string) => void;
    @roleStorage.Mutation storageIdToken!: (token: string) => void;
    @roleStorage.Mutation storageRole!: (role: string) => void;
    isRemember = false;
    isShowPassword = false;
    forgotPasswordLink = ''; // å°šæœª
    imgOfVerificationCode = ''; // å°šæœª
    consultantDto = {
      account: '',
      username: '',
      password: '',
      verificationCode: '',
    }
    forgotPasswordLink = '';
    imgOfVerificationCode='';
    mounted() {
      this.getRememberUserName();
      this.regenerateCode();
      this.getLinkOfForgotPassword();
    };
    private getLinkOfForgotPassword():void{
      getForgotPasswordLink().then(link=>{
        console.log('link',link);
    private getRememberUserName(): void {
      const username = localStorage.getItem('consultantUserName')
      if (username) {
        this.consultantDto.username = username;
        this.isRemember = true;
      }
    }
    private getLinkOfForgotPassword(): void {
      getForgotPasswordLink().then(link => {
        this.forgotPasswordLink = link;
      });
    };
    recordAccount(): void {
      this.isRemember = !this.isRemember;
      if (this.isRemember) {
        console.log('sotre account');
      }
    };
    regenerateCode(): void {
      getVerificationCodeImg().then((imgOfbase64:any)=>{
    public regenerateCode(): void {
      getVerificationCodeImg().then(imgOfbase64 => {
        this.imgOfVerificationCode = imgOfbase64;
      });
    };
    // loginWithConsultant():void{
    //   console.log('consultantDto',this.consultantDto);
    //   logInToConsultant(this.consultantDto).then(res=>{
    //     localStorage.setItem('roleOfState',Role.CONSULTANT);
    //     this.$router.push('/myAppointmentList/appointmentList');
    //   });
    // }
    fakeLogin(): void {
        const user = {
            username: 'admin',
            password: 'admin'
        }
        login(user).then((res) => {
    public loginWithConsultant(): void {
      this.recordAccount();
      logInToConsultant(this.consultantDto).then(res => {
            this.storageIdToken(res.data.id_token);
            this.storageRole(Role.ADMIN);
            this.$router.push('/myAppointmentList/appointmentList');
        })
      }, (error) => {
        this.consultantDto.password = '';
        this.consultantDto.verificationCode = '';
      });
    }
    private recordAccount(): void {
      localStorage.setItem('consultantUserName', this.isRemember ? this.consultantDto.username : '');
    };
  };
</script>
<style lang="scss"
  scoped>
  .mt-20 {
@@ -187,11 +191,13 @@
        right: 15px;
      }
    }
    &__forgot-password{
    &__forgot-password {
        color: $PRIMARY_RED;
        text-decoration:none;
      text-decoration: none;
        font-size: 16px; 
    }
    &__verifyBlock {
      display: flex;
      justify-content: space-between;
@@ -201,7 +207,7 @@
      width: 126px;
      border: 1px black solid;
      height: 50px;
      img{
      img {
        width: 100%;
        height: 100%;
      }
PAMapp/pages/login/index.vue
@@ -4,7 +4,7 @@
      <div class="pam-paragraph">
        <div class="mdTxt">
        ç¶å®šæ–¹å¼
        é©—證方式<small class="pam-field-title__hint pl-10">(顧問會以您指定的方式與您聯繫)</small>
        </div>
        <div class="pam-tags">
          <el-row type="flex" class="pt-10">
@@ -15,7 +15,6 @@
              :class="{ 'active': connectDevice === 'EMAIL'}"
              @click="connectDevice = 'EMAIL'">Email</el-button>
          </el-row>
        </div>
          <el-row type="flex" class="pt-10" v-show="connectDevice === 'MOBILE'">
@@ -213,7 +212,20 @@
        </span>
      </el-dialog>
      <PopUpFrame class="pam-popUpFrame"
        :isOpen.sync="applySuccessConfirmVisable">
          <div class="pam-popUp-title text--center">
            æ­¡è¿Žæ‚¨ç™»å…¥æˆåŠŸï¼Œå¦‚æ‚¨é ç´„è«®è©¢ï¼Œé¡§å•æœƒä»¥æ‚¨ç•™ä¸‹çš„{{ connectDevice === 'MOBILE' ? '手機號碼' : 'Email'}}與您聯繫
          </div>
          <div class="pam-popUp-confirm-bolck pam-paragraph">
            <div class="text--center">
              <el-button
                  type="primary"
                  @click="confirmApplySuccess"
              >我知道了</el-button>
            </div>
          </div>
      </PopUpFrame>
      <el-button class="mt-30" @click="fakeLogin">客戶登入</el-button>
    </div>
@@ -223,12 +235,14 @@
import { namespace } from 'nuxt-property-decorator';
import { Vue, Component } from 'vue-property-decorator';
import { login } from '~/assets/ts/api/consultant';
import { Role } from '../../components/NavBar.vue';
const localStorage = namespace('localStorage');
import { Role } from '~/assets/ts/models/enum/Role';
const roleStorage = namespace('localStorage');
@Component
export default class Login extends Vue {
  @localStorage.Mutation storageIdToken!: (token:string) => void;
  @localStorage.Mutation storageRole!: (role:string) => void;
  @roleStorage.Mutation storageIdToken!: (token:string) => void;
  @roleStorage.Mutation storageRole!: (role:string) => void;
  connectDevice: 'MOBILE' | 'EMAIL' = 'MOBILE';
@@ -242,6 +256,7 @@
  emailResendCounter = 30;
  registerDialogVisable = false;
  applySuccessConfirmVisable = false;
  name = '';
  agreeControct = false;
  isReadContract = false;
@@ -263,9 +278,14 @@
  };
  applyAccount(): void {
    this.applySuccessConfirmVisable = true;
    console.log('apply new account!')
  };
  confirmApplySuccess(): void {
    this.applySuccessConfirmVisable = false
  }
  // TODO: åƒ…OTP認證開發前 æš«æ™‚使用
   fakeLogin() {
        const user = {
PAMapp/store/localStorage.ts
@@ -2,8 +2,8 @@
@Module
export default class LocalStorage extends VuexModule {
  id_token:string|null = null;
  role_State:string|null = null;
  id_token = localStorage.getItem('id_token');
  role_State= localStorage.getItem('current_role');
  get idToken(): string|null {
    return this.id_token;
pamapi/src/main/java/com/pollex/pam/security/provider/EServiceAuthenticationProvider.java
@@ -17,6 +17,8 @@
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
import org.springframework.security.authentication.AuthenticationCredentialsNotFoundException;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.Authentication;
@@ -32,10 +34,7 @@
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.*;
@Component
public class EServiceAuthenticationProvider {
@@ -98,6 +97,7 @@
        String dtoJson = new ObjectMapper().writeValueAsString(dto);
        RestTemplate restTemplate = getTrustAllRestTemplate();
        settingMessageConvertesToSpecifyType(restTemplate, MediaType.ALL);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
@@ -120,4 +120,12 @@
        requestFactory.setReadTimeout(300000);
        return new RestTemplate(requestFactory);
    }
    private void settingMessageConvertesToSpecifyType(RestTemplate restTemplate, MediaType mediaType) {
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(Collections.singletonList(mediaType));
        messageConverters.add(converter);
        restTemplate.setMessageConverters(messageConverters);
    }
}
pamapi/src/main/java/com/pollex/pam/web/rest/TestLoginResource.java
@@ -1,5 +1,6 @@
package com.pollex.pam.web.rest;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.pollex.pam.config.ApplicationProperties;
import com.pollex.pam.security.jwt.JWTFilter;
import com.pollex.pam.security.jwt.TokenProvider;
@@ -7,22 +8,39 @@
import com.pollex.pam.security.token.OtpAuthenticationToken;
import com.pollex.pam.service.LoginService;
import com.pollex.pam.service.OtpWebService;
import com.pollex.pam.service.dto.EServiceRequest;
import com.pollex.pam.service.dto.EServiceResponse;
import com.pollex.pam.service.dto.OtpResponseDTO;
import com.pollex.pam.web.rest.vm.OtpAccount;
import org.apache.http.conn.ssl.NoopHostnameVerifier;
import org.apache.http.conn.ssl.SSLConnectionSocketFactory;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.ssl.SSLContexts;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.http.*;
import org.springframework.http.client.HttpComponentsClientHttpRequestFactory;
import org.springframework.http.converter.HttpMessageConverter;
import org.springframework.http.converter.json.MappingJackson2HttpMessageConverter;
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.client.RestTemplate;
import tw.com.softleader.otp.ws.OtpWebServicePortBindingStub;
import javax.net.ssl.SSLContext;
import javax.xml.rpc.ServiceException;
import java.rmi.RemoteException;
import java.security.KeyManagementException;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.cert.X509Certificate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
// todo,僅為初期接login方便使用而用get的方式登入,目前已拆出OtpResource與EServiceResource,主要是用這兩個做登入
@@ -73,17 +91,46 @@
    }
    @GetMapping("/byEService")
    public ResponseEntity<UserJWTController.JWTToken> loginByEService(@RequestParam("account") String account, @RequestParam("password") String password) throws Exception {
        EServiceAuthenticationToken authenticationToken = new EServiceAuthenticationToken(
            account,
            password
        );
    public ResponseEntity<EServiceResponse> loginByEService(@RequestParam("account") String account, @RequestParam("password") String password) throws Exception {
        EServiceRequest dto = new EServiceRequest();
        dto.setFunc("ValidateUserLogin");
        dto.setId(account);
        dto.setPin(password);
        dto.setPwd(password);
        dto.setSys("epos");
        Authentication authentication = authenticationManagerBuilder.getObject().authenticate(authenticationToken);
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        String jwt = tokenProvider.createToken(authentication, false);
        HttpHeaders httpHeaders = new HttpHeaders();
        httpHeaders.add(JWTFilter.AUTHORIZATION_HEADER, "Bearer" + jwt);
        return new ResponseEntity<>(new UserJWTController.JWTToken(jwt), httpHeaders, HttpStatus.OK);
        String dtoJson = new ObjectMapper().writeValueAsString(dto);
        RestTemplate restTemplate = getTrustAllRestTemplate();
        settingMessageConvertesToSpecifyType(restTemplate, MediaType.ALL);
        HttpHeaders headers = new HttpHeaders();
        headers.setContentType(MediaType.APPLICATION_JSON);
        HttpEntity<String> entity = new HttpEntity<>(dtoJson, headers);
        return restTemplate.exchange(applicationProperty.geteServiceLoginUrl(), HttpMethod.POST, entity, EServiceResponse.class);
    }
    private void settingMessageConvertesToSpecifyType(RestTemplate restTemplate, MediaType mediaType) {
        List<HttpMessageConverter<?>> messageConverters = new ArrayList<>();
        MappingJackson2HttpMessageConverter converter = new MappingJackson2HttpMessageConverter();
        converter.setSupportedMediaTypes(Collections.singletonList(mediaType));
        messageConverters.add(converter);
        restTemplate.setMessageConverters(messageConverters);
    }
    private RestTemplate getTrustAllRestTemplate() throws KeyStoreException, NoSuchAlgorithmException, KeyManagementException {
        SSLContext sslContext = SSLContexts.custom()
            .loadTrustMaterial(null, (X509Certificate[] x509Certs, String s) -> true)
            .build();
        SSLConnectionSocketFactory csf = new SSLConnectionSocketFactory(sslContext, new NoopHostnameVerifier());
        CloseableHttpClient httpClient = HttpClients.custom()
            .setSSLSocketFactory(csf)
            .build();
        HttpComponentsClientHttpRequestFactory requestFactory = new HttpComponentsClientHttpRequestFactory();
        requestFactory.setHttpClient(httpClient);
        requestFactory.setConnectTimeout(300000);
        requestFactory.setReadTimeout(300000);
        return new RestTemplate(requestFactory);
    }
}
pamapi/src/main/resources/config/application-sit.yml
@@ -115,4 +115,4 @@
  otp-web-service-url: https://vtwlifeopensyssit.pru.intranet.asia:443/pcalife-otp/ws/otpWebService
  otp-web-service-password: es20!%Pass
  otp-web-service-system-type: epos
  e-service-login-url: https://ssotwsit.eservice.pcalife.com.tw/sso/acctValidate
  e-service-login-url: https://eserviceuat.pcalife.com.tw/sso/chatbotValidate
pamapi/src/main/resources/logback-spring.xml
@@ -4,6 +4,27 @@
<configuration scan="true">
    <include resource="org/springframework/boot/logging/logback/base.xml"/>
    <property name="logback.dir" value="/appublic/applications/pamapi"/>
    <springProfile name="sit,uat,prod">
        <appender name="logToFile" class="ch.qos.logback.core.rolling.RollingFileAppender">
            <File>${logback.dir}/pamapi_server.log</File>
            <rollingPolicy  class="ch.qos.logback.core.rolling.TimeBasedRollingPolicy">
                <FileNamePattern>${logback.dir}/log.%d{yyyy-MM-dd}.zip</FileNamePattern>
                <maxHistory>180</maxHistory>
                <totalSizeCap>2GB</totalSizeCap>
            </rollingPolicy>
            <encoder>
                <charset>UTF-8</charset>
                <pattern>%d [%thread] %-5level %logger{36} %line - %msg%n</pattern>
            </encoder>
        </appender>
        <root level="DEBUG">
            <appender-ref ref="logToFile" />
        </root>
    </springProfile>
<!-- The FILE and ASYNC appenders are here as examples for a production configuration -->
<!--
    <appender name="FILE" class="ch.qos.logback.core.rolling.RollingFileAppender">