?
如果大家熟悉Linux的話,一定對(duì)ssh,sftp,scp等命令非常熟悉。ssh是一個(gè)安全協(xié)議,用來(lái)在不同系統(tǒng)或者服務(wù)器之間進(jìn)行安全連接。ssh 在連接和傳送的過(guò)程中會(huì)加密所有的數(shù)據(jù)。具體的解釋,大家可以參考百度百科的文檔。地址為:http://baike.baidu.com/view/16184.htm
但是SSH一般是基于客戶端的或者Linux命令行的。比如客戶端的工具:OpenSSH,putty,SSH Tectia;在linux上大家可以通過(guò)ssh username@host連接到所要想連接的主機(jī)。但是如果在J2EE中,如何實(shí)現(xiàn)SSH呢?進(jìn)而可以實(shí)現(xiàn)SCP,SFTP的功能呢?下面介紹的JSCH就可以實(shí)現(xiàn)下邊的功能。
JSCH是一個(gè)純粹的用java實(shí)現(xiàn)SSH功能的java ?library. 官方地址為:http://www.jcraft.com/jsch/
GitHub 地址為:https://github.com/vngx/vngx-jsch
mvn 配置如下:
<dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.46</version> </dependency>
?
下面簡(jiǎn)單介紹下JSCH的特點(diǎn):
1.基于DSA和RSA加密。
2.可以實(shí)現(xiàn)4中認(rèn)證機(jī)制。分別是:
(1i): password
(2i): publickey(DSA,RSA)
(3i): keyboard-interactive
(4i): gss-api-with-mic
3.生成public/private key pair.
4.執(zhí)行bash script 等腳本
5.可以通過(guò)HTTP/SOCK5 proxy
6.支持常見(jiàn)SSH1協(xié)議和SSH2協(xié)議
我們?nèi)粘S玫降腏SCH主要是基于是密碼認(rèn)證和private key 認(rèn)證。
基于密碼認(rèn)證的比較簡(jiǎn)單。簡(jiǎn)單代碼如下:
?
?
public class JschHandler { private static final Logger log = LoggerFactory.getLogger(JschHandler.class); public static final String SFTP_PROTOCAL = "sftp"; private String username; private String host; private int port; private String identity; private UserInfo userInfo; private JSch jsch = null; protected Session session = null; private boolean firstInit = false; private int authType = -1; /** * Private/public key authorization * @param username user account * @param host server host * @param port ssh port * @param identity the path of private key file. * @see http://www.jcraft.com/jsch/ */ public JschHandler(String username,String host,int port,String identity){ this.username = username; this.host = host; this.port = port; this.identity = identity; firstInit = false; jsch = new JSch(); authType = 0 ; } /** * Password authorization * @param username * @param host * @param port * @param userInfo User information for authorization * @see com.jcraft.jsch.UserInfo * @see http://www.jcraft.com/jsch/ */ public JschHandler(String username,String host,int port,UserInfo userInfo){ this.username = username; this.host = host; this.port = port; this.userInfo = userInfo; firstInit = false; jsch = new JSch(); authType = 1; } /** * * Initialize SSH session. * When the parameters is not right, It will throw an JSchException. * @throws MessageServicerException * @see com.jcraft.jsch.JSch */ @SuppressWarnings("static-access") protected void init() throws JSchException{ try { validate(); log.info("JSCH identity:"+identity); jsch.setLogger(new JschLogger()); jsch.setConfig("StrictHostKeyChecking", "no"); if(authType==0) jsch.addIdentity(identity); session = jsch.getSession(username, host, port); if(authType==1) session.setUserInfo(userInfo); session.connect(); log.info("JSCH session connect success."); } catch (JSchException e) { log.error(e.getMessage()); throw e; } } /** * Validate parameters * @throws JSchException */ private void validate() throws JSchException{ if(firstInit) return; if(username==null||username.isEmpty()){ throw new JSchException("Parameter:username is empty."); } if(host==null||host.isEmpty()){ throw new JSchException("Parameter:host is empty."); }else{ try { InetAddress inet = InetAddress.getByName(host); host = inet.getHostAddress(); log.info("JSCH connection address:"+host); } catch (UnknownHostException e) { throw new JSchException(e.getMessage(),e); } } if(authType==0&&(identity==null||identity.isEmpty())){ throw new JSchException("Parameter:identity is empty."); } if(authType==1&&(userInfo==null)){ throw new JSchException("Parameter:userInfo is empty."); } firstInit = true; } /** * release connections. * @author */ protected void destory(){ if(session!=null) session.disconnect(); log.info("JSCH session destory"); } private static class JschLogger implements com.jcraft.jsch.Logger{ @Override public boolean isEnabled(int level) { return true; } @Override public void log(int level, String message) { System.out.println(String.format("[JSCH --> %s]", message)); } } public void setUserInfo(UserInfo userInfo) { this.userInfo = userInfo; } }
?? ? client
?
public static class MyUserInfo implements UserInfo, UIKeyboardInteractive { public String getPassword() { return null; } public boolean promptYesNo(String str) { Object[] options = { "yes", "no" }; int foo = JOptionPane.showOptionDialog(null, str, "Warning", JOptionPane.DEFAULT_OPTION, JOptionPane.WARNING_MESSAGE, null, options, options[0]); return foo == 0; } String passphrase; JTextField passphraseField = (JTextField) new JPasswordField(20); public String getPassphrase() { return passphrase; } public boolean promptPassphrase(String message) { Object[] ob = { passphraseField }; int result = JOptionPane.showConfirmDialog(null, ob, message, JOptionPane.OK_CANCEL_OPTION); if (result == JOptionPane.OK_OPTION) { passphrase = passphraseField.getText(); return true; } else { return false; } } public boolean promptPassword(String message) { return true; } public void showMessage(String message) { JOptionPane.showMessageDialog(null, message); } final GridBagConstraints gbc = new GridBagConstraints(0, 0, 1, 1, 1, 1, GridBagConstraints.NORTHWEST, GridBagConstraints.NONE, new Insets(0, 0, 0, 0), 0, 0); private Container panel; public String[] promptKeyboardInteractive(String destination, String name, String instruction, String[] prompt, boolean[] echo) { panel = new JPanel(); panel.setLayout(new GridBagLayout()); gbc.weightx = 1.0; gbc.gridwidth = GridBagConstraints.REMAINDER; gbc.gridx = 0; panel.add(new JLabel(instruction), gbc); gbc.gridy++; gbc.gridwidth = GridBagConstraints.RELATIVE; JTextField[] texts = new JTextField[prompt.length]; for (int i = 0; i < prompt.length; i++) { gbc.fill = GridBagConstraints.NONE; gbc.gridx = 0; gbc.weightx = 1; panel.add(new JLabel(prompt[i]), gbc); gbc.gridx = 1; gbc.fill = GridBagConstraints.HORIZONTAL; gbc.weighty = 1; if (echo[i]) { texts[i] = new JTextField(20); } else { texts[i] = new JPasswordField(20); } panel.add(texts[i], gbc); gbc.gridy++; } if (JOptionPane.showConfirmDialog(null, panel, destination + ": " + name, JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE) == JOptionPane.OK_OPTION) { String[] response = new String[prompt.length]; for (int i = 0; i < prompt.length; i++) { response[i] = texts[i].getText(); } return response; } else { return null; // cancel } } }
? @Test
public void testSftp() throws JSchException{ UserInfo userInfo = new MyUserInfo(); JftpHandler jhandler = new JftpHandler("username","hostname",22,userInfo); try { jhandler.init(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } String pwd = null; try { pwd = jhandler.pwd(); } catch (SftpException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(pwd); // jhandler.destory(); }?
基于private key 認(rèn)證的有點(diǎn)費(fèi)時(shí)。關(guān)于如何配置private/public key認(rèn)證,大家通過(guò)google來(lái)配置。簡(jiǎn)單流程如下:
1.在linux 下執(zhí)行ssh-keygen -t dsa /ssh-keygen -t rsa.這樣就會(huì)成一對(duì)對(duì)應(yīng)的public key 和private key.比如id_dsa_1024,id_dsa_1024.pub.
2. 把public key(id_dsa_1024.pub)復(fù)制到想要連接的服務(wù)器上,放到對(duì)應(yīng)用戶的.ssh目錄下。
3.
cd ~/.ssh
#將Client的公鑰放入Server的信任列表
cat id_dsa_1024.pub >> authorized_keys
#更新權(quán)限,很重要
chmod 0600 *從此以后Client SSH登錄Server就不要手工輸入密碼了
配置完成以后,重新登錄一下,就可以發(fā)現(xiàn)不用輸入密碼就可以實(shí)現(xiàn)遠(yuǎn)程登錄了。
由于現(xiàn)在基于SSH協(xié)議的算法很多,加密和解密的算法也不一樣。目前Jsch只支持OpenSSH和SSH 1生成的private/public key.
所以當(dāng)你們發(fā)現(xiàn)不能通過(guò)private/public key認(rèn)證的時(shí)候,不是jsch的問(wèn)題,而是不能識(shí)別的問(wèn)題。
簡(jiǎn)單代碼如下:
?
?
?
@Test public void testSftp() throws JSchException{ JftpHandler jhandler = new JftpHandler("username","hostname",22,"C:\\data\\id_dsa_2048_a"); try { jhandler.init(); } catch (Exception e) { // TODO Auto-generated catch block e.printStackTrace(); } String pwd = null; try { pwd = jhandler.pwd(); } catch (SftpException e) { // TODO Auto-generated catch block e.printStackTrace(); } System.out.println(pwd); // jhandler.destory(); }?
上面只是對(duì)JSCH的簡(jiǎn)單介紹,希望對(duì)大家有所用戶。。。。
更多文章、技術(shù)交流、商務(wù)合作、聯(lián)系博主
微信掃碼或搜索:z360901061

微信掃一掃加我為好友
QQ號(hào)聯(lián)系: 360901061
您的支持是博主寫(xiě)作最大的動(dòng)力,如果您喜歡我的文章,感覺(jué)我的文章對(duì)您有幫助,請(qǐng)用微信掃描下面二維碼支持博主2元、5元、10元、20元等您想捐的金額吧,狠狠點(diǎn)擊下面給點(diǎn)支持吧,站長(zhǎng)非常感激您!手機(jī)微信長(zhǎng)按不能支付解決辦法:請(qǐng)將微信支付二維碼保存到相冊(cè),切換到微信,然后點(diǎn)擊微信右上角掃一掃功能,選擇支付二維碼完成支付。
【本文對(duì)您有幫助就好】元
