天天看點

阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo

目錄

我的需求:

1.安裝過程​​​​​​:

附帶圖:​2.開啟遠端通路

3.修改配置檔案,禁止匿名通路

4.建立一個使用者

5.開啟被動模式

6.配置使用者ftp權限及通路路徑限制

碰見的問題:

整合nginx

我的需求:

1.搭建完ftp後,添加一個ftp使用者,隻允許對指定的目錄進行讀寫操作,其餘目錄禁止讀寫.

2.在java代碼中使用ftp使用者賬戶,進行上傳檔案/圖檔.

3.使用nginx整合ftp,提供對外通路檔案/圖檔的url路徑.

在java中使用ftp上傳時,有關于目錄的問題,參考這篇文章:https://blog.csdn.net/qq_23167527/article/details/66975727

1.安裝過程​​​​​​:

第一步:檢查是否安裝了vsftpd

rpm -qa | grep vsftpd
           

第二步:如果沒有安裝則安裝vsftpd

yum -y install vsftpd
           

第三步: 補充知識點,不需要全部執行

systemctl status vsftpd 檢視服務狀态

systemctl start vsftpd  啟動服務

systemctl stop vsftpd   暫停服務

systemctl restart vsftpd   重新開機啟動服務

systemctl enable vsftpd  開機自啟動

systemctl disable vsftpd   取消開機自啟動
           

附帶圖:
阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo
2.開啟遠端通路

在阿裡雲安全組中,添加安全組規則

阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo

3.修改配置檔案,禁止匿名通路

編輯配置檔案

vim /etc/vsftpd/vsftpd.conf
           

預設是yes将其改為no

anonymous_enable=NO  
           

4.建立一個使用者

建立一個使用者使用ftp

useradd ftpuser -d /home/ftpimage
           

設定使用者密碼,輸入兩次就行

passwd ftpuser
           

5.開啟被動模式

被動模式預設是開啟的,但是需要指定一個端口範圍.

vim /etc/vsftpd/vsftpd.conf
           

在最後面加上,注意這裡是開啟範圍端口,意思是說,8800~8899這個範圍内的端口必須全部開啟,當然你也可以自己随便設定

pasv_min_port=8800

pasv_max_port=8899
           

表示端口範圍為8800~8899,這個可以随便修改,改完記得重新開機一下vsftpd服務。

友情提示:最大和最小,最好設定為一樣,這樣就成了固定端口了

對應的我們也應該在安全組政策中添加這個範圍的端口。

阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo

6.配置使用者ftp權限及通路路徑限制

編輯配置檔案,在末尾添加,這三行

vim /etc/vsftpd/vsftpd.conf
           
userlist_enable=YES
userlist_deny=NO
userlist_file=/etc/vsftpd/user_list
           

編輯user_list檔案.将使用者名添加進去

ftpuser
           

這時候發現,建立的使用者是可以通路其他路徑的,如果想要不允許,則編輯配置檔案,将這兩行前的#号去掉

chroot_list_enable=YES
# (default follows)
chroot_list_file=/etc/vsftpd/chroot_list
           

如果沒有chroot_list檔案,則手動建立

touch chroot_list
           

編輯chroot_list檔案,将使用者賬号添加進去

阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo

如果發現vsftpd: refusing to run with writable root inside chroot錯誤

原因:從2.3.5之後,vsftpd增強了安全檢查,如果使用者被限定在了其主目錄下,則該使用者的主目錄不能再具有寫權限了!如果檢查發現還有寫權限,就會報該錯誤

解決:編輯配置檔案,在末尾加上

allow_writeable_chroot=YES
           

如果發現上傳不了檔案,則需要設定檔案夾讀寫權限

阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo

碰見的問題:

1.dos指令能連接配接,點選檢視這篇文章: FileZilla MLSD錯誤:連接配接逾時、讀取目錄清單失敗

2.dos指令能連接配接,但是windows連接配接不上,直接修改被動模式的端口,将最大端口和最小端口修改為一樣

整合nginx

1.安裝nginx參考這篇文章:https://www.cnblogs.com/wyd168/p/6636529.html

2.修改nginx配置檔案

阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo

通路效果:

阿裡雲ECS,CentOs7.3搭建FTP伺服器,附帶java使用demo

如果這裡通路報404,則需要考慮指定的目錄是否有可通路權限

導入依賴:

<dependency>
            <groupId>commons-net</groupId>
            <artifactId>commons-net</artifactId>
            <version>3.3</version>
        </dependency>
           

實體類:

public class PicUploadResult {

    private int error;

    /**
     * 圖檔儲存路徑
     */
    private String url;
    // set/get......
}
           

java上傳工具類:

import com.bbpk.common.base.ConstantInterface;
import com.bbpk.common.base.entity.vo.PicUploadResult;
import com.xiaoleilu.hutool.date.DateTime;
import org.apache.commons.lang3.RandomUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.web.multipart.MultipartFile;
import java.io.*;
import java.util.Arrays;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 檔案上傳幫助類
 */
public class FileUploadUtil {


    public static boolean isImage(String contentType) {
        for (String type : ConstantInterface.IMAGE_CONTENT_TYPE) {
            if (contentType.toLowerCase().equals(type)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 照片上傳
     *
     * @param uploadFile    需上傳的檔案
     * @return
     * @throws Exception
     */
    public static PicUploadResult imgUpload(MultipartFile uploadFile) throws Exception {
        if (null == uploadFile) return null;

        // 封裝Result對象,并且将檔案的byte數組放置到result對象中
        PicUploadResult fileUploadResult = new PicUploadResult();

        // 校驗圖檔格式
//        boolean isLegal = isImageFile(uploadFile.getOriginalFilename());
        boolean isLegal = isImage(uploadFile.getContentType());

        // 狀态
        fileUploadResult.setError(isLegal ? 0 : 1);

        // 檔案新路徑
        String fileName = getFileName(uploadFile.getContentType());

        File newFile = new File(fileName);


        InputStream is = uploadFile.getInputStream();

        if (null == is) {
            throw new Exception("圖檔輸入流為擷取失敗");
        }
        // 圖檔上傳到FTP伺服器
        boolean rtn = FTPClientUtil.uploadImage("", newFile.getName(), is);
        fileUploadResult.setUrl("http://IP+端口/"+newFile.getName());
        fileUploadResult.setError(isLegal && rtn ? 0 : 1);
        return fileUploadResult;
    }

    public static String getFileName(String contentType) {
        String suffix = "";
        List<String> type = Arrays.stream(ConstantInterface.IMAGE_CONTENT_TYPE)
                .filter(n -> n.equals(contentType))
                .collect(Collectors.toList());
        if (type.size() > 0) {
            suffix = StringUtils.substringAfterLast(type.get(0), "/");
        }

        Date nowDate = new Date();
        return new DateTime(nowDate).toString("yyyyMMddhhmmssSSSS")
                + RandomUtils.nextInt(100, 9999) + "." + suffix;
    }

}
           
import com.bbpk.common.base.ConstantInterface;
import org.apache.commons.net.ftp.FTP;
import org.apache.commons.net.ftp.FTPClient;
import org.apache.commons.net.ftp.FTPReply;

import java.io.*;

/**
 * FTP用戶端 上傳檔案
 */
public class FTPClientUtil {


    /**
     * 校驗圖檔格式
     *
     * @param filename
     * @return
     */
    public static boolean isImageFile(String filename) {
        // 校驗圖檔格式
        boolean isLegal = false;
        for (String type : ConstantInterface.IMAGE_TYPE) {
            if (org.apache.commons.lang3.StringUtils.endsWithIgnoreCase(filename, type)) {
                isLegal = true;
                break;
            }
        }

        return isLegal;
    }

    /**
     * 擷取FTP連接配接
     *
     * @return
     */
    private static FTPClient getInstance() {
        FTPClient ftp = new FTPClient();
        try {
            int reply;
            ftp.connect("ip位址", 21);//連接配接FTP伺服器
            //如果采用預設端口,可以使用ftp.connect(url)的方式直接連接配接FTP伺服器
            boolean rtn = ftp.login("賬戶", "密碼");//登入
            reply = ftp.getReplyCode();
            if (!FTPReply.isPositiveCompletion(reply)) {
                ftp.disconnect();
            }

        } catch (IOException e) {
            e.printStackTrace();
        }

        return ftp;
    }

    /**
     * 上傳圖檔到伺服器
     *
     * @param relativePath 相對路徑
     * @param filename     檔案名
     * @param input        檔案流
     * @return 成功傳回true,否則傳回false
     */
    public static boolean uploadImage(String relativePath, String filename, InputStream input) {

        return FTPClientUtil.uploadFile("/home/monkeyimg/img" + relativePath, filename, input);
    }

    /**
     * 向FTP伺服器上傳檔案
     *
     * @param path     FTP伺服器儲存目錄
     * @param filename 上傳到FTP伺服器上的檔案名
     * @param input    輸入流
     * @return 成功傳回true,否則傳回false
     */
    public static boolean uploadFile(String path, String filename, InputStream input) {
        boolean success = false;
        FTPClient ftpClient = getInstance();
        ftpClient.enterLocalPassiveMode();
        try {
            ftpClient.setControlEncoding("UTF-8");
            ftpClient.changeWorkingDirectory(path);


            //如果是圖檔 需要修改上傳檔案的格式,否則圖檔以文本的形式傳輸,會失真
            //ftpClient預設上傳的格式是文本
            //修改成二進制上傳
            if (isImageFile(filename)) {
                ftpClient.setFileType(FTP.BINARY_FILE_TYPE);
            }

            //注意注意注意:需要設定目錄權限為777 坑死我了
            success = ftpClient.storeFile(new String(filename.getBytes("UTF-8"), "iso-8859-1"), input);

            input.close();
            ftpClient.logout();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (ftpClient.isConnected()) {
                try {
                    ftpClient.disconnect();
                } catch (IOException ioe) {
                }
            }
        }
        return success;
    }

}