點擊此處java
<!-- https://mvnrepository.com/artifact/com.jcraft/jsch --> <dependency> <groupId>com.jcraft</groupId> <artifactId>jsch</artifactId> <version>0.1.54</version> </dependency> <!-- https://mvnrepository.com/artifact/ch.ethz.ganymed/ganymed-ssh2 --> <dependency> <groupId>ch.ethz.ganymed</groupId> <artifactId>ganymed-ssh2</artifactId> <version>build210</version> </dependency>
package com.tianshl; import ch.ethz.ssh2.Connection; import ch.ethz.ssh2.Session; import ch.ethz.ssh2.StreamGobbler; import org.springframework.stereotype.Component; import java.io.BufferedReader; import java.io.InputStreamReader; /** * @author tianshl * @version 2018/5/22 下午1:29 */ @Component public class Ssh2Utils { private Connection connection; /** * 登陸 */ public void login(String host, String username, String password) throws Exception { connection = new Connection(host); connection.connect(); if(!connection.authenticateWithPassword(username, password)){ throw new Exception("管理員帳號或密碼錯誤"); } } /** * 退出 */ public void logout() { try { if (connection != null) connection.close(); } catch (Exception e) { e.printStackTrace(); } } /** * 執行指令 */ public String execCommand(final String command) { final StringBuilder sb = new StringBuilder(256); // 鏈接的通道 Session session = null; try { // 建立session session = connection.openSession(); // 這句很是重要,開啓遠程的客戶端 session.requestPTY("vt100", 80, 24, 640, 480, null); // 開啓後睡眠4秒 // Thread.sleep(4000); // 執行命令 session.execCommand(command); // 起始時間,避免連通性陷入死循環 long start = System.currentTimeMillis(); BufferedReader br = new BufferedReader(new InputStreamReader(new StreamGobbler(session.getStdout()))); char[] arr = new char[512]; int read; while (true) { // 將結果流中的數據讀入字符數組 read = br.read(arr, 0, arr.length); // 推延5秒就退出[針對連通性測試會陷入死循環] if (read < 0 || (System.currentTimeMillis() - start) > 5000) break; // 將結果拼裝進StringBuilder sb.append(new String(arr, 0, read)); } } catch (Throwable e) { e.printStackTrace(); } finally { // 關閉通道 if (session != null) session.close(); } return sb.toString(); } }
package com.tianshl; import com.alibaba.fastjson.JSONObject; import com.google.common.collect.Lists; import com.google.common.collect.Maps; import org.springframework.beans.factory.annotation.Value; import org.springframework.stereotype.Service; import org.springframework.transaction.annotation.Transactional; import org.springframework.web.multipart.MultipartFile; import javax.servlet.http.HttpServletResponse; import java.io.*; import java.util.List; import java.util.Map; /** * service for sftp */ @Service @Transactional public class SftpService { // sftp 服務器地址 @Value("${sftp.host}") private String host; // sftp 服務器管理員帳號 @Value("${sftp.root.username}") private String username; // sftp 服務器管理員密碼 @Value("${sftp.root.password}") private String password; // ssh2工具類 private final Ssh2Utils ssh2Utils; public SftpService(Ssh2Utils ssh2Utils) { this.ssh2Utils = ssh2Utils; } /** * 建立linux用戶 建立相關目錄 以及 權限設置 */ private JSONObject createUser (Ssh2Utils ssh2Utils, String sftpUsername) { // 返回信息 JSONObject resp = new JSONObject(); resp.put("success", false); // 家目錄 String home = "/sftp/" + sftpUsername; // 建立帳號 try { // 建立帳號命令 String stdOut = ssh2Utils.execCommand("useradd -d " + home + " -m -g sftp -s /bin/false " + sftpUsername); // 用戶名已存在 if (stdOut.contains("useradd: user '" + sftpUsername + "' already exists")) { ssh2Utils.logout(); resp.put("success", false); resp.put("msg", "帳戶名稱'" + sftpUsername + "'已存在,請更換其餘名稱."); return resp; } List<String> command = Lists.newArrayList(); // 設置家目錄屬主 command.add("chown root:sftp " + home); // 設置家目錄權限 command.add("chmod 755 " + home); // 建立目錄 (.ssh祕鑰相關, data存放數據文件) command.add("mkdir " + home + "/{.ssh,data}"); // 新增的目錄設置屬主 command.add("chown " + sftpUsername + ":sftp " + home + "/{.ssh,data}"); // 新增目錄設置權限 command.add("chmod 777 " + home + "/data"); command.add("chmod 700 " + home + "/.ssh"); // 執行以上指令 ssh2Utils.execCommand(String.join(";", command)); } catch (Exception e) { e.printStackTrace(); resp.put("msg", "建立帳號失敗"); return resp; } resp.put("success", true); return resp; } /** * 生成祕鑰 */ private JSONObject genSecretKey(Ssh2Utils ssh2Utils, String sftpUsername) { // 返回信息 JSONObject resp = new JSONObject(); resp.put("success", false); String sshDirectory = String.format("/sftp/%s/.ssh", sftpUsername); // 指令集 List<String> command = Lists.newArrayList(); // 刪除舊的私鑰 command.add(String.format("rm -f %s/id_rsa*", sshDirectory)); // 生成新的祕鑰(私鑰+公鑰) command.add(String.format("ssh-keygen -f %s/id_rsa -P '' -C '%s'", sshDirectory, sftpUsername)); // 添加公鑰至authorized_keys command.add(String.format("cat %s/id_rsa.pub >> %s/authorized_keys", sshDirectory, sshDirectory)); // 設置權限 command.add(String.format("chmod 600 %s/authorized_keys", sshDirectory)); // 設置屬主 command.add(String.format("chown %s:sftp %s/*", sftpUsername, sshDirectory)); // 執行以上指令 try { ssh2Utils.execCommand(String.join(";", command)); } catch (Exception e) { e.printStackTrace(); resp.put("msg", "生成祕鑰失敗"); return resp; } resp.put("success", true); return resp; } /** * 添加祕鑰 */ private JSONObject addSecretKey(Ssh2Utils ssh2Utils, String sftpUsername, String pubKey) { // 返回信息 JSONObject resp = new JSONObject(); resp.put("success", false); String sshDirectory = String.format("/sftp/%s/.ssh", sftpUsername); try { // 將公鑰添加至authorized_keys ssh2Utils.execCommand(String.format("echo '%s' >> %s", pubKey, String.format("%s/authorized_keys", sshDirectory))); } catch (Exception e) { e.printStackTrace(); resp.put("msg", "添加祕鑰失敗"); return resp; } resp.put("success", true); return resp; } /** * 更新祕鑰 */ public BaseDto changeSecretKey(String sftpUsername, HttpServletResponse response, MultipartFile secretKey) { try { // 登陸sftp服務器 ssh2Utils.login(host, username, password); JSONObject resp; // 生成祕鑰 if (secretKey == null) { // 爲我生成一個祕鑰 resp = genSecretKey(ssh2Utils, sftpUsername); if (resp.getBoolean("success")) { downloadSecretKey(id, response); } } else { // 使用我本身的祕鑰 resp = addSecretKey(ssh2Utils, sftpUsername, new String(secretKey.getBytes())); } if (!resp.getBoolean("success")) { ssh2Utils.logout(); return BaseDto.error(resp.getString("msg"), null); } ssh2Utils.logout(); } catch (Exception e){ e.printStackTrace(); } return BaseDto.success("設置成功", null); } /** * 下載祕鑰 */ public BaseDto downloadSecretKey(String sftpUsername, HttpServletResponse response){ String sshDirectory = String.format("/sftp/%s/.ssh", sftpUsername); // 下載祕鑰 try { // 登陸sftp服務器 ssh2Utils.login(host, username, password); // 獲取私鑰文件內容 String secret = ssh2Utils.execCommand(String.format("cat %s/id_rsa", sshDirectory)); // 私鑰內容結束標誌 String end = "-----END RSA PRIVATE KEY-----"; // 截取私鑰內容 (去除其餘無關的日誌打印內容) secret = secret.substring(0, secret.lastIndexOf(end) + end.length()); // 以附件形式下載私鑰 response.setContentType("text/plain"); response.setHeader("Content-Disposition", "attachment; filename=\"id_rsa\""); PrintWriter pw = response.getWriter(); pw.write(secret); pw.close(); } catch (Exception e) { e.printStackTrace(); } finally { try { ssh2Utils.logout(); } catch (Exception e) { e.printStackTrace(); } } return null; } /** * 新增sftp帳戶 */ public BaseDto save(String sftpUsername, MultipartFile secretKey) { // 校驗名稱 if (StringUtils.isRealBlank(sftpUsername)) { return BaseDto.error("帳戶名稱不能爲空!", null); } try { // 登陸sftp服務器 ssh2Utils.login(host, username, password); // 建立帳號 JSONObject resp = createUser(ssh2Utils, sftpUsername); if (!resp.getBoolean("success")) { return BaseDto.error(resp.getString("msg"), null); } // 生成祕鑰 if (secretKey == null) { // 爲我生成一個祕鑰 resp = genSecretKey(ssh2Utils, sftpUsername); if (resp.getBoolean("success")) return null; } else { // 使用我本身的祕鑰 resp = addSecretKey(ssh2Utils, sftpUsername, new String(secretKey.getBytes())); } if (!resp.getBoolean("success")) { return BaseDto.error(resp.getString("msg"), null); } } catch (Exception e){ e.printStackTrace(); } finally { try { ssh2Utils.logout(); } catch (Exception e) {} } return BaseDto.success("建立成功", null); }