好的,所以也许是个人的第一次,我在发布这个问题之后找到了答案,那是在过去几个小时搜索谷歌之后。因此,我将分享我的发现,希望可以帮助其他人。
在发现 Apache 使用 SNI 将虚拟主机映射到多个证书后,我发现 Netty 有一个名为 SniHandler 的类,显然服务器端 SNI 支持大部分仅在 Java 8 中可用。我最近刚刚将所需的最低版本更新为Java 8,一切都很好。在稍微弄乱了类之后,我能够轻松地将 SniHandler 放在我的服务器范围的 SSL 实现之间,并为每个虚拟主机添加额外的证书。这就是我对 Netty 爱恨交织的原因,它通常有一个很好的内置解决方案,但我很难找到它。
以防万一这里是我的源代码,你可以在https://github.com/ChioriGreene/ChioriWebServer找到我的整个网络服务器项目
SslContextFactory.class
public class SslContextFactory
{
private static DomainNameMapping<SslContext> mapping;
private SslContextFactory()
{
}
public static void addMapping( String hostname, SslContext context )
{
// Using *.example.com will include all subdomains, including the root TLD
mapping.add( hostname, context );
}
public static SniHandler getSniHandler()
{
return new SniHandler( mapping );
}
public static void init() throws StartupException
{
final File sslCert = new File( "server.crt" );
final File sslKey = new File( "server.key" );
final String sslSecret = "SslSecret";
if ( !sslCert.exists() )
throw new StartupException( "We could not start the HTTPS Server because the '" + sslCert.getName() + "' (aka. SSL Cert) file does not exist. Please generate one and reload the server, or disable SSL in the configs." );
try
{
NetworkManager.getLogger().info( String.format( "Initalizing the SslContext using cert '%s', key '%s', and hasSecret? %s", sslCert.getName(), sslKey.getName(), ( sslSecret != null && !sslSecret.isEmpty() ) ) );
SslContext sslContext;
if ( sslSecret == null || sslSecret.isEmpty() )
sslContext = SslContext.newServerContext( sslCert, sslKey );
else
sslContext = SslContext.newServerContext( sslCert, sslKey, sslSecret );
mapping = new DomainNameMapping<SslContext>( sslContext );
}
catch ( SSLException e )
{
throw new StartupException( "We could not start the HTTPS Server because " + e.getMessage(), e );
}
catch ( Exception e )
{
throw new StartupException( "We could not start the HTTPS Server for an uncaught exception", e );
}
}
}
HttpsInitializer.class
public class HttpsInitializer extends ChannelInitializer<SocketChannel>
{
@Override
protected void initChannel( SocketChannel ch ) throws Exception
{
ChannelPipeline p = ch.pipeline();
try
{
p.addLast( SslContextFactory.getSniHandler() );
}
catch ( Exception e )
{
NetworkManager.shutdownHttpsServer();
throw new IllegalStateException( "The SSL engine failed to initalize", e );
}
p.addLast( "decoder", new HttpRequestDecoder() );
p.addLast( "aggregator", new HttpObjectAggregator( 104857600 ) );
p.addLast( "encoder", new HttpResponseEncoder() );
p.addLast( "deflater", new HttpContentCompressor() );
p.addLast( "handler", new HttpsHandler() );
}
}