Spring boot + JPA источник динамических данных - PullRequest
0 голосов
/ 18 марта 2019

У меня есть ситуация, когда мне нужно создать соединение БД на основе пользовательского ввода, и это созданное соединение должно использоваться для всех транзакций, пока этот конкретный пользователь не выйдет из системы. Мне нужно сделать это в Spring boot + JPA. По умолчанию я беру информацию о соединении из файла yaml при запуске сервера.

Я запутался, как создать новый источник данных и использовать его для всей сессии.

Я новичок в весенней загрузке и JPA. Может кто-нибудь, пожалуйста, помогите мне с примером.

1 Ответ

0 голосов
/ 19 марта 2019

Это не быстрое решение, и для правильной реализации может потребоваться день или около того, но использование Oracle proxy-соединения дает вам скоростьобычный пул JDBC, но каждый пользователь будет иметь свои определенные права на базу данных.Журналы аудита также подберут пользователя, на которого ссылаются.

Пользователь, вошедший в Spring, используется для определения, какой пользователь должен использовать прокси.

Вам понадобятся две зависимости, загруженные со страницы Oracle JDBC .Убедитесь, что версии совпадают.Установите их в своем репозитории Maven.

<dependency>
    <groupId>com.oracle.jdbc</groupId>
    <artifactId>ucp</artifactId>
    <version>12.2.0.1.0</version>
</dependency>
<dependency>
    <groupId>com.oracle.jdbc</groupId>
    <artifactId>ojdbc8</artifactId>
    <version>12.2.0.1.0</version>
    <scope>provided</scope>
</dependency>

Предоставьте источник данных для Spring.

import oracle.ucp.UniversalConnectionPool;
import oracle.ucp.UniversalConnectionPoolAdapter;
import oracle.ucp.admin.UniversalConnectionPoolManager;
import oracle.ucp.admin.UniversalConnectionPoolManagerImpl;
import oracle.ucp.jdbc.PoolDataSource;
import oracle.ucp.jdbc.PoolDataSourceFactory;

@Bean
@SneakyThrows
public DataSource dataSource() throws SQLException {
    final PoolDataSource pds = PoolDataSourceFactory.getPoolDataSource();
    UniversalConnectionPoolManager mgr = UniversalConnectionPoolManagerImpl.getUniversalConnectionPoolManager();

    pds.registerConnectionLabelingCallback(new MyProxyConnectionLabelingCallback("MY_NOPRIV"));//you can make this any name you want
    DataSource result = new ProxyDelegatingDataSource(pds, getNoPrivilegesUser());

    mgr.createConnectionPool((UniversalConnectionPoolAdapter) pds);
    mgr.startConnectionPool(PROXY_UCP_NAME);
    return result;
}

Реализуйте ConnectionLabelingCallback и поймите, сколько это стоит.

import java.sql.SQLException;
import java.util.Properties;
import java.util.concurrent.TimeUnit;
import oracle.jdbc.OracleConnection;
import oracle.ucp.ConnectionLabelingCallback;
import oracle.ucp.jdbc.LabelableConnection;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;

public class MyProxyConnectionLabelingCallback implements ConnectionLabelingCallback {

    public static final String USER_PROXY = "USER_PROXY";

    private final String noPrivilegesUser;

    public ProxyConnectionLabelingCallback(String noPrivilegesUser) {
        this.noPrivilegesUser = noPrivilegesUser;
    }

    @Override
    public int cost(Properties reqLabels, Properties currentLabels) {
        final Object request = reqLabels.get(USER_PROXY);
        final Object current = currentLabels.get(USER_PROXY);
        if (request.equals(current)) {
            //Same user
            return 0;
        }
        if (noPrivilegesUser.equals(current)) {
            //No Priv User. No Little Cost
            return 1;
        }
        //Different user request

        return 1000;
    }

    @Override
    public boolean configure(Properties reqLabels, Object conn) {
        try {
            LabelableConnection lConn = (LabelableConnection) conn;
            String userName = getUserName(noPrivilegesUser);
            final Properties connectionLabels = lConn.getConnectionLabels();
            if (connectionLabels == null) {
                setProxy((OracleConnection) conn, noPrivilegesUser, userName, null);
                lConn.applyConnectionLabel(USER_PROXY, userName);
                return true;
            }
            Object currentLabel = connectionLabels.get(USER_PROXY);
            if (!userName.equals(currentLabel)) {
                setProxy((OracleConnection) conn, currentLabel, userName, null);
                lConn.applyConnectionLabel(USER_PROXY, userName);
            } else {
                //Label match, good
            }
            return true;
        } catch (SQLException| RuntimeException sExp) {
            return false;
        }
    }

    public static String getUserName(String noPrivilegesUser) {
        final Authentication authentication = SecurityContextHolder.getContext().getAuthentication();// you are logged with this user using Spring Security
        if ((authentication == null)) {
            //Not logged in returning non privileged user
            return noPrivilegesUser;
        }
        Object principal = authentication.getPrincipal();
        if (principal.equals("anonymousUser")) {
            //Not logged in returning non privileged user
            return noPrivilegesUser;
        }
        if (principal instanceof UserDetails) {
            final String username = ((UserDetails) (principal)).getUsername();
            //proxy connection to user  username
            return username;
        } else {
            return principal.toString();
        }
    }

    public void setProxy(OracleConnection oraCon, Object currentLabel, String proxyUserName, String proxyPassword) throws SQLException {
        if (oraCon.isProxySession()) {
            oraCon.close(OracleConnection.PROXY_SESSION);
        }

        Properties proxyProperties = new Properties();
        proxyProperties.setProperty(OracleConnection.PROXY_USER_NAME, proxyUserName);
        if (proxyPassword != null) {
            proxyProperties.setProperty(OracleConnection.PROXY_USER_PASSWORD, proxyPassword);
        }
        //below is what can take a few ms
        oraCon.openProxySession(OracleConnection.PROXYTYPE_USER_NAME, proxyProperties);
    }
}


import java.sql.Connection;
import java.sql.SQLException;
import java.util.Properties;
import oracle.ucp.jdbc.PoolDataSource;
import org.springframework.jdbc.datasource.DelegatingDataSource;

class ProxyDelegatingDataSource extends DelegatingDataSource {

    private final PoolDataSource pds;
    private final String noPrivilegesUser;

    public ProxyDelegatingDataSource(PoolDataSource pds, String noPrivilegesUser) {
        super(pds);
        this.pds = pds;
        this.noPrivilegesUser = noPrivilegesUser;
    }

    @Override
    public Connection getConnection() throws SQLException {
        Properties prprts = new Properties();
        prprts.put(ProxyConnectionLabelingCallback.USER_PROXY, getUserName());
        return getConnection(prprts);
    }

    public Connection getConnection(Properties prprts) throws SQLException {
        return pds.getConnection(prprts);
    }

    public Connection getConnection(String username, String password, Properties prprts) throws SQLException {
        return pds.getConnection(username, password, prprts);
    }

    private String getUserName() {
        return ProxyConnectionLabelingCallback.getUserName(noPrivilegesUser);
    }

}

Настройка Oracle privs:

create user JDBCPROXY identified by pass123;
create user MY_NOPRIV identified by pass123;
GRANT CONNECT TO JDBCPROXY;
GRANT CONNECT TO MY_NOPRIV;

alter user MY_NOPRIV grant connect through JDBCPROXY;
alter user USER1 grant connect through JDBCPROXY;

Когда пул создастся, все пользователи подключатся как JDBCPROXY, проксируемый как MY_NOPRIV.Когда «USER1» входит в систему, он переключается на JDBCPROXY, проксифицированный как USER1.

Настройте безопасность Spring и войдите в систему как «USER1».Я не буду вдаваться в это.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...