开发喵星球

若依集成Druid实现数据库密码加密(265)

需求提出

在项目中,数据库密码直接写在配置文件中存在安全风险。为了提高运维安全性,可以使用Druid提供的ConfigFilter功能对数据库密码进行加密。

相关介绍

Druid是一个非常优秀的数据库连接池,同时提供了一些数据库密码加密的功能。通过使用DruidConfigFilter,可以实现对数据库密码的加密和解密,从而提高安全性。

解决思路

  1. 使用Druid工具对数据库密码进行加密。
  2. 配置数据源,使其支持密码解密。
  3. 在项目中配置Druid属性,启用加密功能。
  4. 启动应用程序并验证加密结果。

所需技术

项目结构

ruoyi
├── ruoyi-admin
│   └── src
│       └── main
│           └── resources
│               └── application.yml
├── ruoyi-framework
│   └── src/main/java
│       └── com/ruoyi/framework
│           └── config
                └── properties
                    └── DruidProperties.java

注意事项

完整代码

第一步:执行命令加密数据库密码

在命令行中执行以下命令:

java -cp druid-1.2.4.jar com.alibaba.druid.filter.config.ConfigTools password

其中password是你的数据库密码,执行后会输出加密后的结果:

privateKey:MIIBVAIBADANBgkqhkiG9w0BAQEFAASCAT4wggE6AgEAAkEAuLMVAFmcew+mPfVnzI6utEvhHWO2s6e4R1bVW3a9IpH+pEypeNV6KtZ/w9PuysPfdPxW5fN3BmnKFZUAIMvWhQIDAQABAkA6rnsfr1juKFyzFsMx1KthETKmucWUctczoz0KYEFbN+joNsd/ApQqsS/2MVG1QWbDJLUsSLWkchvRbtiqOlVJAiEA6KmgVeLR2qUU9gv6DJfuWk4Ol1M9GJnTamgyDttsSGcCIQDLOdjcht29s954vApG1fiPTP/kMvZ5aLrccw1lEuEGMwIhAKoe3c3u++MTsi/2se9jaDU/vguIIbRLRfsYFQIoDxUhAiAnCm/cvZPvk5RTgVxAC276qIIoJpou7K2pF/kkx6Gu/QIgKUVFiM8GVZkOWZC+nUm3UIfpGjrKXjvGrlHNvt89uBA=
publicKey:MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALizFQBZnHsPpj31Z8yOrrRL4R1jtrOnuEdW1Vt2vSKR/qRMqXjVeirWf8PT7srD33T8VuXzdwZpyhWVACDL1oUCAwEAAQ==
password:gkYlljNHKe0/4z7bbJxD7v/txWJIFbiGWwsIPo176Q7fG0UjcSizNxuRUI2ll27ZPQf2ekiHFptus2/Rc4cmvA==

第二步:配置数据源

application.yml中配置数据源,提示Druid数据源需要对数据库密码进行解密:

# 数据源配置
spring:
    datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driverClassName: com.mysql.cj.jdbc.Driver
        druid:
            # 主库数据源
            master:
                url: jdbc:mysql://localhost:3306/ry?useUnicode=true&characterEncoding=utf8&zeroDateTimeBehavior=convertToNull&useSSL=true&serverTimezone=GMT%2B8
                username: root
                password: gkYlljNHKe0/4z7bbJxD7v/txWJIFbiGWwsIPo176Q7fG0UjcSizNxuRUI2ll27ZPQf2ekiHFptus2/Rc4cmvA==
            # 从库数据源
            slave:
                # 从数据源开关/默认关闭
                enabled: false
                url: 
                username: 
                password: 
            # 初始连接数
            initialSize: 5
            # 最小连接池数量
            minIdle: 10
            # 最大连接池数量
            maxActive: 20
            # 配置获取连接等待超时的时间
            maxWait: 60000
            # 配置连接超时时间
            connectTimeout: 30000
            # 配置网络超时时间
            socketTimeout: 60000
            # 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒
            timeBetweenEvictionRunsMillis: 60000
            # 配置一个连接在池中最小生存的时间,单位是毫秒
            minEvictableIdleTimeMillis: 300000
            # 配置一个连接在池中最大生存的时间,单位是毫秒
            maxEvictableIdleTimeMillis: 900000
            # 配置检测连接是否有效
            validationQuery: SELECT 1 FROM DUAL
            testWhileIdle: true
            testOnBorrow: false
            testOnReturn: false
            connectProperties: config.decrypt=true;config.decrypt.key=MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALizFQBZnHsPpj31Z8yOrrRL4R1jtrOnuEdW1Vt2vSKR/qRMqXjVeirWf8PT7srD33T8VuXzdwZpyhWVACDL1oUCAwEAAQ==
            webStatFilter: 
                enabled: true
            statViewServlet:
                enabled: true
                # 设置白名单,不填则允许所有访问
                allow:
                url-pattern: /druid/*
                # 控制台管理用户名和密码
                login-username: ruoyi
                login-password: 123456
            filter:
                config:
                    # 是否配置加密
                    enabled: true
                stat:
                    enabled: true
                    # 慢SQL记录
                    log-slow-sql: true
                    slow-sql-millis: 1000
                    merge-sql: true
                wall:
                    config:
                        multi-statement-allow: true

第三步:配置DruidProperties

DruidProperties中配置connectProperties属性:

package com.ruoyi.framework.config.properties;

import org.springframework.beans.factory.annotation.Value;
import org.springframework.context.annotation.Configuration;
import com.alibaba.druid.pool.DruidDataSource;

/**
 * druid 配置属性
 * 
 * @author ruoyi
 */
@Configuration
public class DruidProperties
{
    @Value("{spring.datasource.druid.initialSize}")
    private int initialSize;

    @Value("{spring.datasource.druid.minIdle}")
    private int minIdle;

    @Value("{spring.datasource.druid.maxActive}")
    private int maxActive;

    @Value("{spring.datasource.druid.maxWait}")
    private int maxWait;

    @Value("{spring.datasource.druid.connectTimeout}")
    private int connectTimeout;

    @Value("{spring.datasource.druid.socketTimeout}")
    private int socketTimeout;

    @Value("{spring.datasource.druid.timeBetweenEvictionRunsMillis}")
    private int timeBetweenEvictionRunsMillis;

    @Value("{spring.datasource.druid.minEvictableIdleTimeMillis}")
    private int minEvictableIdleTimeMillis;

    @Value("{spring.datasource.druid.maxEvictableIdleTimeMillis}")
    private int maxEvictableIdleTimeMillis;

    @Value("{spring.datasource.druid.validationQuery}")
    private String validationQuery;

    @Value("{spring.datasource.druid.testWhileIdle}")
    private boolean testWhileIdle;

    @Value("{spring.datasource.druid.testOnBorrow}")
    private boolean testOnBorrow;

    @Value("{spring.datasource.druid.testOnReturn}")
    private boolean testOnReturn;

    @Value("{spring.datasource.druid.connectProperties}")
    private String connectProperties;

    public DruidDataSource dataSource(DruidDataSource datasource)
    {
        /** 配置初始化大小、最小、最大 */
        datasource.setInitialSize(initialSize);
        datasource.setMaxActive(maxActive);
        datasource.setMinIdle(minIdle);

        /** 配置获取连接等待超时的时间 */
        datasource.setMaxWait(maxWait);

        /** 配置驱动连接超时时间,检测数据库建立连接的超时时间,单位是毫秒 */
        datasource.setConnectTimeout(connectTimeout);

        /** 配置网络超时时间,等待数据库操作完成的网络超时时间,单位是毫秒 */
        datasource.setSocketTimeout(socketTimeout);

        /** 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 */
        datasource.setTimeBetweenEvictionRunsMillis(timeBetweenEvictionRunsMillis);

        /** 配置一个连接在池中最小、最大生存的时间,单位是毫秒 */
        datasource.setMinEvictableIdleTimeMillis(minEvictableIdleTimeMillis);
        datasource.setMaxEvictableIdleTimeMillis(maxEvictableIdleTimeMillis);

        /**
         * 用来检测连接是否有效的sql,要求是一个查询语句,常用select 'x'。如果validationQuery为null,testOnBorrow、testOnReturn、testWhileIdle都不会起作用。
         */
        datasource.setValidationQuery(validationQuery);
        /** 建议配置为true,不影响性能,并且保证安全性。申请连接的时候检测,如果空闲时间大于timeBetweenEvictionRunsMillis,执行validationQuery检测连接是否有效。 */
        datasource.setTestWhileIdle(testWhileIdle);
        /** 申请连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnBorrow(testOnBorrow);
        /** 归还连接时执行validationQuery检测连接是否有效,做了这个配置会降低性能。 */
        datasource.setTestOnReturn(testOnReturn);

        /** 为数据库密码提供加密功能 */
        datasource.setConnectionProperties(connectProperties);
        return datasource;
    }
}

第四步:启动应用程序测试验证加密结果

启动应用程序,验证是否能够正常连接数据库并使用加密的密码。

解密工具类

如果忘记密码,可以使用以下工具类进行解密:

import com.alibaba.druid.filter.config.ConfigTools;

public class DecryptPassword {
    public static void main(String[] args) throws Exception {
        String password = ConfigTools.decrypt(
            "MFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBALizFQBZnHsPpj31Z8yOrrRL4R1jtrOnuEdW1Vt2vSKR/qRMqXjVeirWf8PT7srD33T8VuXzdwZpyhWVACDL1oUCAwEAAQ==",
            "gkYlljNHKe0/4z7bbJxD7v/txWJIFbiGWwsIPo176Q7fG0UjcSizNxuRUI2ll27ZPQf2ekiHFptus2/Rc4cmvA=="
        );
        System.out.println("解密密码:" + password);
    }
}

运行结果

通过上述步骤,成功实现了数据库密码的加密和解密,提升了数据库连接的安全性。

   
分类:Java/OOP 作者:无限繁荣, 吴蓉 发表于:2024-07-08 14:47:07 阅读量:226
<<   >>


powered by kaifamiao