验证机制在JGit中大部分与本地git相同。普遍使用SSH协议和HTTP(S)协议和他们所支持的验证方法。
这篇文章总结了如何使用JGit的验证API去安全连接远程GIT库。
虽然在下面的例子中使用的是CloneCommand方法,但是它能实现的方法可以应用到所有用于连接远程仓库的类,例如FetchCommand,PushCommand,LsRemoteCommand等等。所有这些命令都有一个相同的基本类-TransportCommand,它能提供我们所实例的所有方法。
通过HTTP和HTTPS的验证方式很直接。一个继承CredentialsProvider类用于返回命令所需要的认证凭证。用于某个命令的CredentialsProvider类可以被setCredentialsProvider()方法指定。
例如,下面的代码通过HTTPS方法克隆远程库,并且使用用户名和密码作为验证。
CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI( "https://example.com/repo.git" );
cloneCommand.setCredentialsProvider( new UsernamePasswordCredentialsProvider( "user", "password" ) );
UsernamePasswordCredentialsProvider 继承于JGit中的CredentialsProvider类,使用给定的用户名和密码进行验证。
或者JGit(3.5版本或者以上)也可以从用户的.netrc文件中读取到凭证。NetRCCredentialsProvider 使用文件中的第一个计算机条目进行验证。
虽然不推荐通过不安全的连接发送凭证,但是上述的方式同样使用于纯HTTP协议,就像 http://example.com/repo.git.
JGit委托抽象的SSHSessionFactory去创建销毁SSH连接。为了使用SSH的公钥认证,必须指定一个session Factory类。
通过 setTransportConfigCallback(),可以指定一个TransportConfigCallback 接口去拦截连接进程。它有一个单独的方法-configure(),在一个连接建立后被调用。它会传输一个传输类型的参数用来在本地和远程库之间拷贝对象。对于每个协议都有一个确切的传输子类来处理该协议的细节。
如下所示,回调可以用在配置正确的传输实例之前投入使用。
SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
@Override
protected void configure( Host host, Session session ) {
// do nothing
}
};
CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI( "ssh://[email protected]/repo.git" );
cloneCommand.setTransportConfigCallback( new TransportConfigCallback() {
@Override
public void configure( Transport transport ) {
SshTransport sshTransport = ( SshTransport )transport;
sshTransport.setSshSessionFactory( sshSessionFactory );
}
} );
JGit 提供了一个抽象的JSchConfigSessionFactory 可以使用JSch去建立SSH连接并且要求configure()要被覆盖。因为在最简单的例子中并没有任何东西区需要去配置,上方的例子中提供了一个空的方法为了编译通过。JSchConfig SessionFactory与OpenSSH最兼容,因为继承了原始Git使用的SSH实现。她加载了在用户.ssh目录中默认的路径(identity,id_rsa和id_dsa)中已知的端口和秘钥。
如果你的密钥文件名字不同或者放置在其他地方,我建议你重写createDefaultJSch()方法。在调用了基本的方法后,用户秘钥的可以如下面的方法进行添加:
@Override
protected JSch createDefaultJSch( FS fs ) throws JSchException {
JSch defaultJSch = super.createDefaultJSch( fs );
defaultJSch.addIdentity( "/path/to/private_key" )
return defaultJSch;
}
在这个例子中添加了一个用户自定义位置的私钥。如果你查看了JSchJavaDoc,你会发现进一步重载的addIdentity()方法。
为了完整起见,我应该提到还有一个 global sessionFactory。它可以通过SSHSessionFactory去获取和更改,如果没有为命令配置特定的SessionFactory,则用作默认值。但是我建议避免使用它,除了使编写隔离测试更为困难外,可能还有一些代码不在你的控制之中,改变了它。
通过公钥使用SSH,一个SshSessionFctory 必须指定使用密保连接SSH。但是在这种情况下,session Factory的configure()方法要有一个配置。
SshSessionFactory sshSessionFactory = new JschConfigSessionFactory() {
@Override
protected void configure( Host host, Session session ) {
session.setPassword( "password" );
}
} );
CloneCommand cloneCommand = Git.cloneRepository();
cloneCommand.setURI( "ssh://[email protected]/repo.git" );
cloneCommand.setTransportConfigCallback( new TransportConfigCallback() {
@Override
public void configure( Transport transport ) {
SshTransport sshTransport = ( SshTransport )transport;
sshTransport.setSshSessionFactory( sshSessionFactory );
}
} );
一个 Jsch session代表了到服务器的连接。第四行设置了此次会话的密码。其余代码与用于通过SSH连接到公钥认证的代码相同。
一些在这里讨论到的验证方法也可以组合使用。例如,在尝试通过带有公用密钥的SSH连接到远程存储库时设置凭据提供程序不会受到影响。 然而,你通常想知道什么Transport将被用于给定的仓库URL。
为了确定这些,可以使用TransportProtocol的canHandle()方法。 如果协议可以处理给定的URL,则返回true,否则返回false。 所有已注册的TransportProtocols的列表可以从Transport.getTransportProtocols()获取。 一旦知道协议,就可以选择适当的认证方法。
GitHub支持各种协议和认证方法,但肯定不是所有可能方法的组合。 例如,尝试使用SSH进行密码身份验证是常见的错误。 但是不支持此组合 - 只有使用公钥的SSH可以。
GitHUb提供的协议列表中指出了什么是支持的,什么是不支持的。总结如下:
虽然我发现验证机制在JGit API中有点广泛散布,但是他们能完成任务。这里给出的方案希望为您提供在JGit中认证连接所需的基础知识,隐藏API的复杂性可以被看作是编写干净的代码的练习!