首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >将ssh键设置为与apache中的jgit和ssh一起使用

将ssh键设置为与apache中的jgit和ssh一起使用
EN

Stack Overflow用户
提问于 2021-05-31 03:01:59
回答 5查看 2.5K关注 0票数 1

我使用运行在kubernetes容器中的java应用程序的jgit运行git命令,因此我希望允许自定义ssh密钥存储位置等等。

我的第一种方法是使用jsch实现支持的ssh,但遇到了麻烦(我在这里检查了Using Keys with JGit to Access a Git Repository Securely方法,但没有找到它),所以我通过org.eclipse.jgit.ssh.apache工件添加了ssh支持。由于打包/分发的方式,使用外部ssh应用程序并不是一个真正的选择。

我还没有找到多少信息,但假设我只是想模仿jsch方法,并替换调用中使用的会话工厂。最初,我采用的方法是使用所需的ssh路径设置会话工厂。

代码语言:javascript
运行
复制
        final SshdSessionFactoryBuilder builder = new SshdSessionFactoryBuilder();
        builder.setHomeDirectory(new File(homeDir))
                .setConfigFile((f)-> new File(f, "config"))
                .setSshDirectory(new File(sshDir));

        return builder.build(null);

把这个工厂传递给不同的命令。

代码语言:javascript
运行
复制
final CloneCommand cmd = Git.cloneRepository().setDirectory(new File(basePath))
                            .setURI(remotePath);
                    if (sshSessionFactory != null) {
                        cmd.setTransportConfigCallback(new TransportConfigCallback() {
                            @Override
                            public void configure(Transport transport) {
                                final SshTransport sshTransport = (SshTransport)transport;
                                ((SshTransport) transport).setSshSessionFactory(sshSessionFactory);
                            }
                        });
                    }
                    git = cmd.call();

但是,使用这种方法,像克隆这样的命令将无法使用git,试图使用默认的ssh键。在调试器中,我发现它在克隆命令中生成了一个fetch命令,但是没有将会话工厂或会话传递给它,所以fetch只是构建了一个默认配置,并且失败了。

代码语言:javascript
运行
复制
2021-05-31 11:48:09,793 INFO  GitChainRepository.java:114 - Couldn't find git dir, creating it
2021-05-31 11:48:10,748 INFO  AbstractSecurityProviderRegistrar.java:112 - getOrCreateProvider(EdDSA) created instance of net.i2p.crypto.eddsa.EdDSASecurityProvider
2021-05-31 11:48:10,970 INFO  DefaultIoServiceFactoryFactory.java:67 - No detected/configured IoServiceFactoryFactory using Nio2ServiceFactoryFactory
2021-05-31 11:48:12,206 INFO  GitChainRepository.java:133 - Initialized by clone of remote
2021-05-31 11:48:12,207 INFO  GitChainRepository.java:159 - Prepping remote repo git@ghe.snip/gitchainstore-synctest.git
2021-05-31 11:48:12,318 WARN  LoggingUtils.java:634 - exceptionCaught(JGitClientSession[git@ghe.ca-tools.org/52.69.168.141:22])[state=Opened] SshException: Server key did not validate
org.apache.sshd.common.SshException: Server key did not validate
    at org.apache.sshd.client.session.AbstractClientSession.checkKeys(AbstractClientSession.java:583) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.session.helpers.AbstractSession.handleKexMessage(AbstractSession.java:611) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.session.helpers.AbstractSession.doHandleMessage(AbstractSession.java:500) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.session.helpers.AbstractSession.handleMessage(AbstractSession.java:428) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.session.helpers.AbstractSession.decode(AbstractSession.java:1463) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.session.helpers.AbstractSession.messageReceived(AbstractSession.java:388) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.eclipse.jgit.internal.transport.sshd.JGitClientSession.messageReceived(JGitClientSession.java:197) ~[org.eclipse.jgit.ssh.apache-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
    at org.apache.sshd.common.session.helpers.AbstractSessionIoHandler.messageReceived(AbstractSessionIoHandler.java:64) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.io.nio2.Nio2Session.handleReadCycleCompletion(Nio2Session.java:358) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:335) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:332) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at org.apache.sshd.common.io.nio2.Nio2CompletionHandler.lambda$completed$0(Nio2CompletionHandler.java:38) ~[sshd-osgi-2.6.0.jar:2.6.0]
    at java.security.AccessController.doPrivileged(Native Method) ~[?:?]
    at org.apache.sshd.common.io.nio2.Nio2CompletionHandler.completed(Nio2CompletionHandler.java:37) [sshd-osgi-2.6.0.jar:2.6.0]
    at sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127) [?:?]
    at sun.nio.ch.Invoker$2.run(Invoker.java:219) [?:?]
    at sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112) [?:?]
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
    at java.lang.Thread.run(Thread.java:834) [?:?]
2021-05-31 11:48:12,331 INFO  SessionHelper.java:1034 - Disconnecting(JGitClientSession[git@ghe.ca-tools.org/52.69.168.141:22]): SSH2_DISCONNECT_HOST_KEY_NOT_VERIFIABLE - Server key did not validate

org.eclipse.jgit.api.errors.TransportException: git@ghe.snip/gitchainstore-synctest.git: Server key did not validate

    at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:224)
    at org.eclipse.jgit.api.PullCommand.call(PullCommand.java:263)
    at snip.GitChainRepository.setupRemote(GitChainRepository.java:173)
    at snip.GitChainRepository.start(GitChainRepository.java:144)
    at snip.GitChainRepositoryTest.setupGit(GitChainRepositoryTest.java:59)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:566)
    at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:59)
    at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
    at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:56)
    at org.junit.internal.runners.statements.RunBefores.invokeMethod(RunBefores.java:33)
    at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
    at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.BlockJUnit4ClassRunner$1.evaluate(BlockJUnit4ClassRunner.java:100)
    at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:366)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:103)
    at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:63)
    at org.junit.runners.ParentRunner$4.run(ParentRunner.java:331)
    at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:79)
    at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:329)
    at org.junit.runners.ParentRunner.access$100(ParentRunner.java:66)
    at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:293)
    at org.junit.runners.ParentRunner$3.evaluate(ParentRunner.java:306)
    at org.junit.runners.ParentRunner.run(ParentRunner.java:413)
    at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
    at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
    at com.intellij.rt.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:33)
    at com.intellij.rt.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:230)
    at com.intellij.rt.junit.JUnitStarter.main(JUnitStarter.java:58)
Caused by: org.eclipse.jgit.errors.TransportException: git@ghe.snip/gitchainstore-synctest.git: Server key did not validate
    at org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:248)
    at org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:1)
    at org.eclipse.jgit.transport.SshTransport.getSession(SshTransport.java:107)
    at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:281)
    at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:153)
    at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:142)
    at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:94)
    at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1309)
    at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:213)
    ... 31 more
Caused by: org.apache.sshd.common.SshException: Server key did not validate
    at org.apache.sshd.common.future.AbstractSshFuture.verifyResult(AbstractSshFuture.java:126)
    at org.apache.sshd.client.future.DefaultAuthFuture.verify(DefaultAuthFuture.java:39)
    at org.apache.sshd.client.future.DefaultAuthFuture.verify(DefaultAuthFuture.java:32)
    at org.apache.sshd.common.future.VerifiableFuture.verify(VerifiableFuture.java:68)
    at org.eclipse.jgit.transport.sshd.SshdSession.connect(SshdSession.java:164)
    at org.eclipse.jgit.transport.sshd.SshdSession.connect(SshdSession.java:99)
    at org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:235)
    ... 39 more
Caused by: org.apache.sshd.common.SshException: Server key did not validate
    at org.apache.sshd.client.session.AbstractClientSession.checkKeys(AbstractClientSession.java:583)
    at org.apache.sshd.common.session.helpers.AbstractSession.handleKexMessage(AbstractSession.java:611)
    at org.apache.sshd.common.session.helpers.AbstractSession.doHandleMessage(AbstractSession.java:500)
    at org.apache.sshd.common.session.helpers.AbstractSession.handleMessage(AbstractSession.java:428)
    at org.apache.sshd.common.session.helpers.AbstractSession.decode(AbstractSession.java:1463)
    at org.apache.sshd.common.session.helpers.AbstractSession.messageReceived(AbstractSession.java:388)
    at org.eclipse.jgit.internal.transport.sshd.JGitClientSession.messageReceived(JGitClientSession.java:197)
    at org.apache.sshd.common.session.helpers.AbstractSessionIoHandler.messageReceived(AbstractSessionIoHandler.java:64)
    at org.apache.sshd.common.io.nio2.Nio2Session.handleReadCycleCompletion(Nio2Session.java:358)
    at org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:335)
    at org.apache.sshd.common.io.nio2.Nio2Session$1.onCompleted(Nio2Session.java:332)
    at org.apache.sshd.common.io.nio2.Nio2CompletionHandler.lambda$completed$0(Nio2CompletionHandler.java:38)
    at java.base/java.security.AccessController.doPrivileged(Native Method)
    at org.apache.sshd.common.io.nio2.Nio2CompletionHandler.completed(Nio2CompletionHandler.java:37)
    at java.base/sun.nio.ch.Invoker.invokeUnchecked(Invoker.java:127)
    at java.base/sun.nio.ch.Invoker$2.run(Invoker.java:219)
    at java.base/sun.nio.ch.AsynchronousChannelGroupImpl$1.run(AsynchronousChannelGroupImpl.java:112)
    at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
    at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
    at java.base/java.lang.Thread.run(Thread.java:834)


Process finished with exit code -1

最后,我决定只覆盖默认的会话工厂,这是一种工作,但不是真正的工作。

代码语言:javascript
运行
复制
SshSessionFactory.setInstance(sshSessionFactory);

它最终会工作一段时间,但是会崩溃,无法从工厂创建新的会话(我还不知道为什么,但我还是不想覆盖默认实例,因此发布了这个问题)。

代码语言:javascript
运行
复制
org.eclipse.jgit.api.errors.TransportException: git@ghe.snip/gitchainstore-synctest.git: Apache MINA sshd session factory is closing down; cannot create new ssh sessions on this factory
        at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:224) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.api.PullCommand.call(PullCommand.java:263) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at snip.GitChainRepository.updateRemote(GitChainRepository.java:190) ~[core-0.1.0-28.jar:?]
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:515) [?:?]
        at java.util.concurrent.FutureTask.runAndReset(FutureTask.java:305) [?:?]
        at java.util.concurrent.ScheduledThreadPoolExecutor$ScheduledFutureTask.run(ScheduledThreadPoolExecutor.java:305) [?:?]
        at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128) [?:?]
        at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628) [?:?]
        at java.lang.Thread.run(Thread.java:829) [?:?]
Caused by: org.eclipse.jgit.errors.TransportException: git@ghe.snip/gitchainstore-synctest.git: Apache MINA sshd session factory is closing down; cannot create new ssh sessions on this factory
        at org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:248) ~[org.eclipse.jgit.ssh.apache-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:1) ~[org.eclipse.jgit.ssh.apache-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.SshTransport.getSession(SshTransport.java:107) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:281) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:153) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:142) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:94) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1309) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:213) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        ... 8 more
Caused by: java.io.IOException: Apache MINA sshd session factory is closing down; cannot create new ssh sessions on this factory
        at org.eclipse.jgit.transport.sshd.SshdSessionFactory.register(SshdSessionFactory.java:272) ~[org.eclipse.jgit.ssh.apache-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:234) ~[org.eclipse.jgit.ssh.apache-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.sshd.SshdSessionFactory.getSession(SshdSessionFactory.java:1) ~[org.eclipse.jgit.ssh.apache-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.SshTransport.getSession(SshTransport.java:107) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.TransportGitSsh$SshFetchConnection.<init>(TransportGitSsh.java:281) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.TransportGitSsh.openFetch(TransportGitSsh.java:153) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.FetchProcess.executeImp(FetchProcess.java:142) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.FetchProcess.execute(FetchProcess.java:94) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.transport.Transport.fetch(Transport.java:1309) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        at org.eclipse.jgit.api.FetchCommand.call(FetchCommand.java:213) ~[org.eclipse.jgit-5.11.0.202103091610-r.jar:5.11.0.202103091610-r]
        ... 8 more

因此,总之:什么是自定义ssh会话创建并确保它通过调用其他命令的瓷器命令持续存在的正确方法?这是带有jgit的bug吗?我是错过了什么,还是做错了什么?

EN

回答 5

Stack Overflow用户

回答已采纳

发布于 2021-09-22 08:22:04

代码语言:javascript
运行
复制
File sshDir = new File(FS.DETECTED.userHome(), "/.ssh");
SshdSessionFactory sshSessionFactory = new SshdSessionFactoryBuilder()
        .setPreferredAuthentications("publickey")
        .setHomeDirectory(FS.DETECTED.userHome())
        .setSshDirectory(sshDir)
        .build(null);

上面的代码适用于我,只需要将id_rsa文件放在.ssh文件夹中即可。钥匙必须没有密码。还在寻找用钥匙传递密码的方法。

您可以使用此链接来更好地理解:https://medium.com/@pratikshende99/how-to-clone-git-repo-with-ssh-url-by-executing-command-through-java-using-processbuilder-e162010266f5

票数 2
EN

Stack Overflow用户

发布于 2021-06-04 00:06:04

我不认为你错过了什么。有一个回调钩子可以在命令上使用,您可以在其中插入配置代码。我从没和米娜合作过。我asked a similar question,但在这里一直没有得到答案。如果你知道怎么做,请张贴,因为这是一个特别具有挑战性的课题。

票数 0
EN

Stack Overflow用户

发布于 2022-01-10 02:33:51

使用JGit版本6.0.202111291000-r,我能够使用Apache执行传输命令。为了这个,

TransportCommand.回调中的

  • 设置CustomSshSessionFactory

代码语言:javascript
运行
复制
cmd.setTransportConfigCallback(
transport -> {
  if(transport instanceOf SshTransport) {
    SshTransport sshTransport = (SshTransport) transport;
    // Set passphrase using a CustomCredentialsProvider
    sshTransport.setCredentialsProvider(new CustomCredentialProvider(passphrase));
    // Provide private key to `CustomSshSessionFactory`
    SshSessionFactory sshFactory = new CustomSshSessionFactory(privatekey);
    sshTransport.setSshSessionFactory(sshFactory);

  }
});

  • 创建了SshdSessionFactory的实现。你也可以使用SshdSessionFactoryBuilder

代码语言:javascript
运行
复制
public final class CustomSshSessionFactory extends SshdSessionFactory {


    public static final Path SSH_DIR = Path.of("some-path");

    private final Path privateKeyFile;
    private final byte[] sshKey;

    public CustomSshSessionFactory(byte[] sshKey) {
        this.sshKey = sshKey;
        privateKeyFile = Path.of("some-name", SSH_DIR.toString());
    }

    @Override
    public File getSshDirectory() {
        try {
            return Files.createDirectories(SSH_DIR).toFile();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

// Return paths to private key files
    @Override
    protected List<Path> getDefaultIdentities(File sshDir) {
        try {
            Files.write(privateKeyFile, sshKey);
            return Collections.singletonList(privateKeyFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return Collections.emptyList();
    }

}

CredentialsProvider的自定义实现

代码语言:javascript
运行
复制
public class CustomCredentialProvider extends CredentialsProvider {

    private final List<String> stringStore;

    private final String passphrase;

    public CustomCredentialProvider(String passphrase) {
        this.passphrase = passphrase;
    }

    @Override
    public boolean isInteractive() {
        // Set this according to your requirement
        return false;
    }

    @Override
    public boolean supports(CredentialItem... items) {
        // Set this according to your requirement
        return true;
    }

    @Override
    public boolean get(URIish uri, CredentialItem... items)
            throws UnsupportedCredentialItem {

        for (CredentialItem item : items) {
            if (item instanceof CredentialItem.InformationalMessage) {
                continue;
            }
            if (item instanceof CredentialItem.YesNoType) {
                // Set this according to your requirement
                ((CredentialItem.YesNoType) item).setValue(true);
            } else if (item instanceof CredentialItem.CharArrayType) {
                if (passphrase != null) {
                    ((CredentialItem.CharArrayType) item)
                            .setValue(passphrase.toCharArray());
                } else {
                    return false;
                }
            } else if (item instanceof CredentialItem.StringType) {
                if (passphrase != null) {
                    ((CredentialItem.StringType) item)
                            .setValue(passphrase);
                } else {
                    return false;
                }
            } else {
                return false;
            }
        }
        return true;
    }
}

在这里,需要注意的重要事情是

通过CredentialsProvider

  • private密钥的自定义实现设置密码的
  • 作为文件输入到SshSessionFactory
票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/67767455

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档