GRPC - это относительно новая концепция взаимодействия между клиентом и сервером, но не более.
gRPC client-serverЧто такое удаленный вызов процедур (RPC)?
Удаленный вызов процедуры - это протокол связи программного обеспечения. Один процесс может вызвать процедуру (также известную как функция или подпрограмма) на удаленной системе (например, локальной) без предварительного знания сети удаленной системы.
RPC использует традиционную модель "клиент-сервер". Сервер определяет процедуры, а клиент запрашивает удаленные серверы для применения бизнес-логики и возврата результата.
Rest vs gRPC:
Передача репрезентативного состояния (REST) - это коммуникационный протокол взаимодействия между клиентом и сервером, построенный на основе HTTP 1.1/HTTPS 1.1 с такими глаголами, как (PUT, POST, GET и т.д.).
GRPC - это удаленный вызов протокола от Google, кроссплатформенный коммуникационный протокол с открытым исходным кодом, основанный на контрактах и упрощающий межсервисное взаимодействие.
GRPC использует двунаправленную функцию HTTP/2.0 и TLS. gRPC также обеспечивает более эффективную коммуникацию через сериализованные двоичные полезные нагрузки. В качестве механизма управления и сериализации полезной нагрузки он использует буфер протокола, подобно JSON в Rest.
В отличие от JSON буфер протокола также состоит из трех основных частей:
В отличие от HTTP/1.1, который последовательно загружает ресурсы, HTTP/2.0 использует TCP-соединение и одно соединение для передачи многих потоков данных, поэтому блокировка ресурсов отсутствует. В HTTP/1.1 мы можем столкнуться с проблемой, если ресурс не сможет загрузиться, последовательность будет заблокирована.
Что такое proto3?
syntax = 'proto3'; package bookStorePackage; // Book service definition. defines all the rpc methods here service Book { rpc createBook (BookItemReq) returns (BookItem); rpc readBook (BookRequest) returns (BookItem); rpc readBooks (Empty) returns (BooksList); } // inputs / request , e.g. BookItemReq // outputs / response BookItem must be defined // they are defined with a keyword of struct message BookItemReq { string name = 1; string description = 2; string author = 3; } message BookItem { int32 id = 1; string name = 2; string description = 3; string author = 4; } message BookRequest { int32 id = 1; } message BooksList { repeated BookItem books = 1; } message Empty {}
Файл `.proto` содержит структуру нашего gRPC и определяет процедуры и запросы/ответы для каждого вызова. Файлы .proto транслируются в файлы буферов proto с помощью плагина protoc.
protoc --proto_path=src --java_out=build/gen PROTO_PATH
Давайте теперь подробнее рассмотрим код. Вы можете найти много ресурсов для реализации gRPC без TLS. Мы рассмотрим создание клиента gRPC на android с TLS.
Некоторые требования перед началом работы: безопасный gRPC-сервер, написанный на любом языке.
Как это сделать для Android Studio:
Во-первых, нам нужно создать новый проект в android. В этом проекте мы будем использовать пустую активность. Затем установите зависимости и добавьте следующее в build.gradle.
plugins { id 'com.google.protobuf' version '0.8.18' } // this is used to generate proto buf file when you build the project protobuf { protoc { artifact="com.google.protobuf:protoc:3.21.7" } plugins { grpc { artifact = 'io.grpc:protoc-gen-grpc-java:1.51.0' } } generateProtoTasks { all().each { task -> task.builtins { java { option 'lite' } } task.plugins { grpc { option 'lite' } } } } } dependencies { // for TLS based connection we need okhttp implementation 'io.grpc:grpc-okhttp:1.51.1' implementation 'io.grpc:grpc-protobuf-lite:1.51.1' implementation 'io.grpc:grpc-stub:1.51.1' // these are used to set up a secure client implementation 'com.squareup.okhttp3:okhttp-tls:4.10.0' implementation 'com.squareup.okhttp3:okhttp:4.10.0' }
Теперь нам нужно добавить файл proto в наш проект.
File Structure Section in Android StudioНам нужно изменить структуру с android на проект. Теперь мы можем добавить наш файл proto в app/src/main/proto. Нам нужно создать каталог с именем proto и поместить туда наш файл .proto.
Proto file destination app/src/main/protoТеперь нам нужно собрать наш проект с помощью панели инструментов > build > rebuild project.
rebuild project to get generated code.Вот сгенерированный файл, который вы получите.
auto-generated protocol buffer files.BookGrpc auto-generated classОдин важный момент, как мы знаем, в java мы имеем определенное имя пакета в нашем проекте. Как мы можем указать его в нашем proto файле?
Очень просто. Нам нужно добавить опцию для java, чтобы направлять компилятор (protoc) при генерации буферного файла proto.
proto file with java optionsДобавив эту опцию в наш файл proto, наш компилятор поймет, что ему нужно указать имя пакета, которое мы навязали. По умолчанию он будет использовать ключевое слово package в качестве имени нашего пакета.
Теперь давайте разберемся, как настроить нашего клиента на взаимодействие с сервером gRPC через защищенное соединение.
Мы должны поместить наш сертификат подписи в категорию raw в папке res нашего приложения.
location to add the signing certificateПосле размещения сертификата нам нужно просто использовать следующий фрагмент кода, и мы сможем легко взаимодействовать с нашим защищенным сервером.
try{ Resources res = getResources(); InputStream instream = res.openRawResource(R.raw.ca_cert); CertificateFactory cf = CertificateFactory.getInstance("X.509"); Certificate ca = cf.generateCertificate(instream); KeyStore kStore = KeyStore.getInstance(KeyStore.getDefaultType()); kStore.load(null, null); kStore.setCertificateEntry("ca", ca); TrustManagerFactory tmf = TrustManagerFactory .getInstance(TrustManagerFactory.getDefaultAlgorithm()); tmf.init(kStore); TrustManager[] trustManagers = tmf.getTrustManagers(); if (trustManagers.length != 1 || !(trustManagers[0] instanceof X509TrustManager)) { throw new IllegalStateException("Unexpected default trust managers:" + Arrays.toString(trustManagers)); } SSLContext context = SSLContext.getInstance("TLS"); context.init(null, tmf.getTrustManagers(), null); SSLSocketFactory sslSocketFactory = context.getSocketFactory(); final ManagedChannel channel = OkHttpChannelBuilder .forAddress("IP Address",PORT) .useTransportSecurity() .overrideAuthority("add same DNS / IP:PORT entry here") .sslSocketFactory(sslSocketFactory) .build(); // BookGrpc is an auto generated class from the proto we defined. BookGrpc.BookBlockingStub stub = BookGrpc.newBlockingStub(channel); // create a request object BookItemReq requestData = BookItemReq .newBuilder() .setName("AnyName") .setAuthor("AnyAuthor") .setDescription("Any Description") .build(); BookItem response = stub.createBook(requestData); // handle the response System.out.println(response); channel.shutdown(); } catch (Exception e){ e.printStackTrace(); }
Используя предоставленный пример кода, вы можете взаимодействовать с вашим защищенным сервером gRPC.
Что делает этот код?
Как мы знаем, чтобы установить безопасное соединение, у нас есть набор сертификатов, которые гарантируют, что наша связь зашифрована. Нам нужно добавить сертификат подписи в наше android-приложение.
Далее мы считываем сертификат с помощью следующих строк.
Resources res = getResources(); InputStream instream = res.openRawResource(R.raw.ca_cert);
Сначала мы получаем экземпляр ресурса, затем используем функцию openRawResource для чтения нашего сертификата. Затем мы генерируем сертификат из нашего файла и добавляем его в качестве доверенного сертификата. Используя доверенный сертификат, мы инициализируем экземпляр контекста SSL для инициализации фабрики сокетов SSL. Фабрика сокетов SSL действует как фактор защищенных сокетов.
Зашифрованный канал обрабатывает запросы и ответы от сервера. Мы использовали OkHttpChannelBuilder, который поддерживает использование SSLSocketFactor для обеспечения безопасной среды связи между клиентом и сервером.
Как получить сертификаты самостоятельно?
Для генерации сертификатов вы можете использовать следующий скрипт:
rm *.pem rm *.srl rm *.cnf # 1. Generate CA's private key and self-signed certificate openssl req -x509 -newkey rsa:4096 -days 365 -nodes -keyout ca-key.pem -out ca-cert.pem -subj "/C=FR/ST=Occitanie/L=Toulouse/O=Test Org/OU=Test/CN=*.test/[email protected]" echo "CA's self-signed certificate" openssl x509 -in ca-cert.pem -noout -text # 2. Generate web server's private key and certificate signing request (CSR) openssl req -newkey rsa:4096 -nodes -keyout server-key.pem -out server-req.pem -subj "/C=FR/ST=Ile de France/L=Paris/O=Server TLS/OU=Server/CN=*.tls/[email protected]" # Remember that when we develop on localhost, It’s important to add the IP:0.0.0.0 as an Subject Alternative Name (SAN) extension to the certificate. echo "subjectAltName=DNS:*.tls,DNS:example.com,IP:0.0.0.0" > server-ext.cnf # Or you can use localhost DNS and grpc.ssl_target_name_override variable # echo "subjectAltName=DNS:localhost" > server-ext.cnf # 3. Use CA's private key to sign web server's CSR and get back the signed certificate openssl x509 -req -in server-req.pem -days 60 -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out server-cert.pem -extfile server-ext.cnf echo "Server's signed certificate" openssl x509 -in server-cert.pem -noout -text # 4. Generate client's private key and certificate signing request (CSR) openssl req -newkey rsa:4096 -nodes -keyout client-key.pem -out client-req.pem -subj "/C=FR/ST=Alsace/L=Strasbourg/O=PC Client/OU=Computer/CN=*.client.com/[email protected]" # Remember that when we develop on localhost, It’s important to add the IP:0.0.0.0 as an Subject Alternative Name (SAN) extension to the certificate. echo "subjectAltName=DNS:eaple.com,IP:0.0.0.0" > client-ext.cnf # 5. Use CA's private key to sign client's CSR and get back the signed certificate openssl x509 -req -in client-req.pem -days 60 -CA ca-cert.pem -CAkey ca-key.pem -CAcreateserial -out client-cert.pem -extfile client-ext.cnf echo "Client's signed certificate" openssl x509 -in client-cert.pem -noout -text
Примечание: Полный код вы можете найти на сайте https://github.com/AbdullahJanKhan/android-grpc-tls
20.08.2023 18:21
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в 2023-2024 годах? Или это полная лажа?".
20.08.2023 17:46
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
19.08.2023 18:39
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в частности, магию поплавков и гибкость flexbox.
19.08.2023 17:22
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для чтения благодаря своей простоте. Кроме того, мы всегда хотим проверить самые последние возможности в наших проектах!
18.08.2023 20:33
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий их языку и культуре.
14.08.2023 14:49
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип предназначен для представления неделимого значения.