springboot使用ssh公钥连接mysql(含账号密码连接)

引言

在项目开发过程中,遇到了连接数据库时需要使用ssh公钥的情况。在本地使用navicat可以直接通过可视化界面去进行ssh的连接,但是在java中无法直接去进行连接。

后来经过查询资料,发现必须要在java中编写相关配置文件后才可以正常连接。

问题解决

原理:程序在本机创建ssh连接,连接到ssh server,然后再发送数据库操作指令,指令会被转发到目标数据库服务器上,返回操作结果

**前提:**项目已经配置好mysql连接所需要参数

**注意:**我演示的是使用ssh的公钥模式进行连接,如果需要使用密码模式进行连接,需要打开和关闭某些注释

  1. 引入依赖

    <dependency>
        <groupId>com.jcraft</groupId>
        <artifactId>jsch</artifactId>
        <version>0.1.55</version>
    </dependency>
    
  2. 编写ssh连接配置类

    package com.lzj.config;
    
    import com.jcraft.jsch.JSch;
    import com.jcraft.jsch.JSchException;
    import com.jcraft.jsch.Session;
    
    import java.util.Properties;
    
    /**
     * <p>
     *  SSH连接配置类
     * </p>
     *
     * @author:雷子杰
     * @date:2023/3/4
     */
    public class SSHConnectionConfig {
          
          
    
        //本地的ssh中的knownhost文件路径
        private String SSH_PATH_FILE_KNOWN_HOSTS = "C:\\Users\\86158\\.ssh\\known_hosts";
        //本地的ssh密钥路径
        private String SSH_PATH_FILE_PRIVATE_KEY = "**********************************";
        //ssh连接的用户名
        private String SSH_USER = "******";
        //ssh远程连接的ip地址
        private String SSH_REMOTE_SERVER = "65.115.26.30";
        //ssh连接的端口号,一般默认为22
        private Integer SSH_REMOTE_PORT = 22;
        //SSH使用密码
        //private String sshPassword;
    
        //本地mysql发起连接的IP地址
        private String MYSQL_REMOTE_SERVER = "127.0.0.1";
        //本地数据库连接时用的端口号(不能填3306)
        private Integer LOCAl_PORT = 3307;
        //远程数据库端口用的端口号
        private Integer REMOTE_PORT = 3309;
    
        //com.jcraft.jsch.Session;
        private Session session;
    
        /**
         * 关闭ssh连接
         */
        public void closeSSH() {
          
          
            session.disconnect();
        }
    
        /**
         * 创建ssh连接
         */
        public void createSSH() throws JSchException {
          
          
            JSch jSch = new JSch();
    
            //下面这两个设置是在公钥模式需要设置的,非公钥模式不需要进行设置
            //设置known_hosts文件路径,如:~/.ssh/known_hosts(known_hosts中存储是已认证的远程主机host key)
            jSch.setKnownHosts(SSH_PATH_FILE_KNOWN_HOSTS);
            //设置私钥
            jSch.addIdentity(SSH_PATH_FILE_PRIVATE_KEY);
    
            session = jSch.getSession(SSH_USER, SSH_REMOTE_SERVER, SSH_REMOTE_PORT);
    
            //如果是密码模式需要设置密码
            //session.setPassword(sshPassword);
    
            //设置连接过程不校验known_hosts文件中的信息
            Properties config = new Properties();
            config.put("StrictHostKeyChecking", "no");
            session.setConfig(config);
    
            //ssh 建立连接!
            session.connect();
    
            //根据安全策略,您必须通过转发端口进行连接
            session.setPortForwardingL(LOCAl_PORT, MYSQL_REMOTE_SERVER, REMOTE_PORT);
        }
    }
    
  3. 编写监听器

    注意:

    1. Listener类使用@WebListener注解;
    2. SpringBoot的启动类需要增加@ServletComponentScan用于扫描加载Listener类;

    经过我的尝试,发现如果使用了@Component注解,就算不使用@WebListener也同样可以完成监听功能

    package com.lzj.config;
    
    import org.springframework.stereotype.Component;
    
    import javax.servlet.ServletContextEvent;
    import javax.servlet.ServletContextListener;
    import javax.servlet.annotation.WebListener;
    
    /**
     * <p>
     *
     * </p>
     *
     * @author:雷子杰
     * @date:2023/3/4
     */
    @Component//尽量加上这个
    @WebListener//声明为监听器
    public class MyContextListener implements ServletContextListener {
          
          
    
        private SSHConnectionConfig sshConnectionConfig;
    
        public MyContextListener() {
          
          
            super();
        }
    
        @Override
        public void contextInitialized(ServletContextEvent sce) {
          
          
            System.out.println("Context initialized ... !");
            try {
          
          
                sshConnectionConfig = new SSHConnectionConfig();
                sshConnectionConfig.createSSH();
            } catch (Throwable e) {
          
          
                e.printStackTrace(); // 连接失败
            }
    
        }
    
        @Override
        public void contextDestroyed(ServletContextEvent sce) {
          
          
            System.out.println("Context destroyed ... !");
            sshConnectionConfig.closeSSH();//断开ssh连接
        }
    }
    
  4. 注意可能需要修改你的mysql连接配置

    可以看见我的的url中的localhost:3307,这个ip和端口号是根据你编写的ssh配置类MYSQL_REMOTE_SERVERLOCAl_PORT来的,你可能需要进行修改

    spring:
      datasource:
        type: com.alibaba.druid.pool.DruidDataSource
        driver-class-name: com.mysql.jdbc.Driver
        username: root
        password: ******
        url: jdbc:mysql://localhost:3307/leopard-vendor_cloud?autoReconnect=true&useUnicode=true&useSSL=false
    
  5. 测试

    编写一个测试类测试数据库的连接

    package com.lzj;
    
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.test.context.junit4.SpringRunner;
    
    import javax.sql.DataSource;
    import java.sql.SQLException;
    
    /**
     * <p>
     *
     * </p>
     *
     * @author:雷子杰
     * @date:2023/3/3
     */
    @SpringBootTest(classes = SpringbootDetabaseApplication.class)
    @RunWith(SpringRunner.class)
    public class InitTest {
          
          
    
        @Autowired
        private DataSource dataSource;
    
        @Test
        public void testDataSource() throws SQLException {
          
          
    
            System.out.println(dataSource.getConnection());
        }
    }
    

    测试结果如下:

    image-20230304155236024

    可以发现控制台正常输出了连接相关信息

总结

image-20230304160003390

**注意:**数据库连接地址由原来的123.mysql.com:3306改为127.0.0.1:3307,这样子,ssh连接会为每一个127.0.0.1:3307上的操作转发到123.mysql.com:3306上去,便可以正常操作数据库了。ssh连接的创建,可以采用私钥的方式,亦可以采用用户名密码的方式。

参考文章

猜你喜欢

转载自blog.csdn.net/qq_49137582/article/details/129335722