java - 如何在 hibernate.cfg.xml 中将 hibernate.connection.password 设置为加密值,然后将其解密以在配置中使用?

标签 java hibernate encryption

我正在尝试在 hibernate.connection.password 的属性中创建加密值。在运行时,加密值被拾取并解密。然后我尝试覆盖 HibernateUtil 中的属性。但即使在解密之后,该值似乎也没有被使用,因为它无法进行身份验证。我该如何让它发挥作用?

public class HibernateUtil {
    private static final SessionFactory sessionFactory;

    private static ServiceRegistry serviceRegistry;

    private static final String keyFile="/keys/.aoo1key";
    static {
        try {
                Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
                String passwordToDecrypt=cfg.getProperty("hibernate.connection.password");
                if(passwordToDecrypt.startsWith("ENC(")&&passwordToDecrypt.endsWith(")")) {
                    passwordToDecrypt = passwordToDecrypt.substring(4,passwordToDecrypt.length()-1);
                    PropertiesEncryption propertiesEncryption = new PropertiesEncryption(keyFile);
                    String decrypted = propertiesEncryption.decryptValue(passwordToDecrypt);
                    cfg.setProperty("hibernate.connection.password", decrypted);
                }

                StandardServiceRegistry standardRegistry = cfg.getStandardServiceRegistryBuilder().build();

                Metadata metaData = new MetadataSources(standardRegistry).getMetadataBuilder().build();
                sessionFactory = metaData.getSessionFactoryBuilder().build();
        } catch (Throwable th) {

            System.err.println("Enitial SessionFactory creation failed" + th);

            throw new ExceptionInInitializerError(th);

        }
    }

    public static SessionFactory getSessionFactory() {

        return sessionFactory;

    }


}

hibernate.cfg.xml

<?xml version='1.0' encoding='utf-8'?>
<!DOCTYPE hibernate-configuration PUBLIC
"-//Hibernate/Hibernate Configuration DTD//EN"
"http://www.hibernate.org/dtd/hibernate-configuration">

<hibernate-configuration>
<session-factory>


<property name="hibernate.connection.driver_class">com.mysql.jdbc.Driver</property>
<property name="hibernate.connection.url">jdbc:mysql://localhost:3306/hibernate5</property>
<property name="hibernate.connection.username">root</property>
 <!--  <property name="hibernate.connection.password">dog</property>   -->
<property name="hibernate.connection.password">ENC(MYFBqlDom8ZawVi+toB3PU0MdI10Desvsq4D2Z5lejk=)</property>
<property name="hibernate.connection.pool_size">10</property>
<property name="show_sql">true</property>
<property name="hibernate.dialect">org.hibernate.dialect.MySQLDialect</property>
<property name="hibernate.current_session_context_class">thread</property>

<mapping class="net.model.Employee" />

</session-factory>
</hibernate-configuration>

异常

Enitial SessionFactory creation failedorg.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
Exception in thread "main" java.lang.ExceptionInInitializerError
    at net.roseindia.HibernateUtil.<clinit>(HibernateUtil.java:66)
    at net.roseindia.GetAllData.main(GetAllData.java:18)
Caused by: org.hibernate.service.spi.ServiceException: Unable to create requested service [org.hibernate.engine.jdbc.env.spi.JdbcEnvironment]
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:271)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:233)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
    at org.hibernate.engine.jdbc.internal.JdbcServicesImpl.configure(JdbcServicesImpl.java:51)
    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:94)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:242)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.handleTypes(MetadataBuildingProcess.java:352)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.complete(MetadataBuildingProcess.java:111)
    at org.hibernate.boot.model.process.spi.MetadataBuildingProcess.build(MetadataBuildingProcess.java:83)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:418)
    at org.hibernate.boot.internal.MetadataBuilderImpl.build(MetadataBuilderImpl.java:87)
    at net.roseindia.HibernateUtil.<clinit>(HibernateUtil.java:60)
    ... 1 more
Caused by: org.hibernate.exception.JDBCConnectionException: Error calling Driver#connect
    at org.hibernate.engine.jdbc.connections.internal.BasicConnectionCreator$1$1.convert(BasicConnectionCreator.java:105)
    at org.hibernate.engine.jdbc.connections.internal.BasicConnectionCreator.convertSqlException(BasicConnectionCreator.java:123)
    at org.hibernate.engine.jdbc.connections.internal.DriverConnectionCreator.makeConnection(DriverConnectionCreator.java:41)
    at org.hibernate.engine.jdbc.connections.internal.BasicConnectionCreator.createConnection(BasicConnectionCreator.java:58)
    at org.hibernate.engine.jdbc.connections.internal.PooledConnections.addConnections(PooledConnections.java:123)
    at org.hibernate.engine.jdbc.connections.internal.PooledConnections.<init>(PooledConnections.java:42)
    at org.hibernate.engine.jdbc.connections.internal.PooledConnections.<init>(PooledConnections.java:20)
    at org.hibernate.engine.jdbc.connections.internal.PooledConnections$Builder.build(PooledConnections.java:161)
    at org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl.buildPool(DriverManagerConnectionProviderImpl.java:109)
    at org.hibernate.engine.jdbc.connections.internal.DriverManagerConnectionProviderImpl.configure(DriverManagerConnectionProviderImpl.java:72)
    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.configureService(StandardServiceRegistryImpl.java:94)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.initializeService(AbstractServiceRegistryImpl.java:242)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.getService(AbstractServiceRegistryImpl.java:210)
    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.buildJdbcConnectionAccess(JdbcEnvironmentInitiator.java:145)
    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:66)
    at org.hibernate.engine.jdbc.env.internal.JdbcEnvironmentInitiator.initiateService(JdbcEnvironmentInitiator.java:35)
    at org.hibernate.boot.registry.internal.StandardServiceRegistryImpl.initiateService(StandardServiceRegistryImpl.java:88)
    at org.hibernate.service.internal.AbstractServiceRegistryImpl.createService(AbstractServiceRegistryImpl.java:259)
    ... 13 more
Caused by: java.sql.SQLException: Access denied for user 'root'@'localhost' (using password: YES)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:1055)
    at com.mysql.jdbc.SQLError.createSQLException(SQLError.java:956)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3491)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:3423)
    at com.mysql.jdbc.MysqlIO.checkErrorPacket(MysqlIO.java:910)
    at com.mysql.jdbc.MysqlIO.secureAuth411(MysqlIO.java:3923)
    at com.mysql.jdbc.MysqlIO.doHandshake(MysqlIO.java:1273)
    at com.mysql.jdbc.ConnectionImpl.createNewIO(ConnectionImpl.java:2031)
    at com.mysql.jdbc.ConnectionImpl.<init>(ConnectionImpl.java:718)
    at com.mysql.jdbc.JDBC4Connection.<init>(JDBC4Connection.java:46)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:62)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:423)
    at com.mysql.jdbc.Util.handleNewInstance(Util.java:406)
    at com.mysql.jdbc.ConnectionImpl.getInstance(ConnectionImpl.java:302)
    at com.mysql.jdbc.NonRegisteringDriver.connect(NonRegisteringDriver.java:282)
    at org.hibernate.engine.jdbc.connections.internal.DriverConnectionCreator.makeConnection(DriverConnectionCreator.java:38)
    ... 28 more

最佳答案

我发现如果我把它分解成步骤,我就能让它做我想做的事。我在实例化 StandardServiceRegistry 的同时进行构建。这似乎是我的代码的主要问题。另外,我发现我应该使用 standardServiceRegistryBuilder.applySetting 设置解密的密码,而不是使用 Configuration 对象。

StandardServiceRegistry standardRegistry = cfg.getStandardServiceRegistryBuilder().build();

它的工作原理是这样的

public class HibernateUtil {
    private static StandardServiceRegistry serviceRegistry;
    private static SessionFactory sessionFactory =buildSessionFactory();
    private static final String keyFile="/keys/.aoo1key";

     // Hibernate 5:
    private static SessionFactory buildSessionFactory() {
        try {
            Configuration cfg = new Configuration().configure("hibernate.cfg.xml");
            // Create the ServiceRegistry from hibernate.cfg.xml
            StandardServiceRegistryBuilder standardServiceRegistryBuilder = cfg.getStandardServiceRegistryBuilder();
            //Get the encrypted value
            String passwordToDecrypt=cfg.getProperty("hibernate.connection.password");
            //Test if it is encrypted
            if(passwordToDecrypt.startsWith("ENC(")&&passwordToDecrypt.endsWith(")")) {
                //Stripping "ENC(" and ")" 
                passwordToDecrypt = passwordToDecrypt.substring(4,passwordToDecrypt.length()-1);
                //TODO Key file is the key to use for decrytion, the name of my class PropertiesEncryption is kind of bad, what should I call it?
                PropertiesEncryption propertiesEncryption = new PropertiesEncryption(keyFile);
                String decrypted = propertiesEncryption.decryptValue(passwordToDecrypt);
                //Overwrite the encrypted value
                standardServiceRegistryBuilder.applySetting("hibernate.connection.password", decrypted);
            }


            //This will build even if the password wasn't never encrypted
            serviceRegistry =standardServiceRegistryBuilder.build();
            // Create a metadata sources using the specified service registry.
            Metadata metadata = new MetadataSources(serviceRegistry).getMetadataBuilder().build();

            return metadata.getSessionFactoryBuilder().build();
        } catch (Throwable ex) {

            if (serviceRegistry != null) {
                StandardServiceRegistryBuilder.destroy(serviceRegistry);
             }

            throw new ExceptionInInitializerError(ex);
        }
    }

    public static SessionFactory getSessionFactory() {
        return sessionFactory;
    }

    public static void shutdown() {
        // Close caches and connection pools
       // getSessionFactory().close();
        if (serviceRegistry != null) {
            StandardServiceRegistryBuilder.destroy(serviceRegistry);
        }
    }
}

关于java - 如何在 hibernate.cfg.xml 中将 hibernate.connection.password 设置为加密值,然后将其解密以在配置中使用?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51736887/

相关文章:

java - Android 异常(不受信任的服务器证书): https XML request with server authentication

java - Hibernate 拦截器和事件监听器

java - 将多对多关系保存在相应的映射表中

laravel - 是否可以使用每个用户不同的 APP_KEY 来加密 Laravel 中的数据?

c++ - 使用公钥 X509 V3 (PKCS7) 使用 AES 128 模式 cbc 加密文件

php - 加密数据库

java - Jaxb marshall 抽象类而不是唯一类

java - 对java中 protected 成员的行为感到困惑

javax.mail.AuthenticationFailedException Java 邮件

java - 无法创建交易异常 : Could not open Hibernate Session for transaction