首页 > 编程语言 >java使用sshd 实现sftp 自定义显示目录

java使用sshd 实现sftp 自定义显示目录

时间:2024-07-03 22:10:35浏览次数:18  
标签:sshd 自定义 server session org apache import 显示目录

 

 

 

pom.xml

 <dependencies>
        <dependency>
            <groupId>cn.hutool</groupId>
            <artifactId>hutool-core</artifactId>
            <version>5.8.28</version>
        </dependency>
        <dependency>
            <groupId>org.apache.sshd</groupId>
            <artifactId>sshd-core</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.apache.sshd</groupId>
            <artifactId>sshd-sftp</artifactId>
            <version>2.9.2</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-web</artifactId>
            <version>2.7.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-test</artifactId>
            <version>2.7.11</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-starter-aop</artifactId>
            <version>2.7.11</version>
        </dependency>
        <dependency>
            <groupId>org.projectlombok</groupId>
            <artifactId>lombok</artifactId>
            <version>1.18.30</version>
            <scope>provided</scope>
        </dependency>
        <dependency>
            <groupId>com.alibaba</groupId>
            <artifactId>fastjson</artifactId>
            <version>2.0.50</version>
        </dependency>
        <dependency>
            <groupId>org.apache.commons</groupId>
            <artifactId>commons-lang3</artifactId>
            <version>3.12.0</version>
        </dependency>

    </dependencies>

 

PasswordAuthenticator

 

package com.zhianchen.sftptest.auth;

import cn.hutool.core.collection.CollectionUtil;
//import com.upi.gftp.common.util.EncryMachineutils;
//import com.upi.gftp.domain.dto .GftpuserDTO;
//import com.upi.gftp.domain.enums.AuthTypeEnum;
//import com.upigftp .domain.enums .StatusEnum;
//import com.upi.gftp.domain .enums.UserTypeEnum;
//import com.upi.gftpservice.SftpSeverService;
//import com.upi.gftp.service.UserService;
//import com.upi.gftp.service .config.EnckeyInfoConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.sshd.server .auth.AsyncAuthException;
import org.apache.sshd.server.auth.password.PasswordChangeRequiredException;
import org.apache.sshd.server .channel.ChannelSession;
import org.apache.sshd.server.command .Command;
import org.apache .sshd.server .session .ServerSession;
import org.apache .sshd.server .shell.ShellFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.util.List;
/**
 * 密码登录验证
 */
@Slf4j
@Component
public class PasswordAuthenticator implements org.apache.sshd.server.auth.password.PasswordAuthenticator, ShellFactory {

    /**
     * 登录
     * @param s
     * @param s1
     * @param serverSession
     * @return
     * @throws PasswordChangeRequiredException
     * @throws AsyncAuthException
     */
    @Override
    public boolean authenticate(String s, String s1, ServerSession serverSession) throws PasswordChangeRequiredException, AsyncAuthException {
        return false;
    }

    @Override
    public Command createShell(ChannelSession channelSession) throws IOException {
        log.error(channelSession.getSession().getUsername()+" this sftp server only allows command;");
        throw  new UnsupportedOperationException(channelSession.getSession().getUsername()+" this sftp server only allows command;");
        //return null;
    }
}

 

PublicKeyAuthenticator

package com.zhianchen.sftptest.auth;

import cn.hutool.core.collection.CollectionUtil;
//import com.upi.gftp.common.constants.CommonConstants;
//import com.upi.gftp.common.util.secretkey.PublicKeyutils;
//import com.upi.gftp.domain.dto.GftpuserDT0;
//import com.upi.gftp .domain.enums .AuthTypeEnum;
//import com.upi.gftp.domain.enums.StatusEnum;
//import com.upi.gftp .domain .enums .UserTypeEnum;
//import com.upi.gftp.service.SftpSeverService;
//import com.upi.gftp.service.UserService;
import lombok.extern.slf4j.Slf4j;
import org.apache.sshd.server.auth.AsyncAuthException;
import org.apache.sshd.server.auth.pubkey.PublickeyAuthenticator;
import org.apache .sshd.server .channel.ChannelSession;
import org.apache .sshd .server . command .Command;
import org.apache .sshd.server .session.ServerSession;
import org.apache .sshd.server .shell.ShellFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.security.PublicKey;
import java.util.List;

/**
 * 秘钥登录
 */
@Slf4j
@Component
public class PublicKeyAuthenticator implements PublickeyAuthenticator, ShellFactory {
    @Override
    public boolean authenticate(String s, PublicKey publicKey, ServerSession serverSession) throws AsyncAuthException {
        String algorithm = publicKey.getAlgorithm();

        return false;
    }

    @Override
    public Command createShell(ChannelSession channelSession) throws IOException {
        log.error(channelSession.getSession().getUsername()+" this sftp server only allows command;");
        throw  new UnsupportedOperationException(channelSession.getSession().getUsername()+" this sftp server only allows command;");
    }
}

 

 

SftpEventListener

package com.zhianchen.sftptest.startup;

import com.alibaba.fastjson.JSON;

import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.date.*;
import cn.hutool.core.util.*;
//import com.upi.gftp.core .Filepipeline;
//import com.upi.gftp.core.domain.FilePipelineContext;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.sshd.server.session.ServerSession;
import org.apache.sshd.sftp.common.SftpException;
import org.apache.sshd.sftp.server .FileHandle;
import org.apache.sshd.sftp.server .Handle;
import org.springframework.stereotype .Component;
import javax.annotation.Resource;
import java.io.IOException;
import java.nio.file.CopyOption;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardOpenOption;
import java.util.*;
import java.util.stream.Collectors;

/**
 *
 */
@Slf4j
@Component
public class SftpEventListener implements org.apache.sshd.sftp.server.SftpEventListener {
    @Override
    public void initialized(ServerSession session, int version) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.initialized(session, version);
        log.info("initialized ... user {},version {}",session.getUsername(),version);
    }

    @Override
    public void creating(ServerSession session, Path path, Map<String, ?> attrs) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.creating(session, path, attrs);
        log.info("creating ... user {},version {}",session.getUsername(),path);
        int name=path.getNameCount();
    }

    @Override
    public void opening(ServerSession session, String remoteHandle, Handle localHandle) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.opening(session, remoteHandle, localHandle);
        log.info("opening ... user {} start",session.getUsername());
        String  fileHandle=  localHandle.getFileHandle();
        if(fileHandle==null){
            return;
        }
        //文件上传句柄
        if(localHandle instanceof FileHandle){
            Set<StandardOpenOption> openOptions = ((FileHandle) localHandle).getOpenOptions();
            log.info("opening ... user {},options {}",session.getUsername(),JSON.toJSONString(openOptions));
            if(openOptions.contains(StandardOpenOption.WRITE)){
                String s = localHandle.getFile().getFileName().toString();
            }else if(openOptions.contains(StandardOpenOption.READ)){
                String s = localHandle.getFile().getFileName().toString();
            }
        }
        log.info("opening ... user {} finish",session.getUsername());
    }

    @Override
    public void received(ServerSession session, int type, int id) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.received(session, type, id);
        log.info("received ... user {} type {} id {}",session.getUsername(),type,id);
        if(type==18){
            //不允许修改目录和文件名称
            throw new SftpException(600,"modify file or directory name is not allowed!");
        }
    }

    @Override
    public void created(ServerSession session, Path path, Map<String, ?> attrs, Throwable thrown) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.created(session, path, attrs, thrown);
        log.info("created ... user {} ",session.getUsername());
    }

    @Override
    public void moved(ServerSession session, Path srcPath, Path dstPath, Collection<CopyOption> opts, Throwable thrown) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.moved(session, srcPath, dstPath, opts, thrown);
    }

    @Override
    public void moving(ServerSession session, Path srcPath, Path dstPath, Collection<CopyOption> opts) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.moving(session, srcPath, dstPath, opts);
    }

    @Override
    public void read(ServerSession session, String remoteHandle, FileHandle localHandle, long offset, byte[] data, int dataOffset, int dataLen, int readLen, Throwable thrown) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.read(session, remoteHandle, localHandle, offset, data, dataOffset, dataLen, readLen, thrown);
        log.info("read ... user {},file {} ",session.getUsername(),localHandle.getFile().toString());
    }

    @Override
    public void closed(ServerSession session, String remoteHandle, Handle localHandle, Throwable thrown) throws IOException {
        //org.apache.sshd.sftp.server.SftpEventListener.super.closed(session, remoteHandle, localHandle, thrown);
        log.info("closed ... user {} start",session.getUsername());
        //文件上传句柄
        if(localHandle instanceof FileHandle){
            Set<StandardOpenOption> openOptions = ((FileHandle) localHandle).getOpenOptions();
            log.info("opening ... user {},options {}",session.getUsername(),JSON.toJSONString(openOptions));
            if(openOptions.contains(StandardOpenOption.WRITE)&&!localHandle.isOpen()){
                //FilleSftp
                String s = localHandle.getFile().getFileName().toString();
            }else if(openOptions.contains(StandardOpenOption.READ)){
                String s = localHandle.getFile().getFileName().toString();
            }
        }
        localHandle.close();
        log.info("closed ... user {} finish",session.getUsername());
    }
}

 

SftpServerConfig

package com.zhianchen.sftptest.startup;

import com.zhianchen.sftptest.auth.PasswordAuthenticator;
import com.zhianchen.sftptest.auth.PublicKeyAuthenticator;
import com.zhianchen.sftptest.config.CommonConfig;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache .sshd.common .NamedFactory;
import org.apache.sshd.common.file.virtualfs.VirtualFileSystemFactory;
import org.apache.sshd.common.kex.BuiltinDHFactories;
import org.apache.sshd.common.kex.KeyExchangeFactory;
import org.apache.sshd.common.session.SessionContext;
import org.apache.sshd.sftp.server.SftpSubsystemFactory;
import org.apache .sshd.server .ServerBuilder;
import org .apache .sshd .server .SshServer;
import org.apache.sshd.server.keyprovider.SimpleGeneratorHostKeyProvider;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;

import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.rmi.RemoteException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

@Slf4j

public class SftpServerConfig {
    @Autowired
    private CommonConfig commonConfig;

    @Autowired
    private PasswordAuthenticator passwordAuthenticator;

    @Autowired
    private PublicKeyAuthenticator publicKeyAuthenticator;

    @Autowired
    private SftpEventListener sftpEventListener;

    @Bean
    public void sftpServer() {
//创建SshServer对象
        log.info("Create ssh server instance...");
        SshServer sshd = SshServer.setUpDefaultServer();
        log.info("set ssh server port...port:[}.", commonConfig.getPort());
        sshd.setPort(commonConfig.getPort());
        //设置默认的备名文件,如过文件不存在会创建
        log.info("Set key pair provider...");
        sshd.setKeyPairProvider(new SimpleGeneratorHostKeyProvider());
        //设置密销进行登录验证
        log.info("Set public key authenticator...");
        sshd.setPublickeyAuthenticator(publicKeyAuthenticator);//设置用户名和密码进行登录验证
        log.info("Set password authenticator...");
        sshd.setPasswordAuthenticator(passwordAuthenticator);
//设置sftp子系统
        log.info("Set sftp sub system...");
        SftpSubsystemFactory sftpSubsystemFactory = new SftpSubsystemFactory();
        log.info("Add sftp event listener...");
        sftpSubsystemFactory.addSftpEventListener(sftpEventListener);
        sshd.setSubsystemFactories(Collections.singletonList(sftpSubsystemFactory));

        log.info("Set up home folder for users...");
        Path frontendFolder = Paths.get("/sftpfroent"); //gftpPathConfig.getFrontendsftp()
        if (Files.notExists(frontendFolder) || Files.isRegularFile(frontendFolder)) {
            log.info("GFTP frontend folder not exists, will create folder. folder:[}.", frontendFolder);
            try {
                Files.createDirectories(frontendFolder);
            } catch (IOException e) {
                log.error("sftp server start failed! create frontend folder failed! folder:1.", frontendFolder, e);
                return;
            }
        }


        sshd.setFileSystemFactory(new VirtualFileSystemFactory(frontendFolder.toAbsolutePath()) {

            @Override
            public Path getUserHomeDir(SessionContext session) throws IOException {
                String username = session.getUsername();


                if (StringUtils.isBlank(username)) {
                    log.info("client username blank!");
                    throw new RuntimeException("client username blank!");
                }
                Path homeDir = getUserHomeDir(username);
                if (homeDir == null) {
                    //这里给每个用户修改为默认目录+用户名
                    homeDir = getDefaultHomeDir().resolve(username);
                    createHomeDir(username, homeDir);
                } else {
                    createHomeDir(username, homeDir);
                }
                return homeDir;

            }

            public void createHomeDir(String username, Path homeDir) throws RemoteException {
                if (Files.notExists(homeDir) || Files.isRegularFile(homeDir)) {
                    try {
                        Files.createDirectories(homeDir);
                    } catch (Exception e) {
                        log.error("can not create folder {}.", homeDir);
                        throw new RemoteException("Can not create folder " + homeDir);

                    }
                }
                setUserHomeDir(username, homeDir);
            }
        });
            //启动ssh服务
        try {
            log.info("starting sftp server...");
            sshd.start();
            log.info("sftp server started normally,port:1}.", commonConfig.getPort());
        } catch (IOException e) {
            log.error("sftp server start failed!", e);
        }
    }

    private List<KeyExchangeFactory> getKeyExchangeFactories() {
        List<KeyExchangeFactory> keyExchangeFactories = new ArrayList<>();

// Add the Diffie-Hellman-group1-sha1 key exchange factory
        keyExchangeFactories.addAll(NamedFactory.setUpTransformedFactories(false, Arrays.asList(BuiltinDHFactories.dhg1, BuiltinDHFactories.dhg14),
                ServerBuilder.DH2KEX));

        keyExchangeFactories.addAll(BuiltinDHFactories.VALUES.stream().map(ServerBuilder.DH2KEX).collect(Collectors.toList()));
        return keyExchangeFactories;


    }
}

 

CommonConfig

package com.zhianchen.sftptest.config;
/*
* @author : zrht_chenzhian
* @date :2023/12/6 16:07
* @description
* @moduified By:
*/

import lombok.Data;
import org.springframework.boot.context.properties.ConfigurationProperties;
import org.springframework.context.annotation.Configuration;

@Data
@Configuration
@ConfigurationProperties(prefix = "gftp")
public class CommonConfig {

    //tcp端口
    private Integer tcpPort;
    /**
     * gftp系统ip
     */
    private String host;
    /**
     * gftp端口
     */
    private Integer port;
}

 

标签:sshd,自定义,server,session,org,apache,import,显示目录
From: https://www.cnblogs.com/zhian/p/18282636

相关文章

  • Vue3实战笔记(64)—Vue 3自定义指令的艺术:实战中的最佳实践
    文章目录前言一、一些简单的Vue3自定义指令超实用案例总结前言书接上文,在Vue3中,自定义指令是一种强大的工具,允许我们扩展HTML元素的功能。通过自定义指令,我们可以创建可重用的行为,并将它们绑定到任何元素上。下面,本文备份一些简单的Vue3自定义指令超实用案例,并解释......
  • 关于自定义unordered_set\unordered_map中Hash和KeyEqual:函数对象和lambda表达式简单
    以unordered_set为例,首先在cppreference中查看其模板定义:可以看到Hash类默认是std::hash<Key,KeyEqual类似,本文将Hash以函数对象写出,将KeyEqual以lambda写出。classhashvec{ public: size_toperator()(constvector<int>&vec)const{ returnhash<int>()(vec[0])+hash......
  • 调用自定义模块出现ModuleNotFoundError
    产生问题的原因:IDE(pycharm)没有将自定义模块所在目录添加到工作目录中,导致在搜索目录中找不到要调用的模块。Python会在以下路径中搜索它想要寻找的模块:程序所在的文件夹标准库的安装路径操作系统环境变量PYTHONPATH所包含的路径解决方法1:在调用自定义模块前先将自定义模块/......
  • 企业微信hook,自定义工具,收发消息
    协议版本示例:    企业微信协议开发,配置服务器开启服务端,接口开发企业微信协议接口开发,接收发送json数据即可;接口调用:http请求      接下来拿uuid去调用其他接口即可例:发送位置      请求方式POSTContentType:”application/jso......
  • Django 自定义用户表
    当默认的用户表中字段不足以满足我们的业务需求时,可以自己继承和重写用户表,增加想要的字段。1.自定义用户表模型fromdjango.dbimportmodelsfromdjango.contrib.auth.modelsimportAbstractUser#重新定义用户表classUserProfile(AbstractUser):avatar=model......
  • 从零开始带你上手体验Sermant自定义插件开发
    本文分享自华为云社区《Sermant自定义插件开发上手体验》,作者:华为云开源。一、研究缘由由于目前我们所处的行业是汽车行业,项目上进行云服务的迁移时使用到了Sermant中的相关插件,为了加深对Sermant开发和运行机制的了解,我们从零开始体验Sermant自定义插件的开发。下面我们就Se......
  • 自定义ORM框架
    手撕ORM框架1.创建Maven工程2.导入依赖<dependencies><!--引入jdbc的依赖--><dependency><groupId>mysql</groupId><artifactId>mysql-connector-java</artifactId><versi......
  • Dockerfile语法,自定义镜像
    我们一直在使用别人准备好的镜像,那如果我要部署一个Java项目,把它打包为一个镜像该怎么做呢?镜像结构要想自己构建镜像,必须先了解镜像的结构。镜像之所以能让我们快速跨操作系统部署应用而忽略其运行环境、配置,就是因为镜像中包含了程序运行需要的系统函数库、环境、配置、依......
  • 周下载量3000多万的npm包---nanoid(uuid的竞争对手),生产随机字符串,体积更小,可以自定义
    https://www.npmjs.com/package/nanoid体积更小,可以自定义字符集<scriptsetup>import{onMounted}from'vue'import{nanoid,customAlphabet}from'nanoid'onMounted(()=>{letid1=nanoid()console.log(id1)letcustomNanoid......
  • LabVIEW的自定义按钮
    下载几张图片:选用windows风格按钮控件进行自定义,自定义的图片分别放入这6个位置,我们来搞清楚它们的对应关系:(1)当我们设置按钮机械状态为默认(自复位):(2)但我们改变按钮机械状态为按下不自动弹起:其他的几个对应的设置与效果:......