Implementing a gRPC Service

quarkus-grpc 会自动注册并提供公开为 CDI Bean 的 gRPC 服务实现。

gRPC service implementations exposed as CDI beans are automatically registered and served by quarkus-grpc.

实现 gRPC 服务需要生成 gRPC 类。将 proto 文件放入 src/main/proto 并运行 mvn compile

Implementing a gRPC service requires the gRPC classes to be generated. Place your proto files in src/main/proto and run mvn compile.

Generated Code

Quarkus 会为在 proto 文件中声明的服务生成一些实现类:

Quarkus generates a few implementation classes for services declared in the proto file:

  1. A service interface using the Mutiny API

    • the class name is ${JAVA_PACKAGE}.${NAME_OF_THE_SERVICE}

  2. An implementation base class using the gRPC API

    • the class name is structured as follows: ${JAVA_PACKAGE}.${NAME_OF_THE_SERVICE}Grpc.${NAME_OF_THE_SERVICE}ImplBase

例如,如果您使用以下 proto 文件片段:

For example, if you use the following proto file snippet:

option java_package = "hello"; 1

service Greeter { 2
    rpc SayHello (HelloRequest) returns (HelloReply) {}
}
1 hello is the java package for the generated classes.
2 Greeter is the service name.

然后服务接口是 hello.Greeter,实现基础是抽象静态嵌套类: hello.GreeterGrpc.GreeterImplBase

Then the service interface is hello.Greeter and the implementation base is the abstract static nested class: hello.GreeterGrpc.GreeterImplBase.

您需要实现 service interface 或使用服务实现 Bean 扩展 base class,如以下部分所述。

You’ll need to implement the service interface or extend the base class with your service implementation bean as described in the following sections.

Implementing a Service with the Mutiny API

要使用 Mutiny API 实现 gRPC 服务,创建一个实现服务接口的类。然后,实现服务接口中定义的方法。如果您不想实现服务方法,只需从方法体中抛出 java.lang.UnsupportedOperationException (异常将自动转换为适当的 gRPC 异常)。最后,实现服务并添加 @GrpcService 注释:

To implement a gRPC service using the Mutiny API, create a class that implements the service interface. Then, implement the methods defined in the service interface. If you don’t want to implement a service method just throw an java.lang.UnsupportedOperationException from the method body (the exception will be automatically converted to the appropriate gRPC exception). Finally, implement the service and add the @GrpcService annotation:

import io.quarkus.grpc.GrpcService;
import hello.Greeter;

@GrpcService 1
public class HelloService implements Greeter { 2

    @Override
    public Uni<HelloReply> sayHello(HelloRequest request) {
        return Uni.createFrom().item(() ->
                HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
        );
    }
}
1 A gRPC service implementation bean must be annotated with the @GrpcService annotation and should not declare any other CDI qualifier. All gRPC services have the jakarta.inject.Singleton scope. Additionally, the request context is always active during a service call.
2 hello.Greeter is the generated service interface.

服务器实现 bean 还可以扩展 Mutiny 实现基,类名的结构如下:Mutiny${NAME_OF_THE_SERVICE}Grpc.${NAME_OF_THE_SERVICE}ImplBase

The service implementation bean can also extend the Mutiny implementation base, where the class name is structured as follows: Mutiny${NAME_OF_THE_SERVICE}Grpc.${NAME_OF_THE_SERVICE}ImplBase.

Implementing a Service with the default gRPC API

要使用默认 gRPC API 来实现 gRPC 服务器,请创建一个扩展默认实现基的类。然后,重写服务器接口中定义的方法。最后,实现服务器并添加 @GrpcService 注释:

To implement a gRPC service using the default gRPC API, create a class that extends the default implementation base. Then, override the methods defined in the service interface. Finally, implement the service and add the @GrpcService annotation:

import io.quarkus.grpc.GrpcService;

@GrpcService
public class HelloService extends GreeterGrpc.GreeterImplBase {

    @Override
    public void sayHello(HelloRequest request, StreamObserver<HelloReply> responseObserver) {
        String name = request.getName();
        String message = "Hello " + name;
        responseObserver.onNext(HelloReply.newBuilder().setMessage(message).build());
        responseObserver.onCompleted();
    }
}

Blocking Service Implementation

默认情况下,gRPC 服务器的所有方法都会在事件循环上运行。因此,您必须 not 块。如果您的服务器逻辑必须阻塞,请使用 `io.smallrye.common.annotation.Blocking`注释该方法:

By default, all the methods from a gRPC service run on the event loop. As a consequence, you must not block. If your service logic must block, annotate the method with io.smallrye.common.annotation.Blocking:

@Override
@Blocking
public Uni<HelloReply> sayHelloBlocking(HelloRequest request) {
    // Do something blocking before returning the Uni
}

Handling Streams

gRPC 允许接收和返回流:

gRPC allows receiving and returning streams:

service Streaming {
    rpc Source(Empty) returns (stream Item) {} // Returns a stream
    rpc Sink(stream Item) returns (Empty) {}   // Reads a stream
    rpc Pipe(stream Item) returns (stream Item) {}  // Reads a streams and return a streams
}

使用 Mutiny,您可以实现如下操作:

Using Mutiny, you can implement these as follows:

import io.quarkus.grpc.GrpcService;

@GrpcService
public class StreamingService implements Streaming {

    @Override
    public Multi<Item> source(Empty request) {
        // Just returns a stream emitting an item every 2ms and stopping after 10 items.
        return Multi.createFrom().ticks().every(Duration.ofMillis(2))
                .select().first(10)
                .map(l -> Item.newBuilder().setValue(Long.toString(l)).build());
    }

    @Override
    public Uni<Empty> sink(Multi<Item> request) {
        // Reads the incoming streams, consume all the items.
        return request
                .map(Item::getValue)
                .map(Long::parseLong)
                .collect().last()
                .map(l -> Empty.newBuilder().build());
    }

    @Override
    public Multi<Item> pipe(Multi<Item> request) {
        // Reads the incoming stream, compute a sum and return the cumulative results
        // in the outbound stream.
        return request
                .map(Item::getValue)
                .map(Long::parseLong)
                .onItem().scan(() -> 0L, Long::sum)
                .onItem().transform(l -> Item.newBuilder().setValue(Long.toString(l)).build());
    }
}

Health Check

对于已实现的服务器,Quarkus gRPC 会以以下格式公开健康信息:

For the implemented services, Quarkus gRPC exposes health information in the following format:

syntax = "proto3";

package grpc.health.v1;

message HealthCheckRequest {
  string service = 1;
}

message HealthCheckResponse {
  enum ServingStatus {
    UNKNOWN = 0;
    SERVING = 1;
    NOT_SERVING = 2;
  }
  ServingStatus status = 1;
}

service Health {
  rpc Check(HealthCheckRequest) returns (HealthCheckResponse);

  rpc Watch(HealthCheckRequest) returns (stream HealthCheckResponse);
}

客户端可以指定完全限定的服务器名称以获取特定服务器的运行状况,或者跳过指定服务器名称以获取 gRPC 服务器的常规状态。

Clients can specify the fully qualified service name to get the health status of a specific service or skip specifying the service name to get the general status of the gRPC server.

有关更多详细信息,请参阅 gRPC documentation

For more details, check out the gRPC documentation

此外,如果将 Quarkus SmallRye Health 添加到应用程序,则将在 MicroProfile Health 端点响应中添加针对 gRPC 服务器状态的就绪检查,即 /q/health

Additionally, if Quarkus SmallRye Health is added to the application, a readiness check for the state of the gRPC services will be added to the MicroProfile Health endpoint response, that is /q/health.

Reflection Service

Quarkus gRPC 服务器实现了 reflection service。此服务器允许 grpcurlgrpcox 等工具与您的服务器进行交互。

Quarkus gRPC Server implements the reflection service. This service allows tools like grpcurl or grpcox to interact with your services.

dev 模式下,默认情况下启用了反射服务器。在测试或生产模式下,您需要通过将 quarkus.grpc.server.enable-reflection-service 设置为 true 来明确启用它。

The reflection service is enabled by default in dev mode. In test or production mode, you need to enable it explicitly by setting quarkus.grpc.server.enable-reflection-service to true.

Quarkus 公开反射服务器 v1v1alpha

Quarkus exposes both the reflection service v1 and v1alpha.

Scaling

默认情况下,quarkus-grpc 会启动一个在单个事件循环上运行的单个 gRPC 服务器。

By default, quarkus-grpc starts a single gRPC server running on a single event loop.

如果您希望扩展服务器,您可以通过设置 quarkus.grpc.server.instances 来设置服务器实例的数量。

If you wish to scale your server, you can set the number of server instances by setting quarkus.grpc.server.instances.

Server Configuration

Unresolved directive in grpc-service-implementation.adoc - include::{generated-dir}/config/quarkus-grpc_quarkus.grpc.server.adoc[]

当您禁用 quarkus.grpc.server.use-separate-server 时,您正在使用新的 Vert.x gRPC 服务器实现,它使用了现有的 HTTP 服务器。这意味着服务器端口现在是 8080 (或使用 quarkus.http.port 配置的端口)。此外,大多数其他配置属性不再适用,因为应正确配置 HTTP 服务器。

When you disable quarkus.grpc.server.use-separate-server, you are then using the new Vert.x gRPC server implementation which uses the existing HTTP server. Which means that the server port is now 8080 (or the port configured with quarkus.http.port). Also, most of the other configuration properties are no longer applied, since it’s the HTTP server that should already be properly configured.

当您启用 quarkus.grpc.server.xds.enabled 时,xDS 应处理上述大部分配置。

When you enable quarkus.grpc.server.xds.enabled, it’s the xDS that should handle most of the configuration above.

Example of Configuration

Enabling TLS

要启用 TLS,请使用以下配置。

To enable TLS, use the following configuration.

请注意,配置中的所有路径都指定类路径上的资源(通常来自 src/main/resources 或其子文件夹)或外部文件。

Note that all paths in the configuration may either specify a resource on the classpath (typically from src/main/resources or its subfolder) or an external file.

quarkus.grpc.server.ssl.certificate=tls/server.pem
quarkus.grpc.server.ssl.key=tls/server.key

配置 SSL/TLS 后,`plain-text`将自动禁用。

When SSL/TLS is configured, plain-text is automatically disabled.

TLS with Mutual Auth

与相互认证一起使用 TLS,使用以下配置:

To use TLS with mutual authentication, use the following configuration:

quarkus.grpc.server.ssl.certificate=tls/server.pem
quarkus.grpc.server.ssl.key=tls/server.key
quarkus.grpc.server.ssl.trust-store=tls/ca.jks
quarkus.grpc.server.ssl.trust-store-password=*****
quarkus.grpc.server.ssl.client-auth=REQUIRED

Server Interceptors

gRPC 服务器拦截器允许你在调用服务之前执行逻辑,如验证。

gRPC server interceptors let you perform logic, such as authentication, before your service is invoked.

你可以通过创建实现 io.grpc.ServerInterceptor@ApplicationScoped Bean 来实现 gRPC 服务器拦截器:

You can implement a gRPC server interceptor by creating an @ApplicationScoped bean implementing io.grpc.ServerInterceptor:

@ApplicationScoped
// add @GlobalInterceptor for interceptors meant to be invoked for every service
public class MyInterceptor implements ServerInterceptor {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
            Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
        // ...
    }
}

还可以在生产者方法中添加注释作为全局拦截器:

It’s also possible to annotate a producer method as a global interceptor:

import io.quarkus.grpc.GlobalInterceptor;

import jakarta.enterprise.inject.Produces;

public class MyProducer {
    @GlobalInterceptor
    @Produces
    public MyInterceptor myInterceptor() {
        return new MyInterceptor();
    }
}

检查 ServerInterceptor JavaDoc 以正确实现你的拦截器。

Check the ServerInterceptor JavaDoc to properly implement your interceptor.

若要将拦截器应用到所有公开服务,请使用 @io.quarkus.grpc.GlobalInterceptor 标注它。若要将拦截器应用到单个服务,请使用 @io.quarkus.grpc.RegisterInterceptor 在服务中注册它:

To apply an interceptor to all exposed services, annotate it with @io.quarkus.grpc.GlobalInterceptor. To apply an interceptor to a single service, register it on the service with @io.quarkus.grpc.RegisterInterceptor:

import io.quarkus.grpc.GrpcService;
import io.quarkus.grpc.RegisterInterceptor;

@GrpcService
@RegisterInterceptor(MyInterceptor.class)
public class StreamingService implements Streaming {
    // ...
}

如果你有多个服务器拦截器,则可以通过实现 jakarta.enterprise.inject.spi.Prioritized 接口来对它们排序。请注意,在调用特定于服务拦截器之前调用所有全局拦截器。

When you have multiple server interceptors, you can order them by implementing the jakarta.enterprise.inject.spi.Prioritized interface. Please note that all the global interceptors are invoked before the service-specific interceptors.

@ApplicationScoped
public class MyInterceptor implements ServerInterceptor, Prioritized {

    @Override
    public <ReqT, RespT> ServerCall.Listener<ReqT> interceptCall(ServerCall<ReqT, RespT> serverCall,
            Metadata metadata, ServerCallHandler<ReqT, RespT> serverCallHandler) {
        // ...
    }

    @Override
    public int getPriority() {
        return 10;
    }
}

具有最高优先级的拦截器被首先调用。如果拦截器没有实现 Prioritized 接口,使用的默认优先级为 0

Interceptors with the highest priority are called first. The default priority, used if the interceptor does not implement the Prioritized interface, is 0.

Testing your services

测试 gRPC 服务最简单的方法是使用 gRPC 客户端,如 Consuming a gRPC Service 中所示。

The easiest way to test a gRPC service is to use a gRPC client as described in Consuming a gRPC Service.

请注意,在使用客户端测试未使用 TLS 的公开服务的情况下,无需提供任何配置。例如,若要测试上面定义的 HelloService,可以创建以下测试:

Please note that in the case of using a client to test an exposed service that does not use TLS, there is no need to provide any configuration. E.g. to test the HelloService defined above, one could create the following test:

public class HelloServiceTest implements Greeter {

    @GrpcClient
    Greeter client;

    @Test
    void shouldReturnHello() {
        CompletableFuture<String> message = new CompletableFuture<>();
        client.sayHello(HelloRequest.newBuilder().setName("Quarkus").build())
                .subscribe().with(reply -> message.complete(reply.getMessage()));
        assertThat(message.get(5, TimeUnit.SECONDS)).isEqualTo("Hello Quarkus");
    }
}

Trying out your services manually

在开发模式下,你可以在 Quarkus Dev UI 中体验你的 gRPC 服务。只需转到 [role="bare"][role="bare"]http://localhost:8080/q/dev-ui 并单击 gRPC 磁贴下的 Services

In the dev mode, you can try out your gRPC services in the Quarkus Dev UI. Just go to [role="bare"]http://localhost:8080/q/dev-ui and click on Services under the gRPC tile.

请注意,你的应用程序需要公开“正常”HTTP 端口才能访问 Dev UI。如果你的应用程序不公开任何 HTTP 端点,你可以创建一个具有 quarkus-vertx-http 依赖性的专用概要文件:

Please note that your application needs to expose the "normal" HTTP port for the Dev UI to be accessible. If your application does not expose any HTTP endpoints, you can create a dedicated profile with a dependency on quarkus-vertx-http:

    <profiles>
        <profile>
            <id>development</id>
            <dependencies>
                <dependency>
                    <groupId>io.quarkus</groupId>
                    <artifactId>quarkus-vertx-http</artifactId>
                </dependency>
            </dependencies>
        </profile>
    </profiles>

拥有它之后,你可以使用 mvn quarkus:dev -Pdevelopment 运行开发模式。

Having it, you can run the dev mode with: mvn quarkus:dev -Pdevelopment.

如果你使用 Gradle,你可以简单地添加对 quarkusDev 任务的依赖关系:

If you use Gradle, you can simply add a dependency for the quarkusDev task:

dependencies {
    quarkusDev 'io.quarkus:quarkus-vertx-http'
}

gRPC Server metrics

Enabling metrics collection

当应用程序还使用 quarkus-micrometer 扩展时,gRPC 服务器指标会被自动启用。Micrometer 收集应用程序实现的所有 gRPC 服务的指标。

gRPC server metrics are automatically enabled when the application also uses the quarkus-micrometer extension. Micrometer collects the metrics of all the gRPC services implemented by the application.

比如,如果你将指标导出到 Prometheus,你将得到:

As an example, if you export the metrics to Prometheus, you will get:

# HELP grpc_server_responses_sent_messages_total The total number of responses sent
# TYPE grpc_server_responses_sent_messages_total counter
grpc_server_responses_sent_messages_total{method="SayHello",methodType="UNARY",service="helloworld.Greeter",} 6.0
# HELP grpc_server_processing_duration_seconds The total time taken for the server to complete the call
# TYPE grpc_server_processing_duration_seconds summary
grpc_server_processing_duration_seconds_count{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 6.0
grpc_server_processing_duration_seconds_sum{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 0.016216771
# HELP grpc_server_processing_duration_seconds_max The total time taken for the server to complete the call
# TYPE grpc_server_processing_duration_seconds_max gauge
grpc_server_processing_duration_seconds_max{method="SayHello",methodType="UNARY",service="helloworld.Greeter",statusCode="OK",} 0.007985236
# HELP grpc_server_requests_received_messages_total The total number of requests received
# TYPE grpc_server_requests_received_messages_total counter
grpc_server_requests_received_messages_total{method="SayHello",methodType="UNARY",service="helloworld.Greeter",} 6.0

服务名称、方法和类型可以在 tags 中找到。

The service name, method and type can be found in the tags.

Disabling metrics collection

若 要在使用 quarkus-micrometer 时禁用 gRPC 服务器指标,请将以下属性添加到应用程序配置:

To disable the gRPC server metrics when quarkus-micrometer is used, add the following property to the application configuration:

quarkus.micrometer.binder.grpc-server.enabled=false

Use virtual threads

若要在你的 gRPC 服务实现中使用虚拟线程,请检查专用的 guide

To use virtual threads in your gRPC service implementation, check the dedicated guide.

gRPC Server authorization

Quarkus 包括内置安全功能,当支持使用现有 Vert.x HTTP 服务器的 Vert.x gRPC 启用时,允许 authorization using annotations

Quarkus includes built-in security to allow authorization using annotations when the Vert.x gRPC support, which uses existing Vert.x HTTP server, is enabled.

Add the Quarkus Security extension

安全功能由 Quarkus Security 扩展提供,因此请确保你的 pom.xml 文件包含以下依赖关系:

Security capabilities are provided by the Quarkus Security extension, therefore make sure your pom.xml file contains following dependency:

pom.xml
<dependency>
    <groupId>io.quarkus</groupId>
    <artifactId>quarkus-security</artifactId>
</dependency>

若要向现有 Maven 项目添加 Quarkus Security 扩展,请从你的项目基目录运行以下命令:

To add the Quarkus Security extension to an existing Maven project, run the following command from your project base directory:

Unresolved directive in grpc-service-implementation.adoc - include::{includes}/devtools/extension-add.adoc[]

Overview of supported authentication mechanisms

一些受支持的身份验证机制内置于 Quarkus 中,而其他机制要求你添加扩展。下表将特定身份验证要求映射到你可以在 Quarkus 中使用的受支持机制:

Some supported authentication mechanisms are built into Quarkus, while others require you to add an extension. The following table maps specific authentication requirements to a supported mechanism that you can use in Quarkus:

Table 1. Authentication requirements and mechanisms
Authentication requirement Authentication mechanism

Username and password

Basic authentication

Client certificate

Mutual TLS authentication

Custom requirements

Custom authentication

Bearer access token

OIDC Bearer token authentication, JWT, OAuth2

不要忘记至少安装一个基于所选身份验证要求提供 IdentityProvider 的扩展。请参考 Basic authentication guide,了解如何基于用户名和密码提供 IdentityProvider

Do not forget to install at least one extension that provides an IdentityProvider based on selected authentication requirements. Please refer to the Basic authentication guide for example how to provide the IdentityProvider based on username and password.

如果您使用独立的 HTTP 服务器来处理 gRPC 请求,Custom authentication 是您的唯一选择。将 quarkus.grpc.server.use-separate-server 配置属性设置为 false,以便您可以使用其他机制。

If you use separate HTTP server to serve gRPC requests, Custom authentication is your only option. Set the quarkus.grpc.server.use-separate-server configuration property to false so that you can use other mechanisms.

Secure gRPC service

gRPC 服务可以像以下示例中一样,使用 standard security annotations 进行保护:

The gRPC services can be secured with the standard security annotations like in the example below:

package org.acme.grpc.auth;

import hello.Greeter;
import io.quarkus.grpc.GrpcService;
import jakarta.annotation.security.RolesAllowed;

@GrpcService
public class HelloService implements Greeter {

    @RolesAllowed("admin")
    @Override
    public Uni<HelloReply> sayHello(HelloRequest request) {
        return Uni.createFrom().item(() ->
                HelloReply.newBuilder().setMessage("Hello " + request.getName()).build()
        );
    }
}

支持的大多数机制示例都发送了身份验证标头,请参阅使用 gRPC 服务指南的 gRPC Headers 部分,以了解更多有关 gRPC 标头的信息。

Most of the examples of the supported mechanisms sends authentication headers, please refer to the gRPC Headers section of the Consuming a gRPC Service guide for more information about the gRPC headers.

Basic authentication

Quarkus Security 为 Basic authentication 提供内置的身份验证支持。

Quarkus Security provides built-in authentication support for the Basic authentication.

quarkus.grpc.server.use-separate-server=false
quarkus.http.auth.basic=true 1
1 Enable the Basic authentication.
package org.acme.grpc.auth;

import static org.assertj.core.api.Assertions.assertThat;

import io.grpc.Metadata;
import io.quarkus.grpc.GrpcClient;
import io.quarkus.grpc.GrpcClientUtils;
import java.util.concurrent.CompletableFuture;
import org.junit.jupiter.api.Test;

public class HelloServiceTest implements Greeter {

    @GrpcClient
    Greeter greeterClient;

    @Test
    void shouldReturnHello() {
        Metadata headers = new Metadata();
        headers.put("Authorization", "Basic am9objpqb2hu");
        var client = GrpcClientUtils.attachHeaders(greeterClient, headers);

        CompletableFuture<String> message = new CompletableFuture<>();
        client.sayHello(HelloRequest.newBuilder().setName("Quarkus").build())
                .subscribe().with(reply -> message.complete(reply.getMessage()));
        assertThat(message.get(5, TimeUnit.SECONDS)).isEqualTo("Hello Quarkus");
    }
}

Mutual TLS authentication

Quarkus 提供相互TLS (mTLS) 身份验证,以便您可以根据用户的 X.509 证书对用户进行身份验证。在本指南的 TLS with Mutual Auth 部分中,描述了对您的所有 gRPC 服务强制执行身份验证的最简单方法。但是,Quarkus Security 支持角色映射功能,您可以使用此功能执行更细粒度的访问控制。

Quarkus provides mutual TLS (mTLS) authentication so that you can authenticate users based on their X.509 certificates. The simplest way to enforce authentication for all your gRPC services is described in the TLS with Mutual Auth section of this guide. However, the Quarkus Security supports role mapping that you can use to perform even more fine-grained access control.

quarkus.grpc.server.use-separate-server=false
quarkus.http.insecure-requests=disabled
quarkus.http.ssl.certificate.files=tls/server.pem
quarkus.http.ssl.certificate.key-files=tls/server.key
quarkus.http.ssl.certificate.trust-store-file=tls/ca.jks
quarkus.http.ssl.certificate.trust-store-password=**********
quarkus.http.ssl.client-auth=required
quarkus.http.auth.certificate-role-properties=role-mappings.txt     1
quarkus.native.additional-build-args=-H:IncludeResources=.*\\.txt
1 Adds certificate role mapping.
Example of the role mapping file
testclient=admin 1
1 Map the testclient certificate CN (Common Name) to the SecurityIdentity role admin.

Custom authentication

如果您始终实现一个或多个 GrpcSecurityMechanism bean,如果 Quarkus 提供的上文提到的机制无法满足您的需求,可以执行此操作。

You can always implement one or more GrpcSecurityMechanism bean if above-mentioned mechanisms provided by Quarkus do no meet your needs.

Example of custom GrpcSecurityMechanism
package org.acme.grpc.auth;

import jakarta.inject.Singleton;

import io.grpc.Metadata;
import io.quarkus.security.credential.PasswordCredential;
import io.quarkus.security.identity.request.AuthenticationRequest;
import io.quarkus.security.identity.request.UsernamePasswordAuthenticationRequest;

@Singleton
public class CustomGrpcSecurityMechanism implements GrpcSecurityMechanism {

    private static final String AUTHORIZATION = "Authorization";

    @Override
    public boolean handles(Metadata metadata) {
        String authString = metadata.get(AUTHORIZATION);
        return authString != null && authString.startsWith("Custom ");
    }

    @Override
    public AuthenticationRequest createAuthenticationRequest(Metadata metadata) {
        final String authString = metadata.get(AUTHORIZATION);
        final String userName;
        final String password;
        // here comes your application logic that transforms 'authString' to user name and password
        return new UsernamePasswordAuthenticationRequest(userName, new PasswordCredential(password));
    }
}