java Jsch实现跳板机操作远程数据库
2018年05月04日 11:07:20 一念落叶 阅读数:823
jsch是一个纯java实现的ssh,作用有很多,比如实现一个sftp或者ftp,java执行shell命令等等,今天用做于模拟登陆跳板机然后操作数据库和redis,原理为通过本机的端口进行本地端口转发到跳板机再进行连接mysql,相当于如下命令:
ssh -L 1234:localhost:3306 mysql.server.remote
ssh本地端口转发远程端口转发可参考如下博客:
SSH端口转发(本地端口转发、远程端口转发、动态端口转发)工作原理、应用详解
首先导入maven依赖,数据库用的是mysql
-
<dependency>
-
<groupId>com.jcraft</groupId>
-
<artifactId>jsch</artifactId>
-
<version>0.1.53</version>
-
</dependency>
-
<dependency>
-
<groupId>mysql</groupId>
-
<artifactId>mysql-connector-java</artifactId>
-
<version>5.1.36</version>
-
</dependency>
然后建立一个ssh通道模拟登陆到跳板机
-
public class JDBCSSHChannel {
-
private Session session;
-
private Channel channel;
-
/**
-
*
-
* @param localPort 本地host 建议mysql 3306 redis 6379
-
* @param sshHost ssh host
-
* @param sshPort ssh port
-
* @param sshUserName ssh 用户名
-
* @param sshPassWord ssh密码
-
* @param remotoHost 远程机器地址
-
* @param remotoPort 远程机器端口
-
*/
-
public void goSSH(int localPort, String sshHost, int sshPort,
-
String sshUserName, String sshPassWord,
-
String remotoHost, int remotoPort) {
-
try {
-
JSch jsch = new JSch();
-
//登陆跳板机
-
session = jsch.getSession(sshUserName, sshHost, sshPort);
-
session.setPassword(sshPassWord);
-
session.setConfig("StrictHostKeyChecking", "no");
-
session.connect();
-
//建立通道
-
channel = session.openChannel("session");
-
channel.connect();
-
//通过ssh连接到mysql机器
-
int assinged_port = session.setPortForwardingL(localPort, remotoHost, remotoPort);
-
} catch (Exception e) {
-
e.printStackTrace();
-
}
-
}
-
/**
-
* 关闭
-
*/
-
public void close() {
-
if (session != null && session.isConnected() ) {
-
session.disconnect();
-
}
-
if (channel != null && session.isConnected() ) {
-
channel.disconnect();
-
}
-
}
-
}
如果跳板机是用的秘钥文件的话,可以直接在jsch中add
jsch.addIdentity(sshPrvkey);
其中session中的StrictHostKeyChecking是对public_key的检查等级设置,默认值StrictHostKeyChecking=ask
-
//最不安全的级别,相对安全的内网测试时建议使用。如果连接server的key在本地不存在,那么就自动添加到文件中(默认是known_hosts),并且给出一个警告。
-
session.setConfig("StrictHostKeyChecking", "no");
-
//默认的级别,如果连接和key不匹配,给出提示,并拒绝登录
-
session.setConfig("StrictHostKeyChecking", "ask");
-
//最安全的级别,如果连接与key不匹配,就拒绝连接,不会提示详细信息
-
session.setConfig("StrictHostKeyChecking", "yes");
然后连接mysql,在连接mysql前调用下goSSH方法建立跳板机通道即可,另外,连接数据库的时候ip要用localhost或者127.0.0.1
,相当于连接本地mysql数据库一样。
-
public static Connection connDB() {
-
// 声明Connection对象
-
Connection con = null;
-
// 驱动程序名
-
String driver = "com.mysql.jdbc.Driver";
-
// URL指向要访问的数据库名mydata
-
String url = "jdbc:mysql://localhost:3306/TEST";
-
// MySQL配置时的用户名
-
String user = "root";
-
// MySQL配置时的密码
-
String password = "123456";
-
// 遍历查询结果集
-
try {
-
// 加载驱动程序
-
try {
-
Class.forName(driver);
-
} catch (ClassNotFoundException e) {
-
// TODO Auto-generated catch block
-
e.printStackTrace();
-
}
-
// 1.建立跳板机通道
-
JDBCSSHChannel channel = new JDBCSSHChannel();
-
channel.goSSH(localPort, sshHost, sshPort, sshUserName, sshPassWord,
-
remotoHost,remotoPort);
-
// 2.getConnection()方法,连接MySQL数据库!!
-
con = DriverManager.getConnection(url, user, password);
-
} catch (SQLException e) {
-
// TODO: handle exception
-
e.printStackTrace();
-
}
-
return con;
-
}
至于连接redis同样的原理:
-
public static void main(String[] args) throws JSchException {
-
JDBCSSHChannel channel = new JDBCSSHChannel();
-
channel.goSSH(localPort, sshHost, sshPort, sshUserName, sshPassWord,
-
remotoHost,remotoPort);
-
// 1.建立跳板机通道
-
channel.goSSH(localPort, sshHost, sshPort, sshUserName, sshPassWord, remotoHost,
-
remotoPort);
-
JedisPool jedisPool = new JedisPool(new JedisPoolConfig(), redisHost, redisPort, redisTimeout, redisPassword);
-
JedisCommands jedis = jedisPool.getResource();
-
jedis.get(key);
-
channel.close();
但是redis连接cluster有点问题,只能已alone的模式单个连接cluster,直接连接redis cluster会报错:
java.net.SocketTimeoutException: connect timed out
socket连接超时,可能是我姿势不对,目前cluster模式暂未解决,只能用alone模式代理cluster。
另外用完ssh通道记得关闭。