使用 SSH java 连接到数据库

connect to DB using SSH java

我尝试在 java 中连接到 Oracle DB,但我遇到了错误,我搜索了很多次都没有找到帮助我的东西。

当我尝试使用 SQL 开发人员进行连接时,它成功了。

所以我尝试编写 java 代码来访问数据库,它成功连接到 SSH,但是当到达 conn = DriverManager.getConnection:

时我遇到了错误

"java.sql.SQLException: Io exception: Oracle Error ORA-12650"

这是我的功能

public static Connection sshTunel() {
        String sshHost = "sshHost";
        String sshuser = "sshUser";
        String SshKeyFilepath =
            "pathOfKey";
        Session session;
        int localPort = 22;
        String remoteHost = "HostIp";
        int remotePort = 1521;
        String usr = "DB user";
        String pwd = "DB pass";
        try {
            java.util.Properties config = new java.util.Properties();
            JSch jsch = new JSch();
            session = jsch.getSession(sshuser, sshHost, 22);
            jsch.addIdentity(SshKeyFilepath, "ssh Pass");
            config.put("StrictHostKeyChecking", "no");
            config.put("Compression", "yes");
            config.put("ConnectionAttempts", "2");
            session.setConfig(config);
            session.connect();

            System.out.println("SSH Connected ...");

            int assinged_port =
                session.setPortForwardingL(localPort, remoteHost, remotePort);

            System.out.println("localhost:" + assinged_port + " -> " +
                               remoteHost + ":" + remotePort);
            System.out.println("Port Forwarded ...");
            try {
                Class.forName("oracle.jdbc.pool.OracleDataSource");

                conn =
DriverManager.getConnection("jdbc:oracle:thin:@remoteHost:1521/SID",
                            "DB User", "DB Pass");
            } catch (SQLException ex) {
                ex.printStackTrace();
                System.out.println("Error in connection");
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return conn;
    }

SSH 连接到端口 22。隧道的本地端口应该是一个不同的非保留端口,例如61521.

然后您使用 SQL*Net URL 中的本地地址和端口进行连接。

所以只显示相关部分:

    int localPort = 61521;
    String remoteHost = "HostIp";
    int remotePort = 1521;
    ...
    try {
        java.util.Properties config = new java.util.Properties();
        JSch jsch = new JSch();
        session = jsch.getSession(sshuser, sshHost, 22);
        ...
        session.setConfig(config);

        session.connect();

        System.out.println("SSH Connected ...");

        int assinged_port =
            session.setPortForwardingL(localPort, remoteHost, remotePort);

        System.out.println("localhost:" + assinged_port + " -> " +
                           remoteHost + ":" + remotePort);

        try {
            Class.forName("oracle.jdbc.pool.OracleDataSource");

            conn = DriverManager.getConnection(
                       "jdbc:oracle:thin:@localhost:61521/service_name",
                       "DB User", "DB Pass");
        } catch (SQLException ex) {
        ...

在您的 SQL Developer 屏幕截图中,我希望第一个主机值是您的远程主机,即您的代码中实际存在的任何“sshHost”; SSH 在端口 22 上联系。第二个主机和端口值是如何通过 通过 SSH 会话到达数据库侦听器,而不是您。 ('localhost' 有远程服务器; 将其视为本地主机,并到达环回地址 127.0.0.1)。通过单选按钮选择,SSH 连接正在分配自己的本地端口,并连接到该端口,您真的不需要知道它有什么价值。

在您的代码中,此调用:

jsch.getSession(sshuser, sshHost, 22);

这相当于 SQL 开发人员对话框中的第一个主机和端口。同样,sshHost 是第一个主机框中的值。

然后这个调用:

session.setPortForwardingL(localPort, remoteHost, remotePort);

相当于 SQL 开发人员屏幕截图中的第二个主机和端口部分。这里,remoteHost是主机值,可能是localhostremotePort为端口值,即1521。

这与 SQL 开发人员设置的不同之处在于 localPort 值。在自动分配的 SQL 开发人员中(因为您选择了 'automatically assign local port')。在您的代码中,您指定的是您自己,并且该值必须是非保留端口。

因此,只需使用相关部分,您就可以执行以下操作:

jsch.getSession(sshuser, 'your_remote_host', 22);
session.connect();
session.setPortForwardingL(61521, 'localhost', 1521);
DriverManager.getConnection(
                   "jdbc:oracle:thin:@localhost:61521/service_name"

可能有点令人困惑,因为有两个地方提到了 localhost,而且它们的意思似乎略有不同。那是因为它是保留在计算机中的特殊环回地址(因此 'local')。您可以将第一个(在 setPortForwaringL 中)视为远程服务器对自身的内部引用;第二个(在 getConnection() 中)作为您的 PC 对 自身 .

的内部引用

更令人困惑的是,您的屏幕截图显示了两个主机值的 localhost。如果那是您真正拥有的,那么它就没有多大意义,您根本不需要 SSH。所以,我想你更改了真实值以隐藏它以供发布,并且只是选择了一个令人困惑的假值,而不是使用 sshHosthostIP 或类似的。