在开发支付项目时需要读取密钥,为了保证密钥的安全性和项目的多环境使用便捷性,参考springboot的配置读取方案,设计一套支付的密钥读取方案:
优先在系统相对路径(jar包相对路径)查找如果没有,再查找jar包中的resources目录下
- 密钥的安全性建立在:如果是生产环境则读取系统相对jar包目录下的密钥文件,运维人员保密处理(执行: 1.chown -R jar包运行的用户:组 /jar/payment/cert(密钥目录) 2.chmod 740 -R /jar/payment/cert(密钥目录))
- 项目的多环境使用便捷性建立在:jar包resources中打包进默认的密钥,测试环境开发环境无需在jar目录中准备密钥,使用默认密钥即可启动项目
代码:
SpringUtils:
package com.wjj.application.util;
import org.springframework.core.io.ClassPathResource;
import org.springframework.core.io.Resource;
import java.io.*;
/**
* @author hank
*/
public class SpringUtils {
private SpringUtils(){}
/**
* 读取jar包中resources路径下的文本文件
* @param path
* @return
* @throws IOException
*/
public static String readResource(String path) throws IOException {
Resource resource = new ClassPathResource(path);
try(InputStream is = resource.getInputStream()) {
try(InputStreamReader isr = new InputStreamReader(is)) {
try(BufferedReader br = new BufferedReader(isr)) {
String data = null;
StringBuilder content = new StringBuilder();
while ((data = br.readLine()) != null) {
content.append(data);
}
return content.toString();
}
}
}
}
/**
* 读取文本文件,1.优先在系统相对路径查找如果没有2.再查找jar包中的resources目录下
* @param path
* @return
* @throws IOException
*/
public static String readResourcePrioritySys(String path) throws IOException {
String readRelativeFileStr = FileUtils.readRelativeFile(path);
if(readRelativeFileStr == null){
return readResource(path);
}
return readRelativeFileStr;
}
}
FileUtils:
package com.wjj.application.util;
import java.io.*;
/**
* 文件工具集
* @author hank
* @since 2020/3/9 0009 下午 17:58
*/
public class FileUtils {
/**
* 读取相对路径下的的文本文件
* @param filePath
* @return 存在返回内容,不存在返回null
* @throws IOException
*/
public static String readRelativeFile(String filePath) throws IOException {
// 只允许读取相对目录文件
String relativeFilePath = "."+ File.separator+filePath;
File file = new File(relativeFilePath);
// 不存在或者不是文件返回null
if(!file.exists() || !file.isFile()){
return null;
}
try(InputStreamReader reader = new InputStreamReader(new FileInputStream(file))) {
try (BufferedReader br = new BufferedReader(reader)) {
StringBuilder content = new StringBuilder();
String data = null;
while ((data = br.readLine()) != null) {
content.append(data);
}
return content.toString();
}
}
}
}
使用实例PayConfig:
package com.wjj.application.config;
import com.wjj.application.util.SpringUtils;
import lombok.Data;
import lombok.Getter;
import lombok.Setter;
import lombok.ToString;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.io.Resource;
import org.springframework.core.io.ResourceLoader;
import org.springframework.stereotype.Component;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
/**
* 支付配置
* @author hank
*/
@Component
@ConfigurationProperties(prefix = "pay")
@Getter @Setter
public class PayConfig implements InitializingBean {
private String payAppId;
/**
* 公钥
*/
private String pubStr;
/**
* 公钥路径
*/
private String pubPath;
/**
* 私钥路径
*/
private String priPath;
/**
* 私钥
*/
private String priStr;
/**
* 通知地址
*/
private String notifyUrl;
@Override
public void afterPropertiesSet() throws Exception {
pubStr = SpringUtils.readResourcePrioritySys(pubPath);
priStr = SpringUtils.readResourcePrioritySys(priPath);
}
}