转载

Micronaut 教程(二):分布式跟踪、JWT 安全和 AWS Lambda 部署

关键要点

  • Micronaut 提供了与 Zipkin 和 Jaeger 等多种分布式跟踪解决方案的无缝集成。
  • 框架提供了几种“开箱即用”的安全解决方案,例如基于 JWT 的认证。
  • Micronaut 提供了“令牌传播”之类的功能,用以简化微服务之间的安全通信。
  • 因为内存占用少,Micronaut 能够运行在功能即服务(FaaS)无服务器环境中。

在本系列的第一篇文章中,我们使用基于 JVM 的 Micronaut 框架开发并部署了三个微服务。在第二篇文章中,我们将为应用程序添加几个功能:分布式跟踪、JWT 安全性和无服务器功能。此外,我们也将介绍 Micronaut 提供的用户输入验证功能。

分布式跟踪

将系统分解为更小、更细粒度的微服务可以带来多种好处,但也会给生产环境的监控系统增加复杂性。

你应该假设你的网络将会受到恶意实体的骚扰,它们时刻准备着随心所欲地释放它们的愤怒。

——Sam Newman,《构建微服务》

Micronaut 与 Jaeger 和 Zipkin 原生集成——它们都是顶级的开源分布式跟踪解决方案。

Zipkin 是一种分布式跟踪系统,用于收集时序数据,这些数据可用于解决微服务架构中的延迟问题。它负责收集和查找这些数据。

启动 Zipkin 的简单方法是通过 Docker:

复制代码

$ docker run -d -p9411:9411openzipkin/zipkin

这个应用程序由三个微服务组成,也就是我们在第一篇文章中开发的三个微服务(gateway、inventory、books)。

我们需要对这三个微服务做出修改。

修改 build.gradle,加入跟踪依赖项:

复制代码

build.gradle

compile"io.micronaut:micronaut-tracing"

将以下依赖项添加到 build.gradle 中,这样就可以将跟踪数据发送到 Zipkin。

复制代码

build.gradle

runtime'io.zipkin.brave:brave-instrumentation-http'
runtime'io.zipkin.reporter2:zipkin-reporter'
compile'io.opentracing.brave:brave-opentracing'

配置跟踪选项:

复制代码

src/main/resources/application.yml

tracing:
   zipkin:
       http:
           url:http://localhost:9411
       enabled:true
       sampler:
           probability:1

设置 tracing.zipkin.sample.probability = 1,意思是我们要跟踪所有的请求。在生产环境中,你可能希望设置较低的百分比。

在测试时禁用跟踪:

复制代码

src/test/resources/application-test.yml

   tracing:
       zipkin:
           enabled:false

只需要很少的配置更改,就可以将分布式跟踪集成到 Micronaut 中。

运行应用程序

现在让我们运行应用程序,看看分布式跟踪集成是否能够正常运行。在第一篇文章中,我们集成了 Consul,用于实现服务发现。因此,在启动微服务之前需要先启动 Zipkin 和 Consul。在微服务启动好以后,它们将在 Consul 服务发现中进行注册。当我们发出请求时,它们会向 Zipkin 发送数据。

Gradle 提供了一个 flag(-parallel)用来启动微服务:

复制代码

./gradlew -parallelrun

你可以通过 cURL 命令向三个微服务发起请求:

复制代码

$ curl http://localhost:8080/api/books
[{"isbn":"1680502395","name":"Release It!","stock":3},
{"isbn":"1491950358","name":"Building Microservices","stock":2}]

然后,你可以通过 http://localhost:9411 来访问 Zipkin UI。

JWT 安全性

Micronaut 提供了多种开箱即用的安全选项,你可以使用基本的身份验证、基于会话的身份验证、JWT 身份验证、Ldap 身份验证,等等。JSON Web Token(JWT)是一种开放的行业标准(RFC 7519)用于在参与方之间声明安全。

Micronaut 提供了开箱即用的用于生成、签名、加密和验证 JWT 令牌的功能。

我们将把 JWT 身份验证集成到我们的应用程序中。

修改 gateway 微服务,让它支持 JWT

gateway 微服务将负责生成和传播 JWT 令牌。

修改 build.gradle,为每个微服务(gateway、inventory 和 books)添加 micronaut-security-jwt 依赖项:

复制代码

gateway/build.gradle

      compile"io.micronaut:micronaut-security-jwt" 
      annotationProcessor"io.micronaut:micronaut-security"

修改 application.yml:

复制代码

gateway/src/main/resources/application.yml
micronaut:
   application:
       name:gateway
   server:
       port:8080
   security:
       enabled:true
       endpoints:
           login:
               enabled:true
           oauth:
               enabled:true
       token:
           jwt:
               enabled:true
               signatures:
                   secret:
                       generator:
                           secret:pleaseChangeThisSecretForANewOne
           writer:
               header:
                   enabled:true
           propagation:
               enabled:true
               service-id-regex:"books|inventory"

我们做了几个重要的配置变更:

  • micronaut.security.enable = true 启用了安全,并默认为每个端点提供安全保护。
  • micronaut.security.endpoints.login.enable = true 启用了 /login 端点,我们将用它进行身份验证。
  • micronaut.security.endpoints.oauth.enable = true 启用了 /oauth/access_tokenendpoint 端点,在令牌过期时,我们可以使用它来获取新的 JWT 访问令牌。
  • micronaut.security.jwt.enable = true 启用了 JWT 功能。
  • 我们让应用程序启用签名的 JWT。更多的签名和加密选项,请参阅 JWT 令牌生成文档。
  • micronaut.security.token.propagation.enabled = true 表示启用了令牌传播。这是一种在微服务架构中简化 JWT 或其他令牌安全机制的功能。
  • micronaut.security.writer.header.enabled = ture 启用了一个令牌写入器,它将为开发人员在 HTTP 标头中写入 JWT 令牌。
  • micronaut.security.token.propagation.service-id-regex 设置了一个正则表达式,用于匹配需要进行令牌传播的服务。我们匹配了应用程序中的其他两个服务。

你可以使用 @Secured 注解来配置 Controller 或 Controller Action 级别的访问。

使用 @Secured(“isAuthenticated()”) 注解 BookController.java,只允许经过身份验证的用户访问。同时记得使用 @Secured(“isAuthenticated()”) 注解 inventory 和 books 微服务的 BookController 类。

/login 端点被调用时,会尝试通过任何可用的 AuthenticationProvider 对用户进行身份验证。为了简单起见,我们将允许两个用户访问,他们是福尔摩斯和华生。创建 SampleAuthenticationProvider:

复制代码

gateway/src/main/java/example/micronaut/SampleAuthenticationProvider.java

packageexample.micronaut;

importio.micronaut.context.annotation.Requires; 
importio.micronaut.context.env.Environment; 
importio.micronaut.security.authentication.AuthenticationFailed; 
importio.micronaut.security.authentication.AuthenticationProvider; 
importio.micronaut.security.authentication.AuthenticationRequest; 
importio.micronaut.security.authentication.AuthenticationResponse; 
importio.micronaut.security.authentication.UserDetails; 
importio.reactivex.Flowable; 
importorg.reactivestreams.Publisher;

importjavax.inject.Singleton; 
importjava.util.ArrayList; 
importjava.util.Arrays;

@Requires(notEnv = Environment.TEST) 
@Singleton 
publicclassSampleAuthenticationProviderimplementsAuthenticationProvider{

   @Override
   publicPublisher<AuthenticationResponse> authenticate(AuthenticationRequest authenticationRequest) { 
       if(authenticationRequest.getIdentity() ==null) { 
           returnFlowable.just(newAuthenticationFailed()); 
        } 
       if(authenticationRequest.getSecret() ==null) { 
           returnFlowable.just(newAuthenticationFailed()); 
        } 
       if(Arrays.asList("sherlock","watson").contains(authenticationRequest.getIdentity().toString()) && authenticationRequest.getSecret().equals("elementary"))     { 
           returnFlowable.just(newUserDetails(authenticationRequest.getIdentity().toString(),newArrayList<>())); 
        } 
       returnFlowable.just(newAuthenticationFailed()); 
    } 
}

修改 inventory 和 books,让它们支持 JWT

对于 inventory 和 books,除了添加 micronaut-security-jwt 依赖项并使用 @Secured 注解控制器之外,我们还需要修改 application.yml,以便能够验证在 gateway 中生成和签名的 JWT 令牌。

修改 application.yml:

复制代码

inventory/src/main/resources/application.yml

micronaut:
   application:
       name:inventory
   server:
       port:8081
   security:
       enabled:true 
       token:
           jwt:
                 enabled:true
                 signatures:
                     secret: 
                         validation: 
                             secret:pleaseChangeThisSecretForANewOne

请注意,我们使用与 gateway 配置中相同的秘钥,这样就可以验证由 gateway 微服务签名的 JWT 令牌。

运行安全的应用程序

在启动了 Zipkin 和 Consul 之后,你就可以同时启动这三个微服务。Gradle 提供了一个方便的 flag(-parallel):

复制代码

./gradlew -parallelrun

你可以运行 cURL 命令,然后会收到 401 错误,表示未授权!

复制代码

$ curl -I http://localhost:8080/api/books HTTP/1.1 401 Unauthorized
Date: Mon,1Oct201818:44:54GMT transfer-encoding: chunked connection: close

我们需要先登录,并获得一个有效的 JWT 访问令牌:

复制代码

$ curl -X"POST""http://localhost:8080/login"/
-H 'Content-Type: application/json; charset=utf-8' /
-d $'{"username":"sherlock","password":"password"}' 
{"username":"sherlock","access_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWI iOiJzaGVybG9jayIsIm5iZiI6MTUzODQxMjQwOSwicm9sZXMiOltdLCJpc3MiOiJnYX Rld2F5IiwiZXhwIjoxNTM4NDE2MDA5LCJpYXQiOjE1Mzg0MTI0MDl9.1W4CXbN1bJgM CQlCDKJtm7zHWzyZeIr1rHpTuDy6h0","refresh_token":"eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJ zaGVybG9jayIsIm5iZiI6MTUzODQxMjQwOSwicm9sZXMiOltdLCJpc3MiOiJnYXRld2 F5IiwiaWF0IjoxNTM4NDEyNDA5fQ.l72msZKwHmYeLs7T0vKtRxu7_DZr62rPCILNmC 7UEZ4","expires_in":3600,"token_type":"Bearer"}

Micronaut 提供了开箱即用的 RFC 6750 Bearer Token 规范支持。我们可以使用从 /login 响应标头中获得的 JWT 来调用 /api/books 端点。

复制代码

curl"http://localhost:8080/api/books"/ -H'Authorization: Bearer eyJhbGciOiJIUzI1NiJ9.eyJzdWIiOiJzaGVybG9jayIsIm5iZiI6MTUzODQxMjQwOS wicm9sZXMiOltdLCJpc3MiOiJnYXRld2F5IiwiZXhwIjoxNTM4NDE2MDA5LCJpYXQiO jE1Mzg0MTI0MDl9.1W4CXbN1bJgMCQlCDKJtm7zHWz-yZeIr1rHpTuDy6h0'
[{"isbn":"1680502395","name":"Release It!","stock":3}, {"isbn":"1491950358","name":"Building Microservices","stock":2}]

Serverless

我们将添加一个部署到 AWS Lambda 的功能来验证 books 的 ISBN。

复制代码

mncreate-functionexample.micronaut.isbn-validator

注意:我们使用了 Micronaut CLI 提供的 create-function 命令。

验证

我们将创建一个单例来处理 ISBN 10 验证。

创建一个封装操作的接口:

复制代码

packageexample.micronaut;

importjavax.validation.constraints.Pattern;

publicinterfaceIsbnValidator{
   booleanisValid(@Pattern(regexp ="//d{10}") String isbn);
}

Micronaut 的验证基于标准框架 JSR 380 ,也称为 Bean Validation 2.0。

Hibernate Validator 是这个标准的参考实现。

将以下代码段添加到 build.gradle 中:

复制代码

isbn-validator/build.gradle

     compile"io.micronaut.configuration:micronaut-hibernatevalidator"

创建一个实现了 IsbnValidator 的单例。

复制代码

isbn-validator/src/main/java/example/micronaut/DefaultIsbnValidator.java

packageexample.micronaut;

importio.micronaut.validation.Validated; 
importjavax.inject.Singleton; 
importjavax.validation.constraints.Pattern;

@Singleton 
@Validated 
publicclassDefaultIsbnValidatorimplementsIsbnValidator{

   /** 
     * must range from 0 to 10 (the symbol X is used for 10), and must be such that the sum of all the ten digits, each multiplied by its (integer) weight, descending from 10 to 1, is a multiple of 11.
   *@paramisbn 10 Digit ISBN
   *@returnwhether the ISBN is valid or not.
   */
   @Override
   publicbooleanisValid(@Pattern(regexp ="//d{10}") String isbn) { 
       char[] digits = isbn.toCharArray(); 
       intaccumulator =0; 
       intmultiplier =10; 
       for(inti =0; i < digits.length; i++) { 
           charc = digits[i]; 
           accumulator += Character.getNumericValue(c) * multiplier; 
           multiplier--; 
       } 
       return(accumulator %11==0);
   }
}

与之前的代码清单一样,你要为需要验证的类添加 @Validated 注解。

创建单元测试:

复制代码

isbn-validator/src/test/java/example/micronaut/IsbnValidatorTest.java

packageexample.micronaut;

importio.micronaut.context.ApplicationContext; 
importio.micronaut.context.DefaultApplicationContext; 
importio.micronaut.context.env.Environment; 
importorg.junit.AfterClass; 
importorg.junit.BeforeClass; 
importorg.junit.Rule; 
importorg.junit.Test; 
importorg.junit.rules.ExpectedException;
importjavax.validation.ConstraintViolationException;
importstaticorg.junit.Assert.assertFalse; 
importstaticorg.junit.Assert.assertTrue;

publicclassIsbnValidatorTest{

   privatestaticApplicationContext applicationContext;

   @BeforeClass 
   publicstaticvoidsetupContext() { 
        applicationContext =newDefaultApplicationContext(Environment.TEST).start(); 
    }
    
   @AfterClass 
   publicstaticvoidstopContext() {
       if(applicationContext!=null) {     
            applicationContext.stop();
        }
    }

   @RulepublicExpectedException thrown = ExpectedException.none();

   @TestpublicvoidtestTenDigitValidation() {
       thrown.expect(ConstraintViolationException.class);
       IsbnValidator isbnValidator = applicationContext.getBean(IsbnValidator.class);
       isbnValidator.isValid("01234567891"); 
    }

   @Test 
   publicvoidtestControlDigitValidationWorks() {  
        IsbnValidator isbnValidator = applicationContext.getBean(IsbnValidator.class);
        assertTrue(isbnValidator.isValid("1491950358"));
        assertTrue(isbnValidator.isValid("1680502395"));
        assertFalse(isbnValidator.isValid("0000502395"));
    }
}

如果我们尝试使用十一位数字字符串调用该方法,就会抛出 javax.validation.ConstraintViolationException。

函数的输入和输出

这个函数将接受单个参数(ValidationRequest,它是一个封装了 ISBN 的 POJO)。

复制代码

isbn-validator/src/main/java/example/micronaut/IsbnValidationRequest.java

packageexample.micronaut;

publicclassIsbnValidationRequest{ 
   privateString isbn;
   publicIsbnValidationRequest(){
    }
   publicIsbnValidationRequest(String isbn){ 
       this.isbn = isbn; 
    }
   publicStringgetIsbn(){returnisbn; }

   publicvoidsetIsbn(String isbn){this.isbn = isbn; }
}

并返回单个结果(ValidationResponse,一个封装了 ISBN 和一个指示 ISBN 是否有效的布尔值的 POJO)。

复制代码

isbn-validator/src/main/java/example/micronaut/IsbnValidationResponse.java

packageexample.micronaut;

publicclassIsbnValidationResponse{ 
   privateString isbn; 
   privateBoolean valid;
    
   publicIsbnValidationResponse(){
    }

   publicIsbnValidationResponse(String isbn,booleanvalid){
       this.isbn = isbn; 
       this.valid = valid; 
    }
   publicStringgetIsbn(){ 
       returnisbn; 
    }
   publicvoidsetIsbn(String isbn){ 
       this.isbn = isbn; 
    }
   publicBooleangetValid(){ 
       returnvalid; 
    }
   publicvoidsetValid(Boolean valid){ 
       this.valid = valid; 
    }
}

函数测试

当我们运行 create-function 命令时,Micronaut 会在 src/main/java/example/micronaut 目录创建一个 IsbnValidatorFunction 类。修改它,让它实现 java.util.Function 接口。

复制代码

isbn-validator/src/main/java/example/micronaut/IsbnValidatorFunction.java

packageexample.micronaut;

importio.micronaut.function.FunctionBean;
importjava.util.function.Function; 
importjavax.validation.ConstraintViolationException;

@FunctionBean("isbn-validator") 
publicclassIsbnValidatorFunctionimplementsFunction<IsbnValidationRequest,IsbnValidationResponse> {

   privatefinalIsbnValidator isbnValidator;

   publicIsbnValidatorFunction(IsbnValidator isbnValidator) {
       this.isbnValidator = isbnValidator; 
    }

   @Override 
   publicIsbnValidationResponse apply(IsbnValidationRequest req) {
       try{ 
           returnnewIsbnValidationResponse(req.getIsbn(), isbnValidator.isValid(req.getIsbn()));
        }catch(ConstraintViolationException e) { 
           returnnewIsbnValidationResponse(req.getIsbn(),false);
        }
    }
}

上面的代码做了几件事:

  • 使用 @FunctionBean 注解了一个返回函数的方法。
  • 你可以在函数中使用 Micronaut 的编译时依赖注入。我们通过构造函数注入了 IsbnValidator。

函数也可以作为 Micronaut 应用程序上下文的一部分运行,这样方便进行测试。应用程序已经在类路径中包含了用于测试的 function-web 和 HTTP 服务器依赖项:

复制代码

isbn-validator/build.gradle

     testRuntime"io.micronaut:micronaut-http-server-netty" 
     testRuntime"io.micronaut:micronaut-function-web"

要在测试中调用函数,需要修改 IsbnValidatorClient.java

复制代码

isbn-validator/src/test/java/example/micronaut/IsbnValidatorClient.java

packageexample.micronaut;

importio.micronaut.function.client.FunctionClient; 
importio.micronaut.http.annotation.Body; 
importio.reactivex.Single;
importjavax.inject.Named;

@FunctionClient 
publicinterfaceIsbnValidatorClient{
   @Named("isbn-validator") 
    Single<IsbnValidationResponse> isValid(@BodyIsbnValidationRequest isbn);
}

同时修改 IsbnValidatorFunctionTest.java。我们需要测试不同的场景(有效的 ISBN、无效的 ISBN、超过 10 位的 ISBN 和少于 10 位的 ISBN)。

复制代码

isbn-validator/src/test/java/example/micronaut/IsbnValidatorFunctionTest.java

package example.micronaut;

import io.micronaut.context.ApplicationContext; 
import io.micronaut.runtime.server.EmbeddedServer; 
import org.junit.Test; 
import static org.junit.Assert.assertFalse; 
import static org.junit.Assert.assertTrue;

publicclassIsbnValidatorFunctionTest {

    @Test public void testFunction(){ 
        EmbeddedServer server =ApplicationContext.run(EmbeddedServer.class);

        IsbnValidatorClient client = server.getApplicationContext().getBean(IsbnValidatorClient.class);

       assertTrue(client.isValid(newIsbnValidationRequest("1491950358")).blockingGet().getValid());
       assertTrue(client.isValid(new    IsbnValidationRequest("1680502395")).blockingGet().getValid());
       assertFalse(client.isValid(newIsbnValidationRequest("0000502395")).blockingGet().getValid());
       assertFalse(client.isValid(newIsbnValidationRequest("01234567891")).blockingGet().getValid());
       assertFalse(client.isValid(newIsbnValidationRequest("012345678")).blockingGet().getValid());
        server.close();
}

}

部署到 AWS Lambda

假设你拥有 Amazon Web Services(AWS)帐户,那么就可以转到 AWS Lambda 并创建一个新功能。

选择 Java 8 运行时。名称为 isbn-validator,并创建一个新的角色表单模板。角色名称为 lambda_basic_execution。

Micronaut 教程(二):分布式跟踪、JWT 安全和 AWS Lambda 部署

运行./gradlew shadowJar 生成一个 Jar 包。

shadowJar 是 Gradle ShadowJar 插件提供的一个任务。

复制代码

$ du -h isbn-validator/build/libs/isbn-validator-0.1-all.jar11M isbn-validator/build/libs/isbn-validator-0.1-all.jar

上传 JAR,并指定 Handler。

复制代码

io.micronaut.function.aws.MicronautRequestStreamHandler 

我只分配了 256Mb 内存,超时时间为 25 秒。

Micronaut 教程(二):分布式跟踪、JWT 安全和 AWS Lambda 部署

从另一个微服务中调用函数

我们将在 gateway 微服务中使用这个 lambda。修改 gateway 微服务中的 build.gradle,添加 micronaut-function-client:

复制代码

com.amazonaws:aws-java-sdk-lambda dependencies:

build.gradle

     compile"io.micronaut:micronaut-function-client" 
     runtime'com.amazonaws:aws-java-sdk-lambda:1.11.285'

修改 src/main/resources/application.yml:

复制代码

src/main/resources/application.yml

aws:
    lambda:
        functions:
            vat:
                functionName:isbn-validator 
                qualifer:isbn 
        region:eu-west-3# Paris Region

创建一个接口:

复制代码

src/main/java/example/micronaut/IsbnValidator.java

package example.micronaut;

import io.micronaut.http.annotation.Body;
import io.reactivex.Single;

publicinterfaceIsbnValidator { 
    Single<IsbnValidationResponse> validateIsbn(@Body IsbnValidationRequest req); 
}

创建一个 @FunctionClient:

复制代码

src/main/java/example/micronaut/FunctionIsbnValidator.java

packageexample.micronaut;

importio.micronaut.context.annotation.Requires; 
importio.micronaut.context.env.Environment; 
importio.micronaut.function.client.FunctionClient; 
importio.micronaut.http.annotation.Body; 
importio.reactivex.Single;
importjavax.inject.Named;

@FunctionClient 
@Requires(notEnv = Environment.TEST) 
publicinterfaceFunctionIsbnValidatorextendsIsbnValidator{
   @Override 
   @Named("isbn-validator") 
    Single<IsbnValidationResponse> validateIsbn(@BodyIsbnValidationRequest req);
}

关于上面这些代码有几点值得注意:

  • FunctionClient 注解可以在接口上应用引入通知(introduction advice),这样接口定义的方法就会成为远程函数的调用者。
  • 使用函数名 isbn-validator,与 application.yml 定义的一样。

最后一步是修改 gateway 的 BookController,让它调用函数。

复制代码

src/main/java/example/micronaut/BooksController.java

packageexample.micronaut;

importio.micronaut.http.annotation.Controller; 
importio.micronaut.http.annotation.Get; 
importio.micronaut.security.annotation.Secured; 
importio.reactivex.Flowable;

importjava.util.List;

@Secured("isAuthenticated()")
@Controller("/api") 
publicclassBooksController{
   privatefinalBooksFetcher booksFetcher; 
   privatefinalInventoryFetcher inventoryFetcher; 
   privatefinalIsbnValidator isbnValidator;
   publicBooksController(BooksFetcher booksFetcher, InventoryFetcher inventoryFetcher, IsbnValidator isbnValidator) {
       this.booksFetcher = booksFetcher; 
       this.inventoryFetcher = inventoryFetcher; 
       this.isbnValidator = isbnValidator;
    }

   @Get("/books") 
    Flowable<Book> findAll() { 
       returnbooksFetcher.fetchBooks()
             .flatMapMaybe(b -> isbnValidator.validateIsbn(new IsbnValidationRequest(b.getIsbn()))
                 .filter(IsbnValidationResponse::getValid)
                 .map(isbnValidationResponse -> b) 
              )
              .flatMapMaybe(b -> inventoryFetcher.inventory(b.getIsbn())
                  .filter(stock -> stock >0)
                  .map(stock -> { 
                      b.setStock(stock); 
                     returnb; 
                  })
              );
   }
}

我们通过构造函数注入了 IsbnValidator。调用远程函数对程序员来说是透明的。

结论

下面的图片说明了我们在这一系列文章中开发的应用程序:

  • 我们有三个微服务(一个 Java 服务、一个 Groovy 服务和一个 Kotlin 服务)。
  • 这些微服务使用 Consul 进行服务发现。
  • 这些微服务使用 Zipkin 作为分布式跟踪服务。
  • 我们添加了第四个微服务,一个部署到 AWS Lambda 的功能。
  • 微服务之间的通信是安全的。每个请求在 Authorization Http 标头中包含一个 JWT 令牌就可以通过网络。JWT 令牌通过内部请求自动传播。

关于 Micronaut 的更多内容,请访问 官方网站 。

关于作者

Micronaut 教程(二):分布式跟踪、JWT 安全和 AWS Lambda 部署

Sergio del AmoCaballero是一名手机应用程序(iOS、Android,后端由 Grails/Micronaut 驱动)开发者。自 2015 年起,Sergio del Amo 为 Groovy 生态系统和微服务维护着一个新闻源 Groovy Calamari 。

查看英文原文: Micronaut Tutorial: Part 2: Easy Distributed Tracing, JWT Security and AWS Lambda Deployment

原文  https://www.infoq.cn/articles/eZaMFBOPyrYoVfPi*qVq
正文到此结束
Loading...