1. 程式人生 > >Springboot讀取私鑰為null的問題

Springboot讀取私鑰為null的問題

今天在對接三方支付公司的遇到一個小問題讀取證書

按照官方讀取提供的demo通過絕對路徑的讀取配置檔案一切OK

程式碼示例:

 

 

    /**
    * 根據Cer檔案讀取公鑰
    * 
    * @param pubCerPath
    * @return
    */
   public static PublicKey getPublicKeyFromFile(String pubCerPath) {
      FileInputStream pubKeyStream = null;
      try {
         pubKeyStream = new FileInputStream(pubCerPath);
         byte[] reads = new byte[pubKeyStream.available()];
         pubKeyStream.read(reads);
            return getPublicKeyByText(new String(reads));
      } catch (FileNotFoundException e) {
         // //log.error("公鑰檔案不存在:", e);
      } catch (IOException e) {
         // log.error("公鑰檔案讀取失敗:", e);
      } finally {
         if (pubKeyStream != null) {
            try {
               pubKeyStream.close();
            } catch (Exception e) {
               e.printStackTrace();
            }
         }
      }
      return null;
   }

 

 

 

部署到docker中無法通過絕對路徑只能通過Classpath的路徑讀取,因為springboot部署的是個jar包所以通過路徑讀取讀取不到在本地IDE中測試因為讀資原始檔是target/class中的,所以也能正常讀取

更換為以下程式碼示例問題

 

方案一
 
BaofooBizUtil.java
public static String getSignCertByJarFile(String enterpriseCerFilePath) throws IOException
{
    InputStreamReader inputStreamReader = null;
    BufferedReader bufferedReader = null;
    try{
        InputStream stream = BizUtil.class.getClassLoader().getResourceAsStream(enterpriseCerFilePath);
        inputStreamReader = new InputStreamReader(stream); // 建立一個輸入流物件reader
        bufferedReader = new BufferedReader(inputStreamReader); // 建立一個物件,它把檔案內容轉成計算機能讀懂的語言
        StringBuilder buff = new StringBuilder();
        String line = null;
        while ((line = bufferedReader.readLine()) != null) {
            buff.append(line);
            System.out.println(line);
        }
        return buff.toString();
    }catch(IOException ioe){
        ioe.printStackTrace();
        throw ioe;
    }finally{
        if(null != bufferedReader) bufferedReader.close();
        if(null != inputStreamReader) inputStreamReader.close();
    }
}
 
public static InputStream getSignCertByPath(String enterpriseCerFilePath) throws IOException {
     try{
        InputStream stream = BizUtil.class.getClassLoader().getResourceAsStream(enterpriseCerFilePath);
        return stream;
    }catch(Exception ioe){
        throw ioe;
    }
}
==========================================分割線================================================

今天對接另外一家三方支付的時候同樣的程式碼報錯了同樣的問題讀取不到私鑰的內容?

通過斷點除錯找出了問題的原因:

通過位元組流的方式讀取可以把祕鑰檔案,然後 new String(byte[]) 的時候 祕鑰檔案中的 \n 得以保留 示例:

 

 
public static PublicKey getPublicKeyFromFile(String pubCerPath) {
   InputStream pubKeyStream = null;
   try {
      pubKeyStream = BizUtil.getSignCertByPath(pubCerPath);
      byte[] reads = new byte[pubKeyStream.available()];
      pubKeyStream.read(reads);
           return getPublicKeyByText(new String(reads));
   } catch (Exception e) {
      // log.error("公鑰檔案讀取失敗:", e);
   } finally {
      if (pubKeyStream != null) {
         try {
            pubKeyStream.close();
         } catch (Exception e) {
            e.printStackTrace();
         }
      }
   }
   return null;
}

通過以下程式碼直接返回通過StringBuild之後祕鑰中的 \n 丟失了,導致在解析程式碼中解析出錯

 
public static PublicKey getSignCertByJarFile(String pubCerPath) {
    InputStream pubKeyStream = null;
    try {
        String str = BizUtil.getSignCertByJarFile(pubCerPath);
        System.out.println(str);
        return getPublicKeyByText(str);
    } catch (FileNotFoundException e) {
        // //log.error("公鑰檔案不存在:", e);
    } catch (IOException e) {
        // log.error("公鑰檔案讀取失敗:", e);
    } finally {

    }
    return null;
}

 

簡析程式碼:因為 str = “--------BEGIN CERTIFICATE-------- xxxxyyyy -----END CERTIFICATE-----” 根本簡析不處理

 

CertificateFactory certificateFactory = CertificateFactory.getInstance("X509");
BufferedReader br = new BufferedReader(new StringReader(pubKeyText));
String line = null;
StringBuilder keyBuffer = new StringBuilder();
while ((line = br.readLine()) != null) {
   if (!line.startsWith("-")) {
      keyBuffer.append(line);
   }
}

解決方法:

通過位元組流的方式讀入:

 

 InputStream pubKeyStream = null;
   try {
      pubKeyStream = BizUtil.getSignCertByPath(pubCerPath);
      byte[] reads = new byte[pubKeyStream.available()];
      pubKeyStream.read(reads);
      return getPublicKeyByText(new String(reads));
   }

 

直接讀取一條字串 :

 

 

InputStreamReader inputStreamReader = null;
BufferedReader bufferedReader = null;
try{
    InputStream stream = BizUtil.class.getClassLoader().getResourceAsStream(enterpriseCerFilePath);
    inputStreamReader = new InputStreamReader(stream); // 建立一個輸入流物件reader
    bufferedReader = new BufferedReader(inputStreamReader); // 建立一個物件,它把檔案內容轉成計算機能讀懂的語言
    StringBuilder buff = new StringBuilder();
    String line = null;
    while ((line = bufferedReader.readLine()) != null) {
        if(!line.startsWith("-")){
            buff.append(line);
        }
        System.out.println(line);
    }
    return buff.toString();

 

後續:

需要在POM中配置以下配置,不攔截cer,pem,pfx結尾的檔名

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-resources-plugin</artifactId>
    <configuration><encoding>UTF-8</encoding>
        <!-- 過濾字尾為pem、pfx的證書檔案 -->
        <nonFilteredFileExtensions>
            <nonFilteredFileExtension>cer</nonFilteredFileExtension>
            <nonFilteredFileExtension>pem</nonFilteredFileExtension>
            <nonFilteredFileExtension>pfx</nonFilteredFileExtension>
        </nonFilteredFileExtensions>
    </configuration>
</plugin>