Quarkus中ConfigSourceInterceptor的加密配置实现

目录
  • 前言
  • 配置拦截器ConfigSourceInterceptor
    • 内置的实现
    • 加密配置实现
  • 结语

前言

加密配置是一个很常见的需求,在spring boot生态中,已经有非常多的第三方starter实现了,博主所在公司也有这种强制要求,一些敏感配置信息必须加密,比如第三方账号,数据库密码等等。所以研究了下怎么在Quarkus中实现类似的配置加密功能。在前文 Quarkus集成apollo配置中心 中,已经有介绍过Quarkus中的配置架构了,配置加密功能也是基于smallrye-config来实现。

Eclipse MicroProfile Config:https://github.com/eclipse/microprofile-config/

smallrye-config:https://github.com/smallrye/smallrye-config

配置拦截器 ConfigSourceInterceptor

在实现功能前,先看下smallrye-config1.8版本新增的配置拦截器功能。ConfigSourceInterceptor拦截器定义如下:

public interface ConfigSourceInterceptor extends Serializable {
    ConfigValue getValue(ConfigSourceInterceptorContext context, String name);
  //省略、、、
}

实现这个接口,可以在配置加载的时候通过context拿到当前配置的值,然后进行任意逻辑操作。

拦截器是通过java.util.ServiceLoader机制加载的,可以通过提供名为io.smallrye.config.ConfigSourceInterceptor的文件进行注册,该资源META-INF/services/io.smallrye.config.ConfigSourceInterceptor包含完全限定的ConfigSourceInterceptor实现类名称作为其内容。

前文 Quarkus集成apollo配置中心 中,我们已了解Quarkus的配置基于Eclipse MicroProfile Config的规范和smallrye-config的实现,但是ConfigSourceInterceptor的接口设计却没有包含在MicroProfile Config的配置规范中,smallrye团队正在努力参与规范的制定,所以后期这个接口很有可能会迁移到 MicroProfile Config包中,不过目前来看,你可以放心的使用smallrye-config1.8版本体验配置拦截器功能

内置的实现

smallrye-config内置了如下配置拦截器实现:

RelocateConfigSourceInterceptor

ProfileConfigSourceInterceptor

ExpressionConfigSourceInterceptor

FallbackConfigSourceInterceptor

LoggingConfigSourceInterceptor

SecretKeyConfigSourceInterceptor

默认情况下,并非每个拦截器都已注册。只有ProfileConfigSourceInterceptor, ExpressionConfigSourceInterceptor、SecretKeyConfigSourceInterceptor默认已注册。

其他拦截器需要通过ServiceLoader机制进行手动注册。配置中的${}表达式功能正是ExpressionConfigSourceInterceptor来实现的

加密配置实现

基于ConfigSourceInterceptor的机制,实现一个加密的拦截器,在配置时,标记需要被解密的配置,在应用启动时,拦截配置加载,做解密处理即可。这里使用了AES加解密算法,将aesKey配置在配置文件中,将vi向量直接写死在代码里,这样,即使别人拿到了你的完整配置,不知道vi向量值,也无法解密。

ConfigSourceInterceptor实现类可以通过标准javax.annotation.Priority 注释指定优先级。如果未明确指定优先级,则采用io.smallrye.config.Priorities.APPLICATION默认优先级值 。指定优先级时,value值越小,优先级越高,这里指定为PLATFORM早期拦截,代码如下:

/**
 * 1、使用方式为 正常配置值的前面拼接Encrypt=>字符串,如
 * quarkus.datasource.password = Encrypt=>xxxx
 * 2、配置解密的aeskey值,如
 * config.encrypt.aeskey = 11111111111111111
 *
 * @author kl : http://kailing.pub
 * @version 1.0
 * @date 2020/7/10 9:46
 */
//value 值越低优先级越高
@Priority(value = Priorities.PLATFORM)
public class EncryptConfigInterceptor implements ConfigSourceInterceptor {
    private static final String CONFIG_ENCRYPT_KEY = "config.encrypt.aeskey";
    private static final int AES_KEY_LENGTH = 16;
    /**
     * 需要加密值的前缀标记
     */
    private static final String ENCRYPT_PREFIX_NAME = "Encrypt=>";
    /**
     * AES加密模式
     */
    private static final String AES_MODE = "AES/CBC/PKCS5Padding";
    /**
     * AES的iv向量值
     */
    private static final String AES_IV = "1234567890123456";
    @Override
    public ConfigValue getValue(ConfigSourceInterceptorContext context, String name) {
        ConfigValue config = context.proceed(name);
        if (config != null && config.getValue().startsWith(ENCRYPT_PREFIX_NAME)) {
            String encryptValue = config.getValue().replace(ENCRYPT_PREFIX_NAME, "");
            String aesKey = context.proceed(CONFIG_ENCRYPT_KEY).getValue();
            String value = AesEncyptUtil.decrypt(encryptValue, aesKey);
            return config.withValue(value);
        }
        return config;
    }
    public static void main(String[] args) {
        System.out.println("加密后的配置:"+ AesEncyptUtil.encrypt("office#123", "1111111111111111"));
    }
   static class AesEncyptUtil{
       public static Cipher getCipher(int mode, String key) {
           if (key == null || key.length() != AES_KEY_LENGTH) {
               throw new RuntimeException("config.encrypt.key不能为空,且长度为16位");
           }
           SecretKeySpec skeySpec = new SecretKeySpec(key.getBytes(), "AES");
           //使用CBC模式,需要一个向量iv,可增加加密算法的强度
           IvParameterSpec iv = new IvParameterSpec(AES_IV.getBytes());
           Cipher cipher = null;
           try {
               cipher = Cipher.getInstance(AES_MODE);
               cipher.init(mode, skeySpec, iv);
           } catch (InvalidKeyException | InvalidAlgorithmParameterException | NoSuchPaddingException | NoSuchAlgorithmException e) {
               e.printStackTrace();
           }
           return cipher;
       }
       /**
        * AES加密函数
        * @param plaintext 被加密的字符串
        * @param key       AES key
        * @return 加密后的值
        */
       public static String encrypt(final Object plaintext, String key) {
           if (null == plaintext) {
               return null;
           }
           byte[] encrypted = new byte[0];
           try {
               Cipher encryptCipher = getCipher(Cipher.ENCRYPT_MODE, key);
               encrypted = encryptCipher.doFinal(String.valueOf(plaintext).getBytes(StandardCharsets.UTF_8));
           } catch (IllegalBlockSizeException | BadPaddingException e) {
               e.printStackTrace();
           }
           //此处使用BASE64做转码。
           return Base64.getEncoder().encodeToString(encrypted);
       }
       /**
        * AES 解密函数
        *
        * @param ciphertext 被解密的字符串
        * @param key        AES key
        * @return 解密后的值
        */
       public static String decrypt(final String ciphertext, String key) {
           if (null == ciphertext) {
               return null;
           }
           try {
               Cipher decryptCipher = getCipher(Cipher.DECRYPT_MODE, key);
               //先用base64解密
               byte[] encrypted1 = Base64.getDecoder().decode(ciphertext);
               byte[] original = decryptCipher.doFinal(encrypted1);
               return new String(original, StandardCharsets.UTF_8);
           } catch (Exception ex) {
               ex.printStackTrace();
               return null;
           }
       }
   }
}

记得将完整的类名写入到META-INF/services/io.smallrye.config.ConfigSourceInterceptor这个文件中。使用时先配置好加密的key,在application.properties中添加如下配置:

config.encrypt.aeskey = xxxxxxxxxxxxxx

配置值一定要16位,然后将需要加密的值,使用AesEncyptUtil.encrypt(final Object plaintext, String key)方法先得到加密的值,然后做如下配置,以数据库密码为例:

quarkus.datasource.username=mobile_office
quarkus.datasource.password=Encrypt=>/8wYwbxokEleEZzT4niJew==

使用Encrypt=>标记了这个值是加密的,应用程序加载时会被拦截到,然后做解密处理

结语

总的来说,Quarkus中使用的一些api设计是非常优秀的的,通过预留的这种扩展机制,可以非常轻松的实现扩展功能。

以上就是Quarkus中ConfigSourceInterceptor的加密配置实现的详细内容,更多关于Quarkus中ConfigSourceInterceptor加密的资料请关注我们其它相关文章!

(0)

相关推荐

  • Quarkus集成apollo配置中心

    目录 前言 Quarkus的config构成 microProfileconfig设计 集成apollo 前言 Quarkus默认的配置文件和spring boot 一样,默认读取application.properties文件. apollo是一个配置集中管理的开源项目,已被广泛应用. 下面我们就分析下Quarkus的配置加载结构,将apollo集成进来. Eclipse MicroProfile Config:https://github.com/eclipse/microprofile-c

  • Quarkus中实现Resteasy的文件上传下载操作

    目录 前言 文件上传 文件下载 前言 做java web开发,文件的上传和下载是一个非常常见的需求场景.在spring生态下的文件上传下载非常简单,记得五年前,我刚写博的时候也写过spring的上传和下载<SpringMvc实现文件上传与下载>,以及Struts2的文件上传和下载<java Struts2实现文件上传下载>.今天来看看Quarkus框架中是如何实现的,因为Quarkus的JAX-RS采用Resteasy的实现,故Quarkus中的文件上传和下载,也就是Resteas

  • Quarkus云原生开篇java框架简介

    目录 前言 什么是quarkus? 为什么用quarkus? 专为开发人员而设计 容器优先 命令式和响应式代码 结语 前言 Quarkus 是小红帽开源的专门针对云容器环境优化的云原生java框架,目前已迭代到1.6.0版本,已完成了大部分的框架库的集成扩展,为了让你低成本迁移到Quarkus来,它兼容主流的框架开发模式api,如spring web. Quarkus已具备企业级应用开发能力.而且未来容器云肯定是主流了,可以预见,未来的软件都是运行在k8s这样的容器集群里.而容器环境需要应用具备

  • Quarkus篇入门创建项目搭建debug环境

    目录 前言 搭建Quarkus项目 纯手工方式 官网装配器方式 IDEA方式 编写第一个Quarkus接口 启动你的应用并调试 前言 在学习一个新的框架技术前,肯定要先来一套hello word,搭建基本的运行环境和调试环境. 先来创建一个Quarkus的应用 搭建Quarkus项目 下面介绍三种创建Quarkus项目的方式 纯手工方式 1.创建maven工程,这个不多赘述,是个java程序员都会的 2.添加Quarkus依赖,下面贴出基本的依赖 <properties> <quarku

  • Quarkus中filter过滤器跨域cors问题解决方案

    目录 前言 web依赖 过滤器filter开发 resteasy的filter vertx的filter Quarkus中的跨域 前言 Quarkus中的web模块是基于java标准web规范jax-rs构建的,实现则选用了jboss的resteasy.这部分只是请求路由转发部分实现.真正的请求接收则使用了eclipse开源的vert.x框架,底层也是基于netty的一个响应式开发框架.Quarkus将vert.x和resteasy集成在了一起,所以支持响应式和非响应式应用混合开发,这也是Qua

  • Quarkus改造Pmml模型项目异常记录及解决处理

    目录 前言 异常如下: 解决 解决思路 stax-api百科 总结 前言 这个项目是一个PMML模型跑分系统,在使用quarkus架构对其改造的过程中,在加载PMML模型时,抛了一个异常,在网上找了很多资料都没有解决,pmml项目的issue中也没有找到相关的内容,故在此记录下,给遇到问题的你做个参考 jpmml-evaluator:https://github.com/jpmml/jpmml-evaluator 异常如下: java.lang.LinkageError: loader cons

  • Quarkus中ConfigSourceInterceptor的加密配置实现

    目录 前言 配置拦截器ConfigSourceInterceptor 内置的实现 加密配置实现 结语 前言 加密配置是一个很常见的需求,在spring boot生态中,已经有非常多的第三方starter实现了,博主所在公司也有这种强制要求,一些敏感配置信息必须加密,比如第三方账号,数据库密码等等.所以研究了下怎么在Quarkus中实现类似的配置加密功能.在前文 Quarkus集成apollo配置中心 中,已经有介绍过Quarkus中的配置架构了,配置加密功能也是基于smallrye-config

  • SpringBoot配置文件中数据库密码加密两种方案(推荐)

    SpringBoot项目经常将连接数据库的密码明文放在配置文件里,安全性就比较低一些,尤其在一些企业对安全性要求很高,因此我们就考虑如何对密码进行加密. 介绍两种加密方式:jasypt 可加密配置文件中所有属性值; druid 自带了加解密,可对数据库密码进行加密. jasypt 加解密 jasypt 是一个简单易用的加解密Java库,可以快速集成到 Spring 项目中.可以快速集成到 Spring Boot 项目中,并提供了自动配置,使用非常简单. 步骤如下: 1)引入maven依赖 <de

  • Quarkus中的依赖注入DI和面向切面aop编程

    目录 前言 JSR365:Java2.0的上下文和依赖注规范 Bean声明和依赖注入 Bean的生命周期 条件化初始Bean 面向切面编程aop Bean列表接口 结语 前言 做java开发的肯定清楚spring中的核心思想ioc和aop,ioc即控制反转的意思,di的核心思想和ioc一样,描述的也是同一个事情同一个思想,只是di的依赖注入更容易被理解了,aop即面向切面,如注解事务功能,就是基于aop的思想来实现的.Quarkus中也实现了一套非标准的cdi规范,下面就来看看Quarkus中的

  • Spring Kafka中如何通过参数配置解决超时问题详解

    目录 背景 思路 过程 步骤一,查询版本特性 步骤二,查源码 步骤三,查自身的代码 总结 背景 这是我们团队负责的一个不太核心的服务.之前与外部交互时应外部要求由普通kafka集群改成加密kafka集群.我们是数据生产端. 改的过程中并跑上线,60%的请求耗时增加了2倍,也还是在百毫秒的量级可以接受.但是每次重启的第一个请求要5s以上,会超过:运行过程中,一两个月也会有一次超时.因为我们有三次重试,整体没有影响成功率. 上线的时候我们问过网络组,还专门请教过公司专业负责kafka的团队.结论是:

  • SpringBoot配置文件中密码属性加密的实现

    目录 背景 集成jasypt-spring-boot到项目中 配置文件配置加密与读取 工作原理简析 使用自定义的加密算法 结语 本文主要介绍了SpringBoot配置文件中的明文密码如何加密保存,读取以及对于自定义的加密算法加密的参数如何保存和读取. 背景 为了安全的需要,一些重要的信息比如数据库密码不能明文保存在配置文件中,需要进行加密之后再保存.SpringBoot可以使用jasypt-spring-boot这个组件来为配置属性提供加密的支持. 集成jasypt-spring-boot到项目

  • JSP Spring中Druid连接池配置详解

    JSP Spring中Druid连接池配置 jdbc.properties url=jdbc:postgresql://***.***.***.***:****/**** username=*** password=*** applicationContext.xml中配置bean <!-- 阿里 druid 数据库连接池 --> <bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSou

  • spring boot中的properties参数配置详解

    application.properties application.properties是spring boot默认的配置文件,spring boot默认会在以下两个路径搜索并加载这个文件 src\main\resources src\main\resources\config 配置系统参数 在application.properties中可配置一些系统参数,spring boot会自动加载这个参数到相应的功能,如下 #端口,默认为8080 server.port=80 #访问路径,默认为/

  • Oracle在Mybatis中SQL语句的配置方法

    数据库中有下划线的字段在实体中应采用驼峰命名法,如P_NAME对应pName,实例如下: 1.XML文件中SQL语句配置(Geteway.xml文件) <?xml version="1.0" encoding="UTF-8"?> <!DOCTYPE mapper PUBLIC "-//mybatis.org//DTD Mapper 3.0//EN" "http://mybatis.org/dtd/mybatis-3-m

  • Vue中使用vux的配置详解

    Vue中使用vux的配置,分为两种情况: 一.根据vux文档直接安装,无需手动配置 npm install vue-cli -g // 如果还没安装 vue init airyland/vux2 my-project // 创建名为 my-project 的模板 cd my-project // 进入项目 npm install --registry=https://registry.npm.taobao.org // 开始安装 npm run dev // 运行项目 二.想在已创建的Vue工程

随机推荐