Swift-NIO защищенный сервер веб-сокетов
Я пытаюсь создать сервер и клиент websocket в своем приложении для iOS, что мне успешно удалось сделать с помощью примера реализации здесь. ( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketServer) - поэтому в текущей рабочей ситуации я запускаю сервер websocket при запуске приложения, а затем загружаю клиент в веб-представление, которое может подключиться к этому.
Теперь моя проблема в том, что я хочу, чтобы мой сервер был защищенным сервером веб-сокетов (в основном, подключение к серверу веб-сокетов со страницы HTTPS html)
Я новичок в сетевом программировании, и документации Swift-nio по меньшей мере не хватает. Насколько я понимаю, я мог бы использовать ( https://github.com/apple/swift-nio-transport-services)
Я нашел эту ветку, которая именно то, что мне нужно - https://github.com/apple/swift-nio-transport-services/issues/39 - я мог бы отключить аутентификацию TLS, так как мне все равно, в моем случае использования, пока я можно подключить веб-сокет.
Поэтому мой вопрос заключается в том, как расширить свой клиент ( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketClient) и сервер ( https://github.com/apple/swift-nio/tree/master/Sources/NIOWebSocketServer) для использования swift-nio-transport-service.
Я мог бы добавить NIOSSLContext
и прочее, но я думаю, что мне нужно добавить EventLoopGroup
и новый bootstrap
методы. Я знаю, что ответы прямо здесь.... но я просто не могу точно определить это.
Любой указатель будет оценен.
Благодарю.
1 ответ
Чтобы перевести простой NIO
Сервер к NIOTransportServices
Во-первых, вам необходимо внести следующие изменения:
- Добавить зависимость от
NIOTransportServices
на ваш сервер. - + Изменить
MultiThreadedEventLoopGroup
вNIOTSEventLoopGroup
, - + Изменить
ClientBootstrap
вNIOTSConnectionBootstrap
, - + Изменить
ServerBootstrap
вNIOTSListenerBootstrap
, - Создайте и запустите свой код.
Несколько ChannelOption
не работают в NIOTransportServices
Но большинство так и делает: самый простой способ подтвердить, что все работает правильно, - это быстро проверить общий поток.
Это не добавляет никаких дополнительных функциональных возможностей к вашему приложению, но дает те же функциональные возможности с использованием API-интерфейсов iOS.
Чтобы добавить TLS либо NIOTSConnectionBootstrap
или же NIOTSListenerBootstrap
Вы используете .tlsOptions
функция. Например:
NIOTSListenerBootstrap(group: group)
.tlsOptions(myTLSOptions())
Конфигурирование NWProtocolTLS.Options
это довольно сложная вещь. Вам необходимо получить SecIdentity
, который требует взаимодействия с цепочкой для ключей. Куинн несколько обсуждал это здесь.
Когда у вас есть 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
}
Как только вы написали этот код, все должно пройти гладко!
В качестве расширения, если вы хотите защитить сервер NIO в Linux, вы можете сделать это с помощью swift-nio-ssl. Это имеет отдельную конфигурацию, так как API цепочки для ключей недоступны, и поэтому вы делаете гораздо больше загрузки ключей и сертификатов из файлов.
Мне нужен был безопасный веб-сокет без использования
SecIdentity
или же
NIOTransportServices
, поэтому на основе намека @Lukasa на
swift-nio-ssl
Я собрал пример, который, похоже, работает правильно.
Я не знаю, правильно ли это, но я помещаю это здесь на случай, если кому-то еще может быть полезно. Обработка ошибок и прерывание, когда
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()