[英]Swift-NIO secured websocket server
I am trying to create websocket server and client in my iOS app, which i successfully managed to do with the help of sample implementation here.我正在尝试在我的 iOS 应用程序中创建 websocket 服务器和客户端,我在示例实现的帮助下成功地做到了。 ( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketServer ) - so current working situation is, i run the websocket server when app launches and then I load the client in a webview which can connect to it. ( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketServer ) - 所以当前的工作情况是,我在应用程序启动时运行 websocket 服务器,然后在可以连接的 webview 中加载客户端到它。
Now my problem is I want my server to secured websocket server (Basically connect to the websocket server from a HTTPS html page)现在我的问题是我希望我的服务器保护 websocket 服务器(基本上从 HTTPS html 页面连接到 websocket 服务器)
I am new to network programming and Swift-nio documentation is lacking to say the least.我是网络编程的新手,至少可以说缺乏 Swift-nio 文档。 As far as I understand I could use ( https://github.com/apple/swift-nio-transport-services )据我所知,我可以使用( https://github.com/apple/swift-nio-transport-services )
I found this thread which is exactly what I need -https://github.com/apple/swift-nio-transport-services/issues/39 - I could disable the TLS authentication as I dont care in my usecase as long as I could get the websocket connected.我发现这个线程正是我需要的 -https://github.com/apple/swift-nio-transport-services/issues/39 - 我可以禁用 TLS 身份验证,因为我不在乎我的用例,只要我可以连接 websocket。
So my question is how to I extend my client ( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketClient ) and server ( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketServer ) to use swift-nio-transport-service.所以我的问题是如何扩展我的客户端( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketClient )和服务器( https://github.com/apple/swift-nio/ tree/master/Sources/NIOWebSocketServer ) 来使用 swift-nio-transport-service。
I could add the NIOSSLContext
and stuff but I think I need to add the EventLoopGroup
and new bootstrap
methods.我可以添加NIOSSLContext
和其他东西,但我想我需要添加EventLoopGroup
和新的bootstrap
方法。 I know the answers is right there.... but I just cannot seem to pinpoint it.我知道答案就在那里......但我似乎无法确定它。
Any pointer would be appreciated.任何指针将不胜感激。
Thanks.谢谢。
To translate a simple NIO
Server to a NIOTransportServices
one, you need to make the following changes:要将简单的NIO
Server 转换为NIOTransportServices
,您需要进行以下更改:
NIOTransportServices
to your server.向您的服务器添加对NIOTransportServices
的依赖。MultiThreadedEventLoopGroup
to NIOTSEventLoopGroup
.将MultiThreadedEventLoopGroup
更改为NIOTSEventLoopGroup
。ClientBootstrap
to NIOTSConnectionBootstrap
.更改ClientBootstrap
到NIOTSConnectionBootstrap
。ServerBootstrap
to NIOTSListenerBootstrap
.更改ServerBootstrap
到NIOTSListenerBootstrap
。 Some ChannelOption
s don't work in NIOTransportServices
, but most do: the easiest way to confirm that things are behaving properly is to quickly test the common flow.一些ChannelOption
不能在NIOTransportServices
工作,但大多数可以:确认事情正常运行的最简单方法是快速测试公共流程。
This doesn't add any extra functionality to your application, but it does give you the same functionality using the iOS APIs.这不会为您的应用程序添加任何额外的功能,但它确实为您提供了使用 iOS API 的相同功能。
To add TLS to either NIOTSConnectionBootstrap
or NIOTSListenerBootstrap
, you use the .tlsOptions
function.要将 TLS 添加到NIOTSConnectionBootstrap
或NIOTSListenerBootstrap
,请使用.tlsOptions
函数。 For example:例如:
NIOTSListenerBootstrap(group: group)
.tlsOptions(myTLSOptions())
Configuring a NWProtocolTLS.Options
is a somewhat tricky thing to do.配置NWProtocolTLS.Options
是一件有点棘手的事情。 You need to obtain a SecIdentity
, which requires interacting with the keychain.您需要获得一个SecIdentity
,这需要与钥匙串进行交互。 Quinn has discussed this somewhat here .奎因已经有所讨论过这个位置。
Once you have a SecIdentity
, you can use it like so:拥有SecIdentity
,您可以像这样使用它:
func myTLSOptions() -> NWProtocolTLS.Options {
let options = NWProtocolTLS.Options()
let yourSecIdentity = // you have to implement something here
sec_protocol_options_set_local_identity(options.securityProtocolOptions, sec_identity_create(yourSecIdentity)
return options
}
Once you have that code written, everything should go smoothly!一旦您编写了该代码,一切都会顺利进行!
As an extension, if you wanted to secure a NIO server on Linux, you can do so using swift-nio-ssl .作为扩展,如果您想保护 Linux 上的 NIO 服务器,您可以使用swift-nio-ssl 来实现。 This has separate configuration as the keychain APIs are not available, and so you do a lot more loading of keys and certificates from files.这有单独的配置,因为钥匙串 API 不可用,因此您需要从文件中加载更多的密钥和证书。
I needed a secure websocket without using SecIdentity
or NIOTransportServices
, so based on @Lukasa's hint about swift-nio-ssl
I cobbled together an example that appears to work correctly.我需要一个不使用SecIdentity
或NIOTransportServices
的安全 websocket,因此基于@Lukasa 关于swift-nio-ssl
的提示,我拼凑了一个似乎可以正常工作的示例。
I dunno if it's correct, but I'm putting it here in case someone else can benefit.我不知道它是否正确,但我把它放在这里以防其他人可以受益。 Error-handling and aborting when the try
's fail is left out for brevity.为简洁起见,省略了try
失败时的错误处理和中止。
let configuration = TLSConfiguration.forServer(certificateChain: try! NIOSSLCertificate.fromPEMFile("/path/to/your/tlsCert.pem").map { .certificate($0) }, privateKey: .file("/path/to/your/tlsKey.pem"))
let sslContext = try! NIOSSLContext(configuration: configuration)
let upgradePipelineHandler: (Channel, HTTPRequestHead) -> EventLoopFuture<Void> = { channel, req in
WebSocket.server(on: channel) { ws in
ws.send("You have connected to WebSocket")
ws.onText { ws, string in
print("Received text: \(string)")
}
ws.onBinary { ws, buffer in
// We don't accept any Binary data
}
ws.onClose.whenSuccess { value in
print("onClose")
}
}
}
self.eventLoopGroup = MultiThreadedEventLoopGroup(numberOfThreads: 2)
let port: Int = 5759
let promise = self.eventLoopGroup!.next().makePromise(of: String.self)
_ = try? ServerBootstrap(group: self.eventLoopGroup!)
// Specify backlog and enable SO_REUSEADDR for the server itself
.serverChannelOption(ChannelOptions.backlog, value: 256)
.serverChannelOption(ChannelOptions.socketOption(.so_reuseaddr), value: 1)
.childChannelInitializer { channel in
let handler = NIOSSLServerHandler(context: sslContext)
_ = channel.pipeline.addHandler(handler)
let webSocket = NIOWebSocketServerUpgrader(
shouldUpgrade: { channel, req in
return channel.eventLoop.makeSucceededFuture([:])
},
upgradePipelineHandler: upgradePipelineHandler
)
return channel.pipeline.configureHTTPServerPipeline(
withServerUpgrade: (
upgraders: [webSocket],
completionHandler: { ctx in
// complete
})
)
}.bind(host: "0.0.0.0", port: port).wait()
_ = try! promise.futureResult.wait()
try! server.close(mode: .all).wait()
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.