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

现有系统采用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 cloud 自定义ribbon客户端

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

  3. Spring Cloud教程合集

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

  4. spring cloud 2.x版本 Config配置中心教程

    前言 本文采用Spring cloud本文为2.1.8RELEASE,version=Greenwich.SR3 本文基于前面的文章eureka-server的实现. 参考 eureka-server ...

  5. Spring Cloud 升级之路 - 2020.0.x - 7. 使用 Spring Cloud LoadBalancer (2)

    本项目代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 我们使用 Spri ...

  6. SpringCloud升级之路2020.0.x版-24.测试Spring Cloud LoadBalancer

    本系列代码地址:https://github.com/HashZhang/spring-cloud-scaffold/tree/master/spring-cloud-iiford 通过单元测试,我们 ...

  7. spring cloud 服务A调用服务B自定义token消失,记录

    后端:spring cloud 前端:vue 场景:前端ajax请求,包装自定义请求头token到后台做验证,首先调用A服务,A服务通过Feign调用B服务发现自定义token没有传到B服务去; 原因 ...

  8. Spring Cloud Stream消费失败后的处理策略(二):自定义错误处理逻辑

    应用场景 上一篇<Spring Cloud Stream消费失败后的处理策略(一):自动重试>介绍了默认就会生效的消息重试功能.对于一些因环境原因.网络抖动等不稳定因素引发的问题可以起到比 ...

  9. Spring Cloud(7):Zuul自定义过滤器和接口限流

    上文讲到了Zuul的基本使用: https://www.cnblogs.com/xuyiqing/p/10884860.html 自定义Zuul过滤器: package org.dreamtech.a ...

随机推荐

  1. Android 开发笔记___textview_聊天室效果

    <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android=&quo ...

  2. css中的em用法

    px:是相对于浏览器分辨率的一个度量单位 em是一个相对于父元素的font-size的大小的一个度量单位 1.浏览器的默认字体大小是16px 2.如果元素自身没有设置字体大小,那么元素自身上的所有属性 ...

  3. json标准是双引号

    双引号才是json 的标准,单引号是不规范的(虽然在js 中是行的通的)!json 的名称和字符串值需要用双引号引起来,单引号的话,使用json.parse会出现错误

  4. indexed database IndexedDB

    Indexed Database API 目的是提供一个可供javascript存储和检索对象,并且还能进行查询,搜索等数据库操作   设计为几乎完全异步,因此绝大部分操作都稍后执行,因此每次操作都应 ...

  5. Vue.js用法详解(一)更新中~

      前  言 前段时间为了一个数据查询的项目自学了Vue,感觉这款框架还是很不错的,今天就整理整理这个框架如何使用,希望对正在学这个框架的小伙伴有所帮助~ 首先,我们先来了解一下Vue: Vue.js ...

  6. Adobe Html5 Extension开发初体验

    一.背景介绍       Adobe公司出品的多媒体处理软件产品线较多,涵盖了音视频编辑.图像处理.平面设计.影视后期等领域.为了扩展软件的功能,Adobe公司为开发者提供了两种方式来增加软件的功能: ...

  7. SQL系统函数的使用(实验五)

    SQL系统函数的使用(试验5) 函数在查询语句中的使用 查询员工的姓名和日工资(保留1位小数): 查询并显示部门号为01和02的所有员工的姓名首字及岗位: 查询并显示所有员工的姓名及工龄: 查询199 ...

  8. 异步 HttpContext.Current实现取值的方法(解决异步Application,Session,Cache...等失效的问题)

    在一个项目中,为了系统执行效率更快,把一个经常用到的数据库表通过dataset放到Application中,发现在异步实现中每一次都会出现HttpContext.Current为null的异常,后来在 ...

  9. fio——IO基准测试

    简介 fio是IO工具,既可以用于基准测试,也可以用于硬件的压力测试验证(stress/hardware verification). 支持13种不同的IO引擎(sync.mmap.libaio.po ...

  10. Python闭包

    1.概述 闭包是在其词法上下文中引用自由变量的函数. >>> def foo(): ... m=3 ... n=5 ... def bar(): ... a=4 ... return ...