公司需要将系统配置信息中的敏感信息独立存放。

现有系统采用Spring Cloud Config提供配置信息,其中敏感信息主要是Db配置,分解本次需求:

(1)数据库配置信息分离(主要是Db信息)。

(2)原有Config Server功能继续可用。

(3)对特定环境(这里是仿真环境-Demo、生产环境)可以定制配置信息。

思路有如下几种:

(1)Spring Aop 拦截Config Server中配置返回方法,改写方法返回值。

(2)Spring Aop 拦截Config Server中读取配置方法,读取更多文件源。

(3)Filter拦截Config Server中数据返回方法,改写方法返回值。

其中:

方法1与方法3都是对返回结果进行处理,可以兼容Spring Cloud Config的版本升级,因方法1需要绑定到特定方法,而方法3无需考虑具体方法,耦合性更低。

方法2需要改写Config Server的代码,或覆盖Config Server的Bean,较1和2复杂,且无法随这主版本升级,直接pass。

综合考虑采用方法3,以下是处理与代码:

公司统一标准,将Db配置信息存储到Json文件中,因此需要一个解析Json文件的Service:

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.core.env.MapPropertySource;
import org.springframework.stereotype.Component; import java.io.File;
import java.io.IOException;
import java.util.Date;
import java.util.LinkedHashMap;
import java.util.Map; @Component
public class JsonSourcePropertiesLoader {
@Value("${Config.Json.FileLocation}")
String FileLocation; public MapPropertySource load() throws IOException {
File jsonFile = new File(FileLocation);
final Map<String, Object> source = process(jsonFile);
System.out.println(new Date().getTime());
return new MapPropertySource("dbConfigMap",source);
} private Map<String, Object> process(final File resourceFile){
Map<String, Object> map = null;
try{
map = new ObjectMapper().readValue(resourceFile, LinkedHashMap.class);
}catch (IOException e){
e.printStackTrace();
}
return map;
}
}

需要一个类拦截并获取Config Server在正常处理请求后返回的内容,以便接下来的改写:

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpServletResponseWrapper;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.PrintWriter; public class MyResponseWrapper extends HttpServletResponseWrapper {
private ByteArrayOutputStream byteArrayOutputStream;
private ServletOutputStream servletOutputStream;
private PrintWriter printWriter; public MyResponseWrapper(HttpServletResponse response) {
super(response);
byteArrayOutputStream = new ByteArrayOutputStream(4096);
printWriter = new PrintWriter(byteArrayOutputStream);
servletOutputStream = new MyServletOutputStream(byteArrayOutputStream);
} @Override
public PrintWriter getWriter() throws IOException{
return printWriter;
} @Override
public ServletOutputStream getOutputStream() throws IOException{
return servletOutputStream;
} @Override
public void flushBuffer() throws IOException{
if(printWriter!=null){
printWriter.flush();
}
if(servletOutputStream !=null){
servletOutputStream.flush();
}
} @Override
public void reset(){
byteArrayOutputStream.reset();
} public byte[] getResult(){
try{
flushBuffer();
}catch (IOException e){ }
return byteArrayOutputStream.toByteArray();
}
}

对ServletOutputStream的封装类:

import javax.servlet.ServletOutputStream;
import javax.servlet.WriteListener;
import java.io.ByteArrayOutputStream;
import java.io.IOException; public class MyServletOutputStream extends ServletOutputStream {
ByteArrayOutputStream output; public MyServletOutputStream(ByteArrayOutputStream output) {
this.output = output;
} @Override
public void write(int b) throws IOException {
output.write(b);
} public void write(byte[] data, int offset, int length) {
output.write(data, offset, length);
} @Override
public boolean isReady() {
return false;
} @Override
public void setWriteListener(WriteListener listener) { }
}

有了拦截与处理的方法,最后就是把功能组合到拦截器中:

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.fang.microservice.cloud.Loader.JsonSourcePropertiesLoader;
import com.fang.microservice.cloud.Wrapper.MyResponseWrapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.web.servlet.ServletComponentScan;
import org.springframework.core.env.MapPropertySource;
import org.springframework.stereotype.Component; import javax.servlet.*;
import javax.servlet.annotation.WebFilter;
import javax.servlet.http.HttpServletResponse;
import java.io.*; @Component
@ServletComponentScan
@WebFilter(urlPatterns = "/{name}/{profiles:.*[^-].*}", filterName = "ConfigServletFilter")
public class ConfigAspectFilter implements Filter {
@Autowired
JsonSourcePropertiesLoader jsonConfig; @Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest request, ServletResponse response, FilterChain chain) throws IOException, ServletException {
MyResponseWrapper wrapper = new MyResponseWrapper((HttpServletResponse) response);
chain.doFilter(request, wrapper);
byte[] respBytes = wrapper.getResult();
String result = Byte2String(respBytes);
if (response.getContentType().toLowerCase().contains("application/json")) {
if (!result.toLowerCase().contains("datasource.mysql.")) {
JSONObject configObj = (JSONObject) JSON.parse(result);
JSONArray propertySourcesObjs = configObj.getJSONArray("propertySources");
if (propertySourcesObjs.size() > 0) {
JSONObject propertySourcesObj = (JSONObject) propertySourcesObjs.get(0);
JSONObject sourceObj = propertySourcesObj.getJSONObject("source");
MapPropertySource mps = jsonConfig.load();
for (String key : mps.getPropertyNames()) {
sourceObj.put(key, mps.getProperty(key));
}
result = JSON.toJSONString(configObj);
}
}
} response.setContentLength(-1);
PrintWriter out = response.getWriter();
out.write(result);
out.flush();
out.close();
} public static String Byte2String(byte[] buff) {
ByteArrayOutputStream result = new ByteArrayOutputStream();
int length;
try {
result.write(buff, 0, buff.length);
} catch (Exception e) {
e.printStackTrace();
}
try {
return result.toString("UTF-8");
} catch (UnsupportedEncodingException e) {
e.printStackTrace();
}
return "";
} @Override
public void destroy() { }
}

作为敏感数据存储的文件内容:

{ "testDbName":"testDb","userName":"userName","password":"pass"}

测试效果如下:

最后不能忘记特定敏感文件的路径,需要配置在配置文件中:

Config.Json.FileLocation=/xx/test/test.json

这样,一个既可以规避敏感文件,又能不失Config Server方便性的简单处理方案就这样可以投入使用了。

 

Spring Cloud 自定义ConfigServer 解决敏感信息存储问题的更多相关文章

  1. Spring Cloud 自定义ConfigServer

    公司需要将系统配置信息中的敏感信息独立存放. 现有系统采用Spring Cloud Config提供配置信息,其中敏感信息主要是Db配置,分解本次需求: (1)数据库配置信息分离(主要是Db信息). ...

  2. 利用Spring AOP自定义注解解决日志和签名校验

    转载:http://www.cnblogs.com/shipengzhi/articles/2716004.html 一.需解决的问题 部分API有签名参数(signature),Passport首先 ...

  3. spring cloud 自定义ribbon客户端

    一.自定义Ribbon客户端-[方式一]配置类 1.1.自定义负载规则 增加RibbonConfiguration.java配置类 public class RibbonConfiguration { ...

  4. 【分布式事务】spring cloud集成lcn解决分布式事务

    参考地址:https://blog.csdn.net/u010882691/article/details/82256587 参考地址:https://blog.csdn.net/oyh1203/ar ...

  5. (转)利用Spring AOP自定义注解解决日志和签名校验

    一.需解决的问题 部分API有签名参数(signature),Passport首先对签名进行校验,校验通过才会执行实现方法. 第一种实现方式(Origin):在需要签名校验的接口里写校验的代码,例如: ...

  6. spring Cloud中,解决Feign/Ribbon整合Hystrix第一次请求失败的问题?

    Spring Cloud中,Feign和Ribbon在整合了Hystrix后,可能会出现首次调用失败的问题,要如何解决该问题呢? 造成该问题的原因 Hystrix默认的超时时间是1秒,如果超过这个时间 ...

  7. spring cloud报错解决:java.lang.ClassNotFoundException: com.netflix.servo.monitor.Monitors

    见鬼的事发生了. 在家里电脑上拿样例代码,运行时OK的.但一到公司电脑,用同样的代码,就会报下面的错误 ===================== Caused by: java.lang.Class ...

  8. Spring Cloud教程合集

    Spring Cloud系列终于搞完啦! 这一系列是笔者的学习笔记,原书之前也给小伙伴们推荐过 <Spring Cloud微服务实战> 原书采用了较老的Brixton版,笔者在学习的过程中 ...

  9. SpringCloud---API网关服务---Spring Cloud Zuul

    1.概述 1.1 微服务架构出现的问题   及  解决: 1.1.1 前言 每个微服务应用都提供对外的Restful API服务,它通过F5.Nginx等网络设备或工具软件实现对各个微服务的路由与负载 ...

随机推荐

  1. css的基础用法(上)

    css定义: CSS层叠式样表(Cascading  Style Sheets)是一种用来表现html或xml等文件样式的计算机语言.CSS不仅可以静态的修饰网页,还可以配合各种脚本语言动态地对网页个 ...

  2. 菜鸟笔记 -- Chapter 11 格式化

    我们在String中介绍过它有一个格式化的方法,在其它很多地方,也都能看到格式化的操作,那么这节我们就来认真了解一下Java中的格式化操作. 我们在操作中涉及到的格式化有字符串的格式化和一些其它数据类 ...

  3. 字段中有空的时候 进行逻辑运算,mysql 与 oracle 处理函数IFNULL() 与 nvl() ,选取NULL 值 。

    mySQL数据库: SELECT id_p,IFNULL(math,0)+IFNULL(english,0) 总分 from mytest_brian1 Oracle 数据库: select  id_ ...

  4. C#中rpt的数据类型和Oracle中数据类型的匹配

    Oracle中number数据类型对应C#中decimal数据类型,结果是整数 Oracle中number数据类型对应C#中int32数据类型,结果是小数,保留两位小数 Oracle中中date类型数 ...

  5. ios应用数据存储方式(偏好设置)-转

    一.简单介绍 1.很多ios应用都支持偏好设置,比如保存用户名,密码,字体大小等设置,ios提供了一套标准的解决方案来为应用加入偏好设置功能. 2.每个应用都有个NSUserDefaults实例,通过 ...

  6. iOS之出现( linker command failed with exit code 1)错误总结

    本文出自:http://blog.csdn.NET/hengshujiyi/article/details/21182813 补充:我出现这个错误是一个工程中有两个同名的文件,只要删除掉一个就好了,可 ...

  7. Linux入门-第五周

    1.磁盘lvm管理,完成下面要求,并写出详细过程: 1) 创建一个至少有两个PV组成的大小为20G的名为testvg的VG;要求PE大小 为16MB, 而后在卷组中创建大小为5G的逻辑卷testlv; ...

  8. lvs集群实现lvs-dr模型和lvs-nat模型

    ipvsadm ipvsadm命令是lvs集群在应用层的管理工具,我们可以通过此ipvsadm来管理lvs的配置,其实现了集群服务管理:增.删.改,集群服务的RS管理:增.删.改以及查看集群状态. 管 ...

  9. Java中的文件和stream流的操作代码

    1.Java中FileRead方法的运用代码及详解 package example2;import java.io.FileReader;import java.io.IOException;clas ...

  10. Redis学习推荐

    Redis快速入门 https://www.yiibai.com/redis/redis_quick_guide.html Redis用途和使用场景 https://blog.csdn.net/wei ...