一、Docker部署SFTPGo
拉取镜像时国内可能出现网络问题,有两种方法:1:此处不做讲解T。2:使用国外服务器部署(如果确实要部署到国内服务器上,可以现在国外服务器拉取镜像,拉取后保存镜像为tar,scp至目标服务器,再加载为docker镜像即可)
方法2步骤:
- 拉取镜像:
docker pull drakkan/sftpgo
- 保存镜像为tar
docker save -o sftpgo_latest.tar drakkan/sftpgo:latest
- scp tar包至目标服务器(省略)
- 加载tar为docker镜像
docker load -i sftpgo_latest.tar
- 配置挂载目录并设置目录权限(官方文档:Docker - SFTPGo documentation)
mkdir /data/sftpgo/data
mkdir /data/sftpgo/home
chown -R 1000:1000 /data/sftpgo
- 运行docker容器
docker run -d --name sftpgo \
--restart always \
-p 18080:8080 \
-p 2022:2022 \
-p 18090:8090 \
--mount type=bind,source=/data/sftpgo/data,target=/srv/sftpgo \
--mount type=bind,source=/data/sftpgo/home,target=/var/lib/sftpgo \
-e TZ=Asia/Shanghai \
-e SFTPGO_HTTPD__BINDINGS__0__PORT=8080 \
-e SFTPGO_WEBDAVD__BINDINGS__0__PORT=8090 \
--memory 1G --memory-swap 1G \
drakkan/sftpgo
- 运行成功后打开浏览器访问:http://ip:18080 配置账号密码
-
创建用户并分配专属目录
此处不指定默认目录为/srv/sftpgo/data
若想分配服务器上/data/sftpgo/data/dir1 目录给用户,只需在此处填写:/srv/sftpgo/data/dir1
-
连接SFTP服务器并上传文件
sftp -P 2022 username@ip
(username@ip) Password:
Connected to ip.
sftp> put D:\\粽子.png 粽子1.png
Uploading D://粽子.png to /粽子1.png
-
登录client端查看上传的文件
二、调用SFTPGo Api
官方文档上我们又看到SFTPGo是支持通过REST Api进行调用的(REST API - SFTPGo documentation),详细接口文档参考:Get a new admin access token | SFTPGo。这个系统主要有admin端(管理client端用户等)和client端(查看目录文件等)。
我的需求是通过API创建用户为每个用户分配专属目录,并且可以通过API获取到所有用户创建的目录&上传的文件数据。
2.1、获取access_token
这个接口获取access_token是在header中添加参数:Authorization:Basic (username:password 的Base64编码)
2.2、添加client端用户
Header中添加参数:Authorization:Bearer +(2.1中获取的access_token),注意有空格
{
"status": 1,
"username": "user1",
"email": "",
"description": "测试用户1",
"expiration_date": 0,
"password": "passwd12345",
"has_password": true,
"home_dir": "/srv/sftpgo/data/user1",
"uid": 0,
"gid": 0,
"permissions": {
"/": [
"*"
]
}
}
2.3、简易代码
直接用的Postman生成的调试版代码
import cn.hutool.core.codec.Base64;
import com.alibaba.fastjson.JSONObject;
import com.coocaa.client.user.center.sftpgo.req.SaveUserReq;
import lombok.extern.slf4j.Slf4j;
import okhttp3.*;
import org.springframework.stereotype.Component;
import java.io.IOException;
import java.util.Map;
import java.util.concurrent.TimeUnit;
@Slf4j
public class OkHttpUtil {
private static final OkHttpClient CLIENT;
static {
CLIENT = new OkHttpClient.Builder()
.connectTimeout(30, TimeUnit.SECONDS)
.readTimeout(30, TimeUnit.SECONDS)
.writeTimeout(30, TimeUnit.SECONDS)
.build();
}
/**
* 获取access_token
*
* @return token信息
*/
public static String getAccessToken() {
// 替换为你的username
String username = "admin";
// 替换为你的password
String password = "admin12345";
String auth = Base64.encode(username + ":" + password);
Request request = new Request.Builder()
.url("http://localhost:18080/api/v2/token")
.method("GET", null)
.addHeader("Authorization", "Basic " + auth)
.build();
try {
Response response = CLIENT.newCall(request).execute();
if (response.isSuccessful()) {
if (response.body() == null) {
log.error("获取access_token失败 | response:{}", response);
return null;
}
String result = response.body().string();
JSONObject jsonObject = JSONObject.parseObject(result);
String token = jsonObject.getString("access_token");
log.info("获取access_token成功 | result:{}", result);
return token;
} else {
log.error("获取access_token失败 | response:{}", response);
return null;
}
} catch (Exception e) {
log.error("获取access_token异常", e);
return null;
}
}
public static String addUser(SaveUserReq saveUser) {
MediaType mediaType = MediaType.parse("application/json");
RequestBody body = RequestBody.create(mediaType, JSONObject.toJSONString(saveUser));
Request request = new Request.Builder()
.url("http://localhost:18080/api/v2/users")
.method("POST", body)
.addHeader("Authorization", "Bearer " + getAccessToken())
.addHeader("Content-Type", "application/json")
.build();
try {
log.info("SFTPGo API 请求 | url:{} | 参数:{} ", "http://localhost:18080/api/v2/users", JSONObject.toJSONString(saveUser));
Response response = CLIENT.newCall(request).execute();
if (response.isSuccessful()) {
if (response.body() == null) {
log.error("添加用户失败 | response:{}", response);
return null;
}
String result = response.body().string();
log.info("添加用户成功 | result:{}", result);
return result;
} else {
log.error("添加用户失败 | response:{}", response);
return null;
}
} catch (Exception e) {
log.error("SFTPGo API 请求异常 | url:{} | 参数:{} ", "http://localhost:18080/api/v2/users", JSONObject.toJSONString(saveUser), e);
return null;
}
}
public static void main(String[] args) {
SaveUserReq saveUserReq = new SaveUserReq("user1", "测试用户1"
, "passwd12345", "/srv/sftpgo/data/user1");
addUser(saveUserReq);
}
}
SaverUserReq实体类
import lombok.Data;
import java.util.*;
@Data
public class SaveUserReq {
/**
* 用户状态,0表示用户被禁用,无法登录;1表示用户已启用。允许的值:0, 1
*/
private Integer status;
/**
* 用户名,必须唯一
*/
private String username;
/**
* 用户邮箱地址
*/
private String email;
/**
* 可选的描述信息,例如用户的全名
*/
private String description;
/**
* 过期日期,使用毫秒级Unix时间戳表示。0表示没有过期。范围:>= -9007199254740991, <= 9007199254740991
*/
private Long expiration_date;
/**
* 用户密码,若没有已知的哈希算法前缀,将使用bcrypt哈希;也支持argon2id、pbkdf2或unix crypt。出于安全原因,搜索/获取用户时会省略此字段
*/
private String password;
/**
* 是否设置了密码
*/
private Boolean has_password;
/**
* 用户主目录的绝对路径。用户不能上传或下载此目录之外的文件。SFTPGo会尝试自动创建此文件夹(如果缺失)
*/
private String home_dir;
/**
* 用户id,如果你以 root 用户身份运行 SFTPGo,则创建的文件和目录将分配给此 uid。0 表示无变化,所有者将是运行 SFTPGo 的用户
*/
private Integer uid;
/**
* 组id,如果你以 root 用户身份运行 SFTPGo,则创建的文件和目录将分配给此 gid。0 表示无变化,该组将是运行 SFTPGo 的用户的组。
*/
private Integer gid;
/**
* 以目录为键、以权限数组为值的哈希映射。目录必须是绝对路径,需要根目录(“/”)的权限
*/
private Map<String, Object> permissions;
public SaveUserReq(String username, String description, String password, String homeDir) {
this.status = 1;
this.has_password = true;
this.expiration_date = 0L;
this.uid = 0;
this.gid = 0;
this.username = username;
this.description = description;
this.password = password;
this.home_dir = homeDir;
Map<String, Object> map = new HashMap<>(2, 1);
map.put("/", Collections.singletonList("*"));
this.permissions = map;
}
}