JWT Interceptor for gRPC
gRPC JWT Interceptor Server and Client.
The interceptor is same as all Herts streaming type.
build.gradle
def grpcVersion = 'x.x.x'
dependencies {
implementation 'org.hertsstack:herts-core:1.1.0'
implementation 'org.hertsstack:herts-rpc:1.1.0'
implementation 'org.hertsstack:herts-rpc-client:1.1.0'
implementation "io.grpc:grpc-protobuf:${grpcVersion}"
implementation "io.grpc:grpc-services:${grpcVersion}"
implementation "io.grpc:grpc-stub:${grpcVersion}"
}
UnaryService.java
@HertsRpcService(value = HertsType.Unary)
public interface UnaryService extends HertsService {
String helloWorld();
Map<String, String> getUser(String id);
}
UnaryServiceImpl.java
public class UnaryServiceImpl extends HertsServiceUnary<UnaryService> implements UnaryService {
@Override
public String helloWorld() {
return "hello world";
}
@Overide
public Map<String, String> getUser(String id) {
return Collections.singletonMap("name", "foo");
}
}
Herts support interceptor wrapper.
So You can check metadata of gRPC.
JwtServerInterceptor.java
public class JwtServerInterceptor implements HertsRpcInterceptor {
private final JwtVerifier jwtProcessor;
public JwtServerInterceptor() {
this.jwtProcessor = new JwtVerifier();
}
@Override
public void setResponseMetadata(Metadata metadata) {
}
/**
* Before call Server method.
* You can verify token this workflow
*
* @param call ServerCall
* @param requestHeaders Metadata
*/
@Override
public <ReqT, RespT> void beforeCallMethod(ServerCall<ReqT, RespT> call, Metadata requestHeaders) {
Metadata.Key<String> authorization = Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER);
String token = requestHeaders.get(authorization);
if (token == null || token.isEmpty()) {
Status status = RpcErrorException.StatusCode.Status16
.convertToGrpc(RpcErrorException.StatusCode.Status16)
.withDescription("Unauthorized");
call.close(status, requestHeaders);
return;
}
if (this.jwtProcessor.verifyToken(token)) {
Status status = RpcErrorException.StatusCode.Status16
.convertToGrpc(RpcErrorException.StatusCode.Status16)
.withDescription("Unauthorized");
call.close(status, requestHeaders);
return;
}
}
}
Start gRPC Unary Server with Interceptor
Main.java
public class Main {
public static void main(String[] args) {
// Inject other class if need it
var service = new UnaryServiceImpl();
ServerInterceptor interceptor = HertsRpcInterceptBuilder.builder(new JwtServerInterceptor()).build();
HertsRpcServerEngine engine = HertsRpcServerEngineBuilder.builder()
.registerHertsRpcService(service, interceptor)
.build();
engine.start();
}
}
Run server. Default port is 9999
java -jar {Your Jar path}
2023-06-15 13:18:35.747 INFO org.hertstack.rpc.ReflectMethod printMethodName UnaryService stats
2023-06-15 13:18:35.757 INFO org.hertstack.rpc.ReflectMethod printMethodName UnaryService/helloWorld
2023-06-15 13:18:35.757 INFO org.hertstack.rpc.ReflectMethod printMethodName UnaryService/getUser
2023-06-15 13:18:35.946 INFO org.hertstack.rpc.HertsRpcServerEngineBuilder start Started Herts RPC server. gRPC type Unary Port 9999
You need to define io.grpc.CallCredentials when call createHertsRpcService.
Also, If you want recreate token by expires, you should createHertsRpcService again.
Start gRPC Unary Client
public class Main {
public static void main(String[] args) {
HertsRpcClient client = HertsRpcClientBuilder
.builder("localhost")
.secure(false)
.registerHertsRpcServiceInterface(UnaryService.class)
.connect();
UnaryService service = client.createHertsRpcService(UnaryService.class);
var token = "";
service = client.createHertsRpcService(UnaryService.class, generateCredential(token));
var res01 = service.helloWorld();
System.out.println(res01);
}
private static CallCredentials generateCredential(String token) {
return new CallCredentials() {
@Override
public void applyRequestMetadata(RequestInfo requestInfo, Executor appExecutor, MetadataApplier applier) {
Metadata metadata = new Metadata();
metadata.put(Metadata.Key.of("Authorization", Metadata.ASCII_STRING_MARSHALLER), "Bearer " + token);
applier.apply(metadata);
}
@Override
public void thisUsesUnstableApi() {
}
};
}
}