majusko / grpc-jwt-spring-boot-starter

Spring boot starter for gRPC framework with JWT authorization
Other
39 stars 7 forks source link
annotations autowire grpc grpc-framework grpc-java grpc-library interceptor java java-library jwt jwt-authorization microservices ownerfield proto protobuf signing spring-boot springboot-starter

Spring boot starter for gRPC framework with JWT authorization - gRPC Java JWT

Maven Central Release Build Status Test Coverage License: MIT Join the chat at https://gitter.im/grpc-jwt-spring-boot-starter/community

Extending great gRPC library with Auth module. Easy implementation using a simple annotations similar to ones used in Spring Security module.

Quick Start

(Try example project: gRPC example project in Kotlin.)

Simple start consist only from 3 simple steps.

(If you never used gRPC library before, have a look on this basic setup first.)

1. Add Maven dependency

<dependency>
  <groupId>io.github.majusko</groupId>
  <artifactId>grpc-jwt-spring-boot-starter</artifactId>
  <version>${version}</version>
</dependency>

2. Add @Allow annotation to your service method

All you need to do is to annotate your method in the service implementation.

@GRpcService
public class ExampleServiceImpl extends ExampleServiceGrpc.ExampleServiceImplBase {

    @Allow(roles = GrpcRole.INTERNAL)
    public void getExample(GetExample request, StreamObserver<Empty> response) {
        //...
    }
}

3. Add interceptor to client

Just autowire already prepared AuthClientInterceptor bean and intercept your client. It will inject the internal token to every request by default.

@Service
public class ExampleClient {

    @Autowired
    private AuthClientInterceptor authClientInterceptor;

    public void exampleRequest() {
        final ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
        final Channel interceptedChannel = ClientInterceptors.intercept(channel,authClientInterceptor);
        final ExampleServiceBlockingStub stub = ExampleServiceGrpc.newBlockingStub(interceptedChannel);

        stub.getExample(GetExample.newBuilder().build());
    }
}

Documentation

0. Basic setup of gRPC

Useful only in case you never heard about gRPC library from LogNet. You can find there a nice show case too.

0.1 Service implementation

The service definition from .proto file looks like this

service ExampleService {
    rpc GetExample (GetExample) returns (Empty) {};
}

message Empty {}
message GetExample {
    string ownerField = 1;
}

0.2 Service implementation

All you need to do is to annotate your service implementation with GRpcService

@GRpcService
public class ExampleServiceImpl extends ExampleServiceGrpc.ExampleServiceImplBase {

    public void getExample(GetExample request, StreamObserver<Empty> response) {
        response.onNext(Empty.newBuilder().build());
        response.onCompleted();
    }
}

1. Configuration

You can use application.properties to override the default configuration.

grpc.jwt.algorithm=HmacSHA256
grpc.jwt.secret=secret
grpc.jwt.expirationSec=3600

2. Annotations

We know 2 types of annotation: @Allow and @Expose

@Allow

@Exposed

@GRpcService
public class ExampleServiceImpl extends ExampleServiceGrpc.ExampleServiceImplBase {

    @Allow(ownerField="ownerField", roles = GrpcRole.INTERNAL)
    @Exposed(environments={"dev","qa"})
    public void getExample(GetExample request, StreamObserver<Empty> response) {
        //...
    }
}

Token generation

You will need to generate tokens for your users or clients. You might want to specify special roles for each user and also service method. You can use the JwtService for simple and performing usage.

@Service
public class SomeClass {

    private final static String ADMIN = "admin";

    @Autowired
    private JwtService jwtService;

    public void someMethod() {
        final JwtData data = new JwtData("user-id-12345", new HashSet<>(ADMIN));

        final String token = jwtService.generate(data);
    }
}

Making requests

We have two types of usages for client.

  1. Inter-service communication.
  2. User communication.

1. Client for inter-service communication only.

@Service
public class SomeClass {

    @Autowired
    private AuthClientInterceptor authClientInterceptor;

    public void customTokenRequest() {

        final ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
        final Channel interceptedChannel = ClientInterceptors.intercept(channel,authClientInterceptor);
        final ExampleServiceBlockingStub stub = ExampleServiceGrpc.newBlockingStub(interceptedChannel);

        final Empty response = stub.getExample(GetExample.newBuilder().setUserId("user-id-jr834fh").build());
    }
}

2. Client for custom token communication.

@Service
public class SomeClass {

    public void customTokenRequest() {

        final Metadata header = new Metadata();
        header.put(GrpcHeader.AUTHORIZATION, "jwt-token-r348hf34hf43f93");

        final ManagedChannel channel = ManagedChannelBuilder.forTarget(target).usePlaintext().build();
        final ExampleServiceBlockingStub stub = ExampleServiceGrpc.newBlockingStub(channel);
        final ExampleServiceBlockingStub stubWithHeaders = MetadataUtils.attachHeaders(stub, header);

        final Empty response = stub.getExample(GetExample.newBuilder().setUserId("user-id-jr834fh").build());
    }
}

Tests

The library is fully covered with integration tests which are also very useful as a usage example.

GrpcJwtSpringBootStarterApplicationTest

Contributing

All contributors are welcome. If you never contributed to the open-source, start with reading the Github Flow.

  1. Create an issue
  2. Create a pull request with reference to the issue
  3. Rest and enjoy the great feeling of being a contributor.