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;
    }
}
==========================================分割线================================================

今天对接另外一家三方支付的时候同样的代码报错了同样的问题读取不到私钥的内容?

扫描二维码关注公众号,回复: 4427701 查看本文章

通过断点调试找出了问题的原因:

通过字节流的方式读取可以把秘钥文件,然后 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>

猜你喜欢

转载自blog.csdn.net/yhl_woniu/article/details/80136871