目录
一、异常展示
1.1.日志报错
1.2.nacos中SFTP参数配置
二、bug溯源
2.1.本地代码排查
2.1.1.核心代码展示
2.1.2.补充说明
2.2.本地测试
2.3.服务器测试
2.4.SFTP排查
2.4.1.SFTP访问权限排查
2.4.2.SFTP展示权限排查
三、SFTP配置文件权限说明
四、liunx权限说明
上周客户反应,本地文件生成后,在上传文件时创建SFTP目录时失败,既然有问题,那就找呗,毕竟工作不就是创造bug和解决bug么。由异常报错可知,文件是在上传时,创建SFTP目录时失败,而SFTP的目录是 /1001**********23/,下面记录一下解决问题的思路。
public void upload1(String directory,String name, String sftpFileName, InputStream input) throws SftpException {
try {
//创建一级目录
sftp.cd(directory);
} catch (SftpException e) {
logger.warn("directory is not exist:1级目录"+directory);
//创建多级目录
createDir(directory,sftp);
sftp.cd(directory);
}
//创建2级目录
try {
sftp.cd(directory+name);
} catch (Exception e) {
logger.warn("directory is not exist:2级目录"+directory+name);
sftp.mkdir(directory+name);
sftp.cd(directory+name);
}
sftp.put(input, sftpFileName);
logger.info("file:{} is upload successful", sftpFileName);
}
/**
* 创建一个文件目录
*/
public void createDir(String createpath, ChannelSftp sftp) {
try {
if (isDirExist(createpath)) {
this.sftp.cd(createpath);
return;
}
String pathArry[] = createpath.split("/");
StringBuffer filePath = new StringBuffer("/");
for (String path : pathArry) {
if ("".equals(path)) {
continue;
}
filePath.append(path + "/");
if (isDirExist(filePath.toString())) {
sftp.cd(filePath.toString());
} else {
// 建立目录
sftp.mkdir(filePath.toString());
// 进入并设置为当前目录
sftp.cd(filePath.toString());
}
}
this.sftp.cd(createpath);
} catch (SftpException e) {
logger.error("创建路径错误:"+createpath);
}
}
/**
* 判断目录是否存在
*/
public boolean isDirExist(String directory) {
boolean isDirExistFlag = false;
try {
SftpATTRS sftpATTRS = sftp.lstat(directory);
isDirExistFlag = true;
return sftpATTRS.isDir();
} catch (Exception e) {
if ("no such file".equals(e.getMessage().toLowerCase())) {
isDirExistFlag = false;
}
}
return isDirExistFlag;
}
由客户的日志反馈可知,是upload1方法在创建一级目录时失败,上面是创建一级目录的代码。
本地目录创建和SFTP目录创建是不一样的,本地可以一次性创建多级目录,详情请看本地多级目录创建 ,可以直接用mkdirs()方法进行创建多级目录。而SFTP不一样,SFTP没有这个方法,只能用mkdir()方法一级一级创建,具体展示如下:
在排查错误时,除了明显的编写错误以外,别的错误都是不好直接看出来的。所以我们在寻找错误的过程中,Debug是最常用的方法,这里没有上传视频,看图片也差不多的。
截止到这里,符合图片中的日志打印
进一步Debug发现,创建多级目录正常,并无报错。
根据本地 Debug 寻找,发现文件目录正常创建,并没有报错。没报错说明代码的设计是没有问题的,那就需要找系统的问题了。系统方面包含两方面,一方面是本地系统异常,包含白名单和登录失败等问题;一方面是客户SFTP服务器异常,包含创建目录权限限制和SFTP系统配置等。
这个是用测试服务器和测试SFTP运行的程序,我通过一次性创建5级目录 /1000066666/ICBCRecon/01/02/03/200028029321208/ ,进一步验证了不是代码的问题,同时,我们联系客户,也确认了是①服务器和SFTP之间是不需要添加白名单的,②登录是可以正常登录,③生产环境在访问SFTP时,SFTP的端口也是经过服务器防火墙放行的,这个流程就不做记录了。
由上述排查可知,程序是可以正常创建多级目录的,那么代码bug的几率就很小了。检查SFTP创建目录的权限。
用nacos 中配置的SFTP用户登录SFTP,并且在 /1001**********23/ 目录的上一层创建 test 目录,发现报的是没有权限。
然后在 /1001**********23/ 目录的下一层创建 test 目录,发现是可以创建的。
由上述操作可知,当用指定用户创建目录时,权限是没问题的。代码没问题,权限没问题,那就要看SFTP配置问题了。
从上图可以看到,当前目录是 /data/sftpsite/szfs/1001001001000023/ ,与nacos配置相比,多出来了 /data/sftpsite/szfs/ ,那么就有可能是SFTP目录权限的问题,具体还需要验证。
寻找SFTP的ssh配置文件,文件路径 /etc/ssh/sshd_config ,可以看到:
左边是当前SSH配置文件,文件为初始化配置文件,并没有对目录进行权限限制,右边是应该有的权限配置。
从系统的历史操作可以看到 ,在2023年11月22日,配置文件被修改过,所以系统原有的配置操作被初始化掉了,造成了突然的创建目录异常。
根据配置文件可知,原本添加的权限限制都没了,所以这个时候,nacos 配置的路径就应该是系统全路径,也就是系统绝对路径 ,只配置相对路径是访问不到SFTP目录的,所以才会创建目录失败。
所以解决bug有两种操作,一是将权限添加上,然后系统还访问相对路径;一是不添加权限,系统访问绝对路径。
在一般情况下,用户登录上SFTP以后,看到的目录结构都是相对路径,也就是说是经过限制的路径,而非从系统的根路径开始展示,那么合理的添加限制有哪些作用呢?
在SFTP的配置文件/etc/ssh/sshd_config中添加用户访问权限,可以带来以下几个好处:
我上面在2.4.1进行访问权限排查时,是直接用工具进行目录创建测试,而在Linux中,实际上是不需要创建,只看文件就行,具体操作如下:
在Linux系统中,您可以使用ls -l
命令来查看文件操作权限。这个命令会以长格式列出文件和目录的信息,包括权限、所有者、所属组和其他属性。
以下是使用ls -l
命令的示例:
ls -l filename
其中,"filename"是您要查看权限的文件或目录的名称。执行该命令后,将显示类似于以下的结果:
-rw-r--r-- 1 user group 1234 Oct 23 10:00 filename
您还可以使用 ll 命令来查看文件操作权限,它是ls -l
命令的别名。在终端中输入ll
命令即可:在这个例子中,文件权限被表示为"-rw-r--r--"。这些字符按照三个一组划分,分别代表所有者、所属组和其他用户的权限。每组的三个字符分别表示读(r)、写(w)和执行(x)权限。如果权限被拒绝,则表示为"-"。
ll filename
这将以长格式列出文件或目录的详细信息,包括权限、所有者、所属组和其他属性。SFTP查看示例如下: