Spring-使用加密的属性文件02

本文涉及的产品
密钥管理服务KMS,1000个密钥,100个凭据,1个月
简介: Spring-使用加密的属性文件02

概述


对于不敏感的属性信息,以明文形式出现在属性文件中是合适的,但是如果属性信息是数据库用户名和密码等敏感信息,一般希望以密文的方式保存。


这就要求对应用程序配置文件的某些属性进行加密,让Spring容器在读取属性文件后,在内存中对属性进行解密,然后将解密后的属性值赋给目标对象。


我们来看下 PropertyPlaceholderConfigurer的继承关系

20170807063302874.jpg

PropertyResourceConfigurer类中有几个方法


20170807063415397.jpg


实例

代码已托管到Github—> https://github.com/yangshangwei/SpringMaster


20170807105018061.jpg

DES加密解密工具类


信息的加密分为对称和非对称两种方式, 前者表示加密后的信息可以解密为原值,而后者则不能根据加密后的信息还原为原值。


MD5属于非对称加密, DES属于对称加密。

先用DES对属性值进行加密,在读取到属性值时,在用DES进行解密。

DES加密解密工具类

package com.xgj.ioc.propertyplacehoderEncryption;
import java.security.Key;
import java.security.SecureRandom;
import javax.crypto.Cipher;
import javax.crypto.KeyGenerator;
import sun.misc.BASE64Decoder;
import sun.misc.BASE64Encoder;
public class DESUtils {
    private static Key key;
    // 指定DES加密解密用的密钥
    private static String KEY_STR = "myKey";
    static {
        try {
            KeyGenerator generator = KeyGenerator.getInstance("DES");
            generator.init(new SecureRandom(KEY_STR.getBytes()));
            key = generator.generateKey();
            generator = null;
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 
     * 
     * @Title: getEncryptString
     * 
     * @Description: 对字符串进行加密,返回BASE64编码的加密字符串
     * 
     * @param str
     * @return
     * 
     * @return: String
     */
    public static String getEncryptString(String str) {
        BASE64Encoder base64en = new BASE64Encoder();
        try {
            byte[] strBytes = str.getBytes("UTF8");
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.ENCRYPT_MODE, key);
            byte[] encryptStrBytes = cipher.doFinal(strBytes);
            return base64en.encode(encryptStrBytes);
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 
     * 
     * @Title: getDecryptString
     * 
     * @Description:对BASE64编码的加密字符串进行解密,返回解密后的字符串
     * 
     * @param str
     * @return
     * 
     * @return: String
     */
    public static String getDecryptString(String str) {
        BASE64Decoder base64De = new BASE64Decoder();
        try {
            byte[] strBytes = base64De.decodeBuffer(str);
            Cipher cipher = Cipher.getInstance("DES");
            cipher.init(Cipher.DECRYPT_MODE, key);
            byte[] decryptStrBytes = cipher.doFinal(strBytes);
            return new String(decryptStrBytes, "UTF8");
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
    /**
     * 
     * 
     * @Title: main
     * 
     * @Description: 测试方法
     * 
     * @param args
     * @throws Exception
     * 
     * @return: void
     */
    public static void main(String[] args) throws Exception {
        System.out.println(getEncryptString("cc"));
        System.out.println(getEncryptString("zsmart2017"));
        System.out.println(getDecryptString("SkR6wWI9iws="));
        System.out.println(getDecryptString("lSR/mscM1NE3sM98QFjAdw=="));
    }
}


使用密文版的属性文件

  1. 运行 DESUtils, 得到 用户名和密码的加密字符串
  2. 修改jdbc.properties


jdbc.driverClassName=oracle.jdbc.driver.OracleDriver
jdbc.url=jdbc:oracle:thin:@172.25.246.11:1521:xgj
jdbc.username=SkR6wWI9iws=
jdbc.password=lSR/mscM1NE3sM98QFjAdw==


PropertyPlaceholderConfigurer 本身不支持密文版的属性文件,不过我们可以扩展该类,重写 String convertProperty(String propertyName, String propertyValue)方法


package com.xgj.ioc.propertyplacehoderEncryption;
import org.springframework.beans.factory.config.PropertyPlaceholderConfigurer;
/**
 * 
 * 
 * @ClassName: EncryptPropertyPlaceholderConfigurer
 * 
 * @Description: 继承PropertyPlaceholderConfigurer,重写convertProperty方法,对属性进行解密
 * 
 * @author: Mr.Yang
 * 
 * @date: 2017年8月6日 下午11:01:23
 */
public class EncryptPropertyPlaceholderConfigurer extends
        PropertyPlaceholderConfigurer {
    // 对应jdbc.properties中的key
    private String[] encryptPropNames = { "jdbc.username", "jdbc.password" };
    @Override
    protected String convertProperty(String propertyName, String propertyValue) {
        if (isEncryptProp(propertyName)) {
            String decryptValue = DESUtils.getDecryptString(propertyValue);
            System.out.println("解密后的字符串:" + decryptValue);
            return decryptValue;
        } else {
            return propertyValue;
        }
    }
    /**
     * 判断是否是加密的属性
     * 
     * @param propertyName
     * @return
     */
    private boolean isEncryptProp(String propertyName) {
        for (String encryptPropName : encryptPropNames) {
            if (encryptPropName.equals(propertyName)) {
                return true;
            }
        }
        return false;
    }
}


EncryptPropertyPlaceholderConfigurer使用DESUtils中的方法解密加密后的字符串。


修改配置文件,引用自定义的EncryptPropertyPlaceholderConfigurer

<!-- 引入JDBC属性文件  加密-->
    <bean  class="com.xgj.ioc.propertyplacehoderEncryption.EncryptPropertyPlaceholderConfigurer"
        p:location="classpath:spring/jdbc.properties"
        p:fileEncoding="utf-8"/> 

使用自定义的属性加载器后,就无法使用context:property-placeholder属性加载配置文件了,必须使用传统的方式引用加密版的属性文件,如上

完整的配置文件:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
    xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:context="http://www.springframework.org/schema/context"
    xsi:schemaLocation="http://www.springframework.org/schema/beans 
        http://www.springframework.org/schema/beans/spring-beans.xsd
        http://www.springframework.org/schema/context 
        http://www.springframework.org/schema/context/spring-context.xsd">
    <!-- 扫描类包,将标注Spring注解的类自动转化Bean,同时完成Bean的注入 -->
    <context:component-scan base-package="com.xgj.ioc.propertyplacehoderEncryption"/>
    <!-- 引入JDBC属性文件  加密-->
    <bean  class="com.xgj.ioc.propertyplacehoderEncryption.EncryptPropertyPlaceholderConfigurer"
        p:location="classpath:spring/jdbc.properties"
        p:fileEncoding="utf-8"/> 
    <!-- 通过属性名引用属性值 -->     
    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource"
        destroy-method="close"
        p:driverClassName="${jdbc.driverClassName}"
        p:url="${jdbc.url}"
        p:username="${jdbc.username}"
        p:password="${jdbc.password}"/>
    <!-- 配置Jdbc模板  -->
    <bean id="jdbcTemplate" class="org.springframework.jdbc.core.JdbcTemplate"
        p:dataSource-ref="dataSource" />
</beans>

测试类

package com.xgj.ioc.propertyplacehoderEncryption;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.stereotype.Component;
@Component
public class PropertyPlaceHoderEncryptionTest {
    private final static String MATCH_COUNT_SQL = " SELECT count(*) FROM temp_user  "
            + " WHERE user_name =? and password=? ";
    private JdbcTemplate jdbcTemplate;
    @Autowired
    public void setJdbcTemplate(JdbcTemplate jdbcTemplate) {
        this.jdbcTemplate = jdbcTemplate;
    }
    /**
     * 
     * 
     * @Title: getMatchCount
     * 
     * @Description: 根据用户名和密码判断用户是否存在
     * 
     * @param username
     * @param password
     * 
     * @return: int
     */
    public int getMatchCount(String username, String password) {
        return jdbcTemplate.queryForObject(MATCH_COUNT_SQL, new Object[] {
                username, password }, Integer.class);
    }
    /**
     * 
     * 
     * @Title: main
     * 
     * @Description: 测试
     * 
     * @param args
     * 
     * @return: void
     */
    public static void main(String[] args) {
        // 加载Spring配置文件
        ApplicationContext ctx = new ClassPathXmlApplicationContext(
                "classpath:com/xgj/ioc/propertyplacehoderEncryption/beans.xml");
        // 获取通过注解标注的Bean
        PropertyPlaceHoderEncryptionTest propertyplacehoderEncryption = ctx
                .getBean("propertyPlaceHoderEncryptionTest",
                        PropertyPlaceHoderEncryptionTest.class);
        // 调用方法
        int count = propertyplacehoderEncryption.getMatchCount("xgj", "123456");
        System.out.println("匹配的用户数量:" + count);
    }
}


测试结果


20170807113905360.jpg


相关文章
|
2月前
|
监控 Java 应用服务中间件
高级java面试---spring.factories文件的解析源码API机制
【11月更文挑战第20天】Spring Boot是一个用于快速构建基于Spring框架的应用程序的开源框架。它通过自动配置、起步依赖和内嵌服务器等特性,极大地简化了Spring应用的开发和部署过程。本文将深入探讨Spring Boot的背景历史、业务场景、功能点以及底层原理,并通过Java代码手写模拟Spring Boot的启动过程,特别是spring.factories文件的解析源码API机制。
87 2
|
4月前
|
数据安全/隐私保护 Python
用python对文件内容进行加密的2种方式
这篇文章介绍了使用Python对文件内容进行加密的两种方式:利用`cryptography`库的Fernet对称加密和使用`rsa`库进行RSA非对称加密。
101 6
|
11天前
|
Java Spring
【Spring配置】创建yml文件和properties或yml文件没有绿叶
本文主要针对,一个项目中怎么创建yml和properties两种不同文件,进行配置,和启动类没有绿叶标识进行解决。
|
3月前
|
安全 Linux 数据安全/隐私保护
python知识点100篇系列(15)-加密python源代码为pyd文件
【10月更文挑战第5天】为了保护Python源码不被查看,可将其编译成二进制文件(Windows下为.pyd,Linux下为.so)。以Python3.8为例,通过Cython工具,先写好Python代码并加入`# cython: language_level=3`指令,安装easycython库后,使用`easycython *.py`命令编译源文件,最终生成.pyd文件供直接导入使用。
python知识点100篇系列(15)-加密python源代码为pyd文件
|
3月前
|
数据安全/隐私保护 Python
Zipfile学习笔记(二)::通过zipfile模块暴力破解加密的压缩文件
如何使用Python的zipfile模块生成密码表并尝试暴力破解加密的ZIP压缩文件。
56 1
Zipfile学习笔记(二)::通过zipfile模块暴力破解加密的压缩文件
|
3月前
|
存储 安全 Java
|
3月前
|
存储 前端开发 Java
Spring Boot 集成 MinIO 与 KKFile 实现文件预览功能
本文详细介绍如何在Spring Boot项目中集成MinIO对象存储系统与KKFileView文件预览工具,实现文件上传及在线预览功能。首先搭建MinIO服务器,并在Spring Boot中配置MinIO SDK进行文件管理;接着通过KKFileView提供文件预览服务,最终实现文档管理系统的高效文件处理能力。
461 11
|
4月前
|
人工智能 IDE 开发工具
Python实行任意文件的加密—解密
Python实行任意文件的加密—解密
32 2
|
4月前
|
人工智能 IDE 开发工具
Python实行任意文件的加密—解密
Python实行任意文件的加密—解密
58 1
|
3月前
|
Java Maven Spring
用Spring导致的无法运行Java文件的问题的解决方案
本文提供了解决在IntelliJ IDEA社区版中使用Spring Initializr插件创建Spring项目后,Java文件无法运行的问题的方法,主要是通过加载Maven项目来解决。
91 0