通過(guò)SFtp的方式訪(fǎng)問(wèn)服務(wù)器的文件,一定程度上對(duì)服務(wù)器的安全性而言有比較大的提升。比方說(shuō):服務(wù)器只開(kāi)啟部分目錄下的訪(fǎng)問(wèn)權(quán)限,或者只開(kāi)啟讀權(quán)限等。
引入依賴(lài)
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.54</version>
</dependency>
常見(jiàn)的有兩種登錄方式:
1. ip賬號(hào)密碼
2.密鑰key方式
代碼及方法
package com.hf.zuul.zuul.sftps;
import com.jcraft.jsch.*;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
import java.util.Properties;
import java.util.Vector;
/**
* @author hanfei
* @Date 2020/8/23
*/
public class SFtpMethod {
private ChannelSftpsftp;
? ? private Sessionsession;
? ? private Stringip;
? ? private int port;
? ? private StringuserName;
? ? private Stringpassword;
? ? private static final StringfolderPath ="/usr/local/20200805";
? ? private static final StringfileName ="check_credit_apply__mcaus_6eqfy";
? ? public SFtpMethod(String ip, int port, String userName, String password) {
this.ip = ip;
? ? ? ? this.port = port;
? ? ? ? this.userName = userName;
? ? ? ? this.password = password;
? ? }
/**
* 連接服務(wù)器,賬號(hào)密碼
*/
? ? public void connection(){
JSch jSch =new JSch();
? ? ? ? try {
session = jSch.getSession(userName, ip, port);
? ? ? ? ? ? session.setPassword(password);
? ? ? ? ? ? Properties properties =new Properties();
? ? ? ? ? ? properties.put("StrictHostKeyChecking", "no");
? ? ? ? ? ? session.setConfig(properties);
? ? ? ? ? ? session.connect();
? ? ? ? ? ? sftp = (ChannelSftp)session.openChannel("sftp");
? ? ? ? ? ? sftp.connect();
? ? ? ? }catch (JSchException e) {
e.printStackTrace();
? ? ? ? }
}
/**
* 連接服務(wù)器,密鑰方式
? ? * @param passphrase? ? 密鑰口令
? ? * @param keyFile? 密鑰路徑
*/
? ? public void connection(String passphrase, String keyFile){
JSch jSch =new JSch();
? ? ? ? try {
????????????jSch.addIdentity(keyFile);
? ? ? ? ? ? UserInfo userInfo =new MyUserInfo(passphrase);
? ? ? ? ? ? session = jSch.getSession(userName, ip, port);
? ? ? ? ? ? session.setUserInfo(userInfo);
? ? ? ? ? ? session.setTimeout(300000);
? ? ? ? ? ? Properties properties =new Properties();
? ? ? ? ? ? properties.put("StrictHostKeyChecking", "no");
? ? ? ? ? ? session.setConfig(properties);
? ? ? ? ? ? session.connect();
? ? ? ? ? ? sftp = (ChannelSftp)session.openChannel("sftp");
? ? ? ? ? ? sftp.connect();
? ? ? ? }catch (JSchException e) {
e.printStackTrace();
? ? ? ? }
}
/**
* 獲取所有文件名
*/
? ? public ListgetAllFileNames(){
connection();
? ? ? ? List fileNames =new ArrayList<>();
? ? ? ? try {
Vector entries =sftp.ls(folderPath);
? ? ? ? ? ? for (ChannelSftp.LsEntry entrie :entries) {
String name = entrie.getFilename();
? ? ? ? ? ? ? ? if (!".".equals(name) && !"..".equals(name)) {
fileNames.add(name);
? ? ? ? ? ? ? ? }
}
}catch (SftpException e) {
e.printStackTrace();
? ? ? ? }finally {
close();
? ? ? ? }
return fileNames;
? ? }
/**
* 獲取所有文件名,密鑰方式
*/
? ? public ListgetAllFileNames(String passphrase, String keyFile){
connection(passphrase, keyFile);
? ? ? ? List fileNames =new ArrayList<>();
? ? ? ? try {
Vector entries =sftp.ls(folderPath);
? ? ? ? ? ? for (ChannelSftp.LsEntry entrie :entries) {
String name = entrie.getFilename();
? ? ? ? ? ? ? ? if (!".".equals(name) && !"..".equals(name)) {
fileNames.add(name);
? ? ? ? ? ? ? ? }
}
}catch (SftpException e) {
e.printStackTrace();
? ? ? ? }finally {
close();
? ? ? ? }
return fileNames;
? ? }
/**
* 按行讀取文件
? ? * @return
? ? */
? ? public ListreadByLine(){
connection();
? ? ? ? List lines =new ArrayList<>();
? ? ? ? try {
sftp.cd(folderPath);
? ? ? ? ? ? InputStream in =sftp.get(fileName);
? ? ? ? ? ? BufferedReader buffer =new BufferedReader(new InputStreamReader(in));
? ? ? ? ? ? String line ="";
? ? ? ? ? ? while ((line = buffer.readLine()) !=null) {
lines.add(line);
? ? ? ? ? ? }
}catch (SftpException | IOException e) {
e.printStackTrace();
? ? ? ? }finally {
close();
? ? ? ? }
return lines;
? ? }
/**
* 下載文件
? ? * @param localDir
? ? * @return
? ? */
? ? public FiledownLoadFile(String localDir){
connection();
? ? ? ? File file =null;
? ? ? ? OutputStream out;
? ? ? ? try {
file =new File(localDir);
? ? ? ? ? ? sftp.cd(folderPath);
? ? ? ? ? ? out =new FileOutputStream(file);
? ? ? ? ? ? sftp.get(fileName, out);
? ? ? ? }catch (SftpException | FileNotFoundException e) {
e.printStackTrace();
? ? ? ? }finally {
close();
? ? ? ? }
return file;
? ? }
public void close(){
if (sftp !=null) {
sftp =null;
? ? ? ? }
if (session !=null) {
session =null;
? ? ? ? }
}
public static void main(String[] args) {
SFtpMethod sFtpMethod =new SFtpMethod("",22,"","");
? ? ? ? // 顯示所有文件名
? ? ? ? List fileNames = sFtpMethod.getAllFileNames();
? ? ? ? for (String fileName : fileNames) {
System.out.println(fileName);
? ? ? ? }
//? ? ? ? // 按行讀取文件輸出
? ? ? ? List lines = sFtpMethod.readByLine();
? ? ? ? for (String line : lines) {
System.out.println(line);
? ? ? ? }
//? ? ? ? // 下載文件
? ? ? ? sFtpMethod.downLoadFile("/Users/Downloads/check_credit_apply__mcaus_6eqfy");
//? ? ? ? // 密鑰方式
? ? ? ? List fileNamess = sFtpMethod.getAllFileNames("","");
? ? ? ? for (String fileName : fileNamess) {
System.out.println(fileName);
? ? ? ? }
}
/**
* 身份信息
*/
? ? class MyUserInfoimplements UserInfo{
private Stringpassphrase;
? ? ? ? public MyUserInfo(String passphrase) {
this.passphrase = passphrase;
? ? ? ? }
@Override
? ? ? ? public StringgetPassphrase() {
return null;
? ? ? ? }
@Override
? ? ? ? public StringgetPassword() {
return null;
? ? ? ? }
@Override
? ? ? ? public boolean promptPassword(String s) {
return false;
? ? ? ? }
@Override
? ? ? ? public boolean promptPassphrase(String s) {
return false;
? ? ? ? }
@Override
? ? ? ? public boolean promptYesNo(String s) {
return false;
? ? ? ? }
@Override
? ? ? ? public void showMessage(String s) {
}
}
}
通過(guò)秘鑰方式進(jìn)行sftp連接,需要在本地生成秘鑰:ssh-keygen,然后一路回車(chē)或兩次輸入passphrase。接著在.ssh文件夾下使用命令 ssh-copy-id 賬號(hào)@118.XX.XX.XX(目標(biāo)服務(wù)器ip),將公鑰加入到目標(biāo)服務(wù)器的authorized_keys中,接著登錄服務(wù)器進(jìn)行.ssh目錄,chmod 664 authorized_keys,賦予權(quán)限。如果是mac系統(tǒng)可以使用ssh-keygen -e。
秘鑰文件路徑keyFile是本地的私鑰路徑(包含文件名)。下面簡(jiǎn)單驗(yàn)證一下:
我保持本地私鑰文件位置正確的情況下,改變服務(wù)器的私鑰位置或名字,仍能夠正常訪(fǎng)問(wèn)。

在秘鑰驗(yàn)證時(shí),我將keyFile路徑設(shè)置為一個(gè)本地不存在的文件的路徑,報(bào)錯(cuò)如下:

我再把參數(shù)keyFile變?yōu)橐粋€(gè)本地存在的文件,但不是私鑰文件位置。報(bào)錯(cuò)如下:

我將passphrase參數(shù)設(shè)置任意一個(gè)值,還是可以成功連接。這一點(diǎn)很疑惑,不知道為啥,但成功了就高興。
?properties.put("StrictHostKeyChecking", "no");StrictHostKeyChecking有三種選項(xiàng),no、ask、yes。這三個(gè)選項(xiàng)代表了不同的級(jí)別,yes最高,no最低。在ssh訪(fǎng)問(wèn)服務(wù)器的過(guò)程中,會(huì)將服務(wù)器的公鑰保存到本地的~/.ssh/known_hosts中,每次訪(fǎng)問(wèn)服務(wù)器都會(huì)檢查此公鑰是否發(fā)生變化,如果發(fā)生了變化,則這三個(gè)選項(xiàng)的設(shè)置如下:
no:自動(dòng)將服務(wù)器新的公鑰保存到known_hosts中,并發(fā)出一個(gè)警告;
ask:拒絕連接到服務(wù)器,且發(fā)出一個(gè)警告;
yes:拒絕連接到服務(wù)器,且不發(fā)出警告;
一般在測(cè)試環(huán)境下使用no,生產(chǎn)環(huán)境使用yes或ask。