0
点赞
收藏
分享

微信扫一扫

Spring Cloud Open Service Broker

Spring Cloud Open Service Broker_spring

Spring Cloud Open Service Broker 是一个框架,用于构建实现Open Service Broker API​ 的Spring Boot应用程序。

1. 简介

开放服务代理 API定义了平台和服务代理的服务市场之间的 HTTP 接口。

服务代理负责:

  • 宣传其服务产品和计划的目录
  • 预配(创建或更新)服务实例
  • 在服务实例和客户端应用程序之间创建绑定
  • 删除服务实例和客户端应用程序之间的绑定
  • 取消预配(删除)服务实例

Spring CloudOpen Service Broker 项目通过实现所需的 Spring Web 控制器、域对象和配置,为符合 Open Service Broker API 的服务代理提供基架。 服务代理作者可以提供实现相应接口的 Spring bean。

2. 入门

大多数服务代理应用程序实现开放服务代理 API 端点之外的 API 或 Web UI 端点。 这些附加终结点可能会提供有关应用程序的信息、提供仪表板 UI 或提供对应用程序行为的控制。 开发人员可以使用SpringWebFlux或Spring MVC实现这些额外的端点。

虽然 spring-cloud-open-service-broker 在其 API 中使用反应式返回类型,但同时支持阻塞 Web 堆栈(例如使用 tomcat/jetty)或非阻塞 Web 堆栈(例如 netty/undertow 使用)。请参阅模块和中的相应验收测试。​​spring-boot-starter-web​​​​spring-boot-starter-webflux​​​​spring-cloud-open-service-broker-acceptance-webmvc​​​​spring-cloud-open-service-broker-acceptance-webflux​

Spring Cloud Open Service Broker 入门程序不包括对 Spring WebFlux 或 Spring MVC 的传递依赖。 需要 Spring 引导 Web 启动器才能激活自动配置。

2.1. Maven 依赖

要在Spring Web应用程序中使用Spring Cloud Open Service Broker,请添加启动器,如下所示:

<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-open-service-broker</artifactId>
<version>${version}</version>
</dependency>
</dependencies>

2.2. Gradle 依赖

要在Spring Web应用程序中使用Spring Cloud Open Service Broker,请添加启动器,如下所示:

dependencies {
api 'org.springframework.cloud:spring-cloud-starter-open-service-broker:${version}'
}

2.3. 配置服务代理

请参阅 Spring Boot 文档以开始构建Spring Boot应用程序。

该框架提供了实现服务代理所需的大多数组件的默认实现。 在 Spring Boot 方式中,您可以通过提供自己的 Spring bean 实现来覆盖默认行为,并且框架会远离其默认值。

首先,在服务代理的主应用程序类上使用注释,如下所示:​​@SpringBootApplication​

@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}

这将触发包含默认配置。

2.4. 使用唯一的平台 ID

对服务代理的每个请求都能够通过路径变量接收。 这允许服务代理检测其已注册的平台的身份,如Cloud Foundry文档中所述。​​platformInstanceId​

例如,操作员可以将服务代理注册到一个 CF 平台实例,如下所示:

$ cf create-service-broker mybroker username password https://mybroker.app.local/east

操作员还可以将同一服务代理注册到另一个 CF 平台实例,如下所示:

$ cf create-service-broker mybroker username password https://mybroker.app.local/west

然后,代理可以预期对以下路径的请求,其中请求对象中的字段包含值“east”或“west”:​​platformInstanceId​

- https://username:password@mybroker.app.local/east/v2/catalog
- https://username:password@mybroker.app.local/west/v2/catalog

2.5. 自定义服务代理路径

有时,自定义服务代理路径的前缀很有用。 例如,应用程序可能出于其他目的为冲突的终结点提供服务。 您可以使用该属性更改代理路径的前缀,如下所示:​​spring.cloud.openservicebroker.base-path​

spring.cloud.openservicebroker.base-path=/broker

前面的示例将端点从(例如,)更改为。​​application.properties​​​​/​​​​/broker/​​​​/broker/v2/catalog​

3. 广告服务

服务代理目录提供一组元数据,用于描述可用服务以及成本和功能等属性。 目录通过服务代理终结点提供给平台的服务市场。/v2/catalog

服务代理可以提供Catalog类型的 Spring Bean,也可以实现服务CatalogService。

3.1. 提供目录 Bean

您可以通过创建一个 Spring Bean 并将其贡献给 Spring 来公开服务代理目录 应用程序上下文。 您可以在 Spring 类中执行此操作,如下所示:​​@Configuration​

package com.example.servicebroker;

import org.springframework.cloud.servicebroker.model.catalog.Catalog;
import org.springframework.cloud.servicebroker.model.catalog.Plan;
import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleCatalogConfiguration {

@Bean
public Catalog catalog() {
Plan plan = Plan.builder()
.id("simple-plan")
.name("standard")
.description("A simple plan")
.free(true)
.build();

ServiceDefinition serviceDefinition = ServiceDefinition.builder()
.id("example-service")
.name("example")
.description("A simple example")
.bindable(true)
.tags("example", "tags")
.plans(plan)
.build();

return Catalog.builder()
.serviceDefinitions(serviceDefinition)
.build();
}
}

3.2. 使用属性提供目录

您可以在 Java 属性文件或 YAML 文件中使用 Spring 引导外部化配置来配置目录。 在自动配置期间,将解析目录并使其作为 abean 提供。​​Catalog​

以下 YAML 文件配置目录:

# Example Spring Boot YAML configuration
spring:
cloud:
openservicebroker:
catalog:
services:
- id: example-service
name: example
description: A simple example
bindable: true
tags:
- example
- tags
plans:
- id: simple-plan
name: standard
description: A simple plan

以下属性文件配置目录:

# Example Spring Boot properties configuration
spring.cloud.openservicebroker.catalog.services[0].id=example-service
spring.cloud.openservicebroker.catalog.services[0].name=example
spring.cloud.openservicebroker.catalog.services[0].description=A simple example
spring.cloud.openservicebroker.catalog.services[0].bindable=true
spring.cloud.openservicebroker.catalog.services[0].tags[0]=example
spring.cloud.openservicebroker.catalog.services[0].tags[1]=tags
spring.cloud.openservicebroker.catalog.services[0].plans[0].id=simple-plan
spring.cloud.openservicebroker.catalog.services[0].plans[0].name=standard
spring.cloud.openservicebroker.catalog.services[0].plans[0].description=A simple plan

3.3. 实现目录服务

服务代理可以通过实现接口来更好地控制目录。 如果需要从环境或外部数据源读取目录元数据的某些详细信息,则可能需要这样做。​​CatalogService​

以下示例实现接口:​​CatalogService​

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.catalog.Catalog;
import org.springframework.cloud.servicebroker.model.catalog.Plan;
import org.springframework.cloud.servicebroker.model.catalog.ServiceDefinition;
import org.springframework.cloud.servicebroker.service.CatalogService;
import org.springframework.stereotype.Service;

@Service
public class ExampleCatalogService implements CatalogService {

@Override
public Mono<Catalog> getCatalog() {
return getServiceDefinition("example-service")
.map(serviceDefinition -> Catalog.builder()
.serviceDefinitions(serviceDefinition)
.build());
}

@Override
public Mono<ServiceDefinition> getServiceDefinition(String serviceId) {
return Mono.just(ServiceDefinition.builder()
.id(serviceId)
.name("example")
.description("A simple example")
.bindable(true)
.tags("example", "tags")
.plans(getPlan())
.build());
}

private Plan getPlan() {
return Plan.builder()
.id("simple-plan")
.name("standard")
.description("A simple plan")
.free(true)
.build();
}
}

4. 服务实例

服务代理负责配置其目录中播发的服务,并在底层云平台中管理其生命周期。 代理创建的服务称为服务实例。

服务代理必须实现ServiceInstanceService接口,并提供该接口所需方法的实现。 每个方法接收一个 Java 对象参数,该参数包含来自平台的请求的所有详细信息,并返回一个 Java 对象值,该值向平台提供操作的详细信息。

服务实例创建、更新和删除操作可以同步或异步执行。

当服务代理同步创建、更新或删除服务实例时,仅当操作成功完成或发生故障时,相应的接口方法才应阻止并向平台返回响应。

异步执行操作时,服务代理可以在操作完成之前向平台返回响应,并在响应中指示操作正在进行中。 平台轮询服务代理以获取指示异步操作时的操作状态。

4.1. 服务实例创建

服务代理必须提供createServiceInstance() 方法的实现。

服务代理通常在创建服务实例时在平台或其他系统中预配资源。 服务代理负责跟踪与服务实例关联的任何资源,以便将来检索、更新或删除。

4.1.1. 事件注册表

可以利用事件进一步自定义服务实例创建。 为此:

  1. 自动连接CreateServiceInstanceEventFlowRegistrybean。
  2. 使用addInitializationFlow()、addCompletionFlow() 或 addErrorFlow() 方法之一来注册自定义反应式流,以便在创建服务实例的各个阶段运行。

4.2. 服务实例更新

如果在服务目录中设置为 thefield,那么服务代理必须提供updateServiceInstance() 方法的实现。 否则,平台永远不会调用此方法,可以使用接口中的默认实现。plan_updateabletrue

服务代理可以在更新服务实例或部署新资源时修改现有资源的配置。

4.2.1. 事件注册表

可以利用事件进一步自定义服务实例更新。 为此:

  1. 自动连接UpdateServiceInstanceEventFlowRegistrybean。
  2. 使用addInitializationFlow()、addCompletionFlow() 或 addErrorFlow() 方法之一来注册自定义反应式流,以便在更新服务实例的各个阶段运行。

4.3. 服务实例删除

deleteServiceInstance() 方法的实现必须由服务代理提供。

创建操作中预配的任何资源都应由删除操作取消预配。

4.3.1. 事件注册表

可以利用事件进一步自定义服务实例删除。 为此:

  1. 自动连接DeleteServiceInstanceEventFlowRegistrybean。
  2. 使用addInitializationFlow()、addCompletionFlow() 或 addErrorFlow() 方法之一来注册自定义反应式流,以便在删除服务实例的各个阶段运行。

4.4. 服务实例运行状态检索

如果任何创建、更新或删除操作都可以向平台返回异步“正在进行的操作”响应,则服务代理必须提供getLastOperation() 方法的实现。 否则,平台永远不会调用此方法,可以使用接口中的默认实现。

平台为正在进行异步操作的服务实例轮询服务代理的此方法,直到服务代理指示操作已成功完成或发生故障。

4.4.1. 事件注册表

可以利用事件进一步自定义服务实例上次操作请求。 为此:

  1. 自动连接AsyncOperationServiceInstanceEventFlowRegistrybean。
  2. 使用 addInitializationFlow()、addCompletionFlow() 或 addErrorFlow() 方法之一来注册自定义反应式流,以便在上次操作检索的各个阶段运行。

4.5. 服务实例检索

如果在服务目录中设置为 thefield,则服务代理必须提供getServiceInstance() 方法的实现。 否则,平台永远不会调用此方法,可以使用接口中的默认实现。​​instances_retrievable​​​​true​

服务代理负责维护支持检索操作所需的任何服务实例状态。

4.6. 实现示例

以下示例显示了一个服务实例实现:

package com.example.servicebroker;

import java.util.Map;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationRequest;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationResponse;
import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.GetServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.OperationState;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.service.ServiceInstanceService;
import org.springframework.stereotype.Service;

@Service
public class ExampleServiceInstanceService implements ServiceInstanceService {

@Override
public Mono<CreateServiceInstanceResponse> createServiceInstance(CreateServiceInstanceRequest request) {
String serviceInstanceId = request.getServiceInstanceId();
String planId = request.getPlanId();
Map<String, Object> parameters = request.getParameters();

//
// perform the steps necessary to initiate the asynchronous
// provisioning of all necessary resources
//

String dashboardUrl = ""; /* construct a dashboard URL */

return Mono.just(CreateServiceInstanceResponse.builder()
.dashboardUrl(dashboardUrl)
.async(true)
.build());
}

@Override
public Mono<UpdateServiceInstanceResponse> updateServiceInstance(UpdateServiceInstanceRequest request) {
String serviceInstanceId = request.getServiceInstanceId();
String planId = request.getPlanId();
String previousPlan = request.getPreviousValues().getPlanId();
Map<String, Object> parameters = request.getParameters();

//
// perform the steps necessary to initiate the asynchronous
// updating of all necessary resources
//

return Mono.just(UpdateServiceInstanceResponse.builder()
.async(true)
.build());
}

@Override
public Mono<DeleteServiceInstanceResponse> deleteServiceInstance(DeleteServiceInstanceRequest request) {
String serviceInstanceId = request.getServiceInstanceId();
String planId = request.getPlanId();

//
// perform the steps necessary to initiate the asynchronous
// deletion of all provisioned resources
//

return Mono.just(DeleteServiceInstanceResponse.builder()
.async(true)
.build());
}

@Override
public Mono<GetServiceInstanceResponse> getServiceInstance(GetServiceInstanceRequest request) {
String serviceInstanceId = request.getServiceInstanceId();

//
// retrieve the details of the specified service instance
//

String dashboardUrl = ""; /* retrieve dashboard URL */

return Mono.just(GetServiceInstanceResponse.builder()
.dashboardUrl(dashboardUrl)
.build());
}

@Override
public Mono<GetLastServiceOperationResponse> getLastOperation(GetLastServiceOperationRequest request) {
String serviceInstanceId = request.getServiceInstanceId();

//
// determine the status of the operation in progress
//

return Mono.just(GetLastServiceOperationResponse.builder()
.operationState(OperationState.SUCCEEDED)
.build());
}
}

4.7. 事件流配置示例

有多种方法可以配置服务实例事件流。 一种选择是自动连接一个或多个注册表并直接与注册表交互。 另一种选择是为特定流定义 bean。 这些 Bean 会自动识别并添加到相应的注册表中。 最后一个选项是声明一个新的注册表 bean。 但是,请注意,定义新的注册表 Bean 会覆盖提供的自动配置。

4.7.1. 选项 1:自动连线注册表

以下示例显示了服务实例事件流的配置:

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationRequest;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationResponse;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.service.events.AsyncOperationServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.CreateServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.DeleteServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.UpdateServiceInstanceEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceInitializationFlow;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleServiceInstanceEventFlowsConfiguration {

private final CreateServiceInstanceEventFlowRegistry createRegistry;

private final UpdateServiceInstanceEventFlowRegistry updateRegistry;

private final DeleteServiceInstanceEventFlowRegistry deleteRegistry;

private final AsyncOperationServiceInstanceEventFlowRegistry asyncRegistry;

public ExampleServiceInstanceEventFlowsConfiguration(CreateServiceInstanceEventFlowRegistry createRegistry,
UpdateServiceInstanceEventFlowRegistry updateRegistry,
DeleteServiceInstanceEventFlowRegistry deleteRegistry,
AsyncOperationServiceInstanceEventFlowRegistry asyncRegistry) {
this.createRegistry = createRegistry;
this.updateRegistry = updateRegistry;
this.deleteRegistry = deleteRegistry;
this.asyncRegistry = asyncRegistry;

prepareCreateEventFlows()
.then(prepareUpdateEventFlows())
.then(prepareDeleteEventFlows())
.then(prepareLastOperationEventFlows())
.subscribe();
}

private Mono<Void> prepareCreateEventFlows() {
return Mono.just(createRegistry)
.map(registry -> registry.addInitializationFlow(new CreateServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(CreateServiceInstanceRequest request) {
//
// do something before the instance is created
//
return Mono.empty();
}
})
.then(registry.addCompletionFlow(new CreateServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(CreateServiceInstanceRequest request,
CreateServiceInstanceResponse response) {
//
// do something after the instance is created
//
return Mono.empty();
}
}))
.then(registry.addErrorFlow(new CreateServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(CreateServiceInstanceRequest request, Throwable t) {
//
// do something if an error occurs while creating an instance
//
return Mono.empty();
}
})))
.then();
}

private Mono<Void> prepareUpdateEventFlows() {
return Mono.just(updateRegistry)
.map(registry -> registry.addInitializationFlow(new UpdateServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(UpdateServiceInstanceRequest request) {
//
// do something before the instance is updated
//
return Mono.empty();
}
})
.then(registry.addCompletionFlow(new UpdateServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(UpdateServiceInstanceRequest request,
UpdateServiceInstanceResponse response) {
//
// do something after the instance is updated
//
return Mono.empty();
}
}))
.then(registry.addErrorFlow(new UpdateServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(UpdateServiceInstanceRequest request, Throwable t) {
//
// do something if an error occurs while updating an instance
//
return Mono.empty();
}
})))
.then();
}

private Mono<Void> prepareDeleteEventFlows() {
return Mono.just(deleteRegistry)
.map(registry -> registry.addInitializationFlow(new DeleteServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(DeleteServiceInstanceRequest request) {
//
// do something before the instance is deleted
//
return Mono.empty();
}
})
.then(registry.addCompletionFlow(new DeleteServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(DeleteServiceInstanceRequest request,
DeleteServiceInstanceResponse response) {
//
// do something after the instance is deleted
//
return Mono.empty();
}
}))
.then(registry.addErrorFlow(new DeleteServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(DeleteServiceInstanceRequest request, Throwable t) {
//
// do something if an error occurs while deleting an instance
//
return Mono.empty();
}
})))
.then();
}

private Mono<Void> prepareLastOperationEventFlows() {
return Mono.just(asyncRegistry)
.map(registry -> registry.addInitializationFlow(new AsyncOperationServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(GetLastServiceOperationRequest request) {
//
// do something before returning the last operation
//
return Mono.empty();
}
})
.then(registry.addCompletionFlow(new AsyncOperationServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(GetLastServiceOperationRequest request,
GetLastServiceOperationResponse response) {
//
// do something after returning the last operation
//
return Mono.empty();
}
}))
.then(registry.addErrorFlow(new AsyncOperationServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(GetLastServiceOperationRequest request, Throwable t) {
//
// do something if an error occurs while processing the last operation response
//
return Mono.empty();
}
})))
.then();
}

}

4.7.2. 选项 2:事件流 Bean

或者,您可以为各个流配置 bean,如下所示:

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.CreateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.DeleteServiceInstanceResponse;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationRequest;
import org.springframework.cloud.servicebroker.model.instance.GetLastServiceOperationResponse;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceRequest;
import org.springframework.cloud.servicebroker.model.instance.UpdateServiceInstanceResponse;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.UpdateServiceInstanceInitializationFlow;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleServiceInstanceEventFlowsConfiguration2 {

//
// Create Service Instance flows
//

@Bean
public CreateServiceInstanceInitializationFlow createServiceInstanceInitializationFlow() {
return new CreateServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(CreateServiceInstanceRequest request) {
//
// do something before the instance is created
//
return Mono.empty();
}
};
}

@Bean
public CreateServiceInstanceCompletionFlow createServiceInstanceCompletionFlow() {
return new CreateServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(CreateServiceInstanceRequest request,
CreateServiceInstanceResponse response) {
//
// do something after the instance is created
//
return Mono.empty();
}
};
}

@Bean
public CreateServiceInstanceErrorFlow createServiceInstanceErrorFlow() {
return new CreateServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(CreateServiceInstanceRequest request, Throwable t) {
//
// do something if an error occurs while creating an instance
//
return Mono.empty();
}
};
}

//
// Update Service Instance flows
//

@Bean
public UpdateServiceInstanceInitializationFlow updateServiceInstanceInitializationFlow() {
return new UpdateServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(
UpdateServiceInstanceRequest request) {
//
// do something before the instance is updated
//
return Mono.empty();
}
};
}

@Bean
public UpdateServiceInstanceCompletionFlow updateServiceInstanceCompletionFlow() {
return new UpdateServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(UpdateServiceInstanceRequest request,
UpdateServiceInstanceResponse response) {
//
// do something after the instance is updated
//
return Mono.empty();
}
};
}

@Bean
public UpdateServiceInstanceErrorFlow updateServiceInstanceErrorFlow() {
return new UpdateServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(UpdateServiceInstanceRequest request, Throwable t) {
//
// do something if an error occurs while updating an instance
//
return Mono.empty();
}
};
}

//
// Delete Service Instance flows
//

@Bean
public DeleteServiceInstanceInitializationFlow deleteServiceInstanceInitializationFlow() {
return new DeleteServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(
DeleteServiceInstanceRequest request) {
//
// do something before the instance is deleted
//
return Mono.empty();
}
};
}

@Bean
public DeleteServiceInstanceCompletionFlow deleteServiceInstanceCompletionFlow() {
return new DeleteServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(DeleteServiceInstanceRequest request,
DeleteServiceInstanceResponse response) {
//
// do something after the instance is deleted
//
return Mono.empty();
}
};
}

@Bean
public DeleteServiceInstanceErrorFlow deleteServiceInstanceErrorFlow() {
return new DeleteServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(DeleteServiceInstanceRequest request, Throwable t) {
//
// do something if an error occurs while deleting the instance
//
return Mono.empty();
}
};
}

//
// Get Last Operation flows
//

@Bean
public AsyncOperationServiceInstanceInitializationFlow getLastOperationInitializationFlow() {
return new AsyncOperationServiceInstanceInitializationFlow() {
@Override
public Mono<Void> initialize(
GetLastServiceOperationRequest request) {
//
// do something before getting the last operation
//
return Mono.empty();
}
};
}

@Bean
public AsyncOperationServiceInstanceCompletionFlow getLastOperationCompletionFlow() {
return new AsyncOperationServiceInstanceCompletionFlow() {
@Override
public Mono<Void> complete(GetLastServiceOperationRequest request,
GetLastServiceOperationResponse response) {
//
// do something after getting the last operation
//
return Mono.empty();
}
};
}

@Bean
public AsyncOperationServiceInstanceErrorFlow getLastOperationErrorFlow() {
return new AsyncOperationServiceInstanceErrorFlow() {
@Override
public Mono<Void> error(GetLastServiceOperationRequest request, Throwable t) {
//
// do something if an error occurs while getting the last operation
//
return Mono.empty();
}
};
}

}

5. 服务绑定

服务代理可以通过服务绑定向服务实例的使用者提供信息。 服务绑定通常用于向应用程序公开服务实例资源的凭据。

如果字段设置为服务目录中的任何计划,那么服务代理必须提供ServiceInstanceBindingService接口的实现。 否则,平台不会调用服务代理的绑定方法,可以使用此接口的默认实现。 每个方法接收一个 Java 对象参数,其中包含来自平台的请求的所有详细信息,并返回一个 Java 对象值,该值向平台提供操作的详细信息。​​bindable​​​​true​

服务绑定创建和删除操作可以同步或异步执行。

  • 当服务代理同步创建或删除服务绑定时,仅当操作成功完成或发生故障时,相应的接口方法才应阻止并向平台返回响应。
  • 异步执行操作时,服务代理可以在操作完成之前向平台返回响应,并在响应中指示操作正在进行中。 平台轮询服务代理以获取指示异步操作时的操作状态。

5.1. 服务绑定创建

服务代理必须提供createServiceInstanceBinding() 方法的实现。

支持两种类型的绑定:

  • 应用绑定可用于向应用程序提供凭据、日志排出和卷服务。
  • 路由绑定可用于为平台提供代理请求时使用的路由。

此方法的响应允许返回两种 Java 对象类型之一,以反映两种受支持的绑定类型。

服务代理可以为所有绑定请求生成一组凭据,也可以为每个绑定请求提供唯一凭据。

5.1.1. 事件注册表

可以使用事件进一步自定义服务绑定创建。 为此:

  1. 自动连接CreateServiceInstanceBindingEventFlowRegistrybean。
  2. 使用addInitializationFlow()、addCompletionFlow() 或 addErrorFlow() 方法之一来注册要在创建服务绑定的各个阶段运行的自定义反应式流。

5.2. 服务绑定删除

服务代理必须提供deleteServiceInstanceBinding() 方法的实现。

删除操作应取消预配在创建操作中预配的任何凭据。

5.2.1. 事件注册表

可以使用事件进一步自定义服务绑定删除。 为此: .自动连接DeleteServiceInstanceBindingEventFlowRegistrybean。

  1. 使用addInitializationFlow()、addCompletionFlow() 或 addErrorFlow() 方法之一来注册自定义反应式流,以便在删除服务绑定的各个阶段运行。

5.3. 服务绑定操作状态检索

如果任何创建或删除操作可以向平台返回异步“正在进行的操作”响应,则服务代理必须提供getLastOperation() 方法的实现。否则,平台永远不会调用此方法,可以使用接口中的默认实现。

平台为正在进行异步操作的服务实例轮询服务代理的此方法,直到服务代理指示操作已成功完成或发生故障。

5.3.1. 事件注册表

可以使用事件进一步自定义服务绑定上一个操作请求。 为此: .自动连接AsyncOperationServiceInstanceBindingEventFlowRegistrybean。

  1. 使用 addInitializationFlow()、addCompletionFlow() 或 addErrorFlow() 方法之一来注册自定义反应式流,以便在上次操作检索的各个阶段运行。

5.4. 服务绑定检索

如果在服务目录中设置了该字段,则服务目录必须提供getServiceInstanceBinding() 方法的实现。 否则,平台永远不会调用此方法,可以使用接口中的默认实现。bindings_retrievabletrue

服务代理负责维护支持检索操作所需的任何服务绑定状态。

5.5. 实现示例

下面的示例实现服务绑定:

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceAppBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceAppBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.GetServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.service.ServiceInstanceBindingService;
import org.springframework.stereotype.Service;

@Service
public class ExampleServiceBindingService implements ServiceInstanceBindingService {

@Override
public Mono<CreateServiceInstanceBindingResponse> createServiceInstanceBinding(CreateServiceInstanceBindingRequest request) {
String serviceInstanceId = request.getServiceInstanceId();
String bindingId = request.getBindingId();

//
// create credentials and store for later retrieval
//

String url = new String(/* build a URL to access the service instance */);
String bindingUsername = new String(/* create a user */);
String bindingPassword = new String(/* create a password */);

CreateServiceInstanceBindingResponse response = CreateServiceInstanceAppBindingResponse.builder()
.credentials("url", url)
.credentials("username", bindingUsername)
.credentials("password", bindingPassword)
.bindingExisted(false)
.async(true)
.build();

return Mono.just(response);
}

@Override
public Mono<DeleteServiceInstanceBindingResponse> deleteServiceInstanceBinding(DeleteServiceInstanceBindingRequest request) {
String serviceInstanceId = request.getServiceInstanceId();
String bindingId = request.getBindingId();

//
// delete any binding-specific credentials
//

return Mono.just(DeleteServiceInstanceBindingResponse.builder()
.async(true)
.build());
}

@Override
public Mono<GetServiceInstanceBindingResponse> getServiceInstanceBinding(GetServiceInstanceBindingRequest request) {
String serviceInstanceId = request.getServiceInstanceId();
String bindingId = request.getBindingId();

//
// retrieve the details of the specified service binding
//

String url = new String(/* retrieved URL */);
String bindingUsername = new String(/* retrieved user */);
String bindingPassword = new String(/* retrieved password */);

GetServiceInstanceBindingResponse response = GetServiceInstanceAppBindingResponse.builder()
.credentials("username", bindingUsername)
.credentials("password", bindingPassword)
.credentials("url", url)
.build();

return Mono.just(response);
}
}

5.6. 事件流配置示例

有多种方法可以配置服务绑定事件流。 一种选择是自动连接一个或多个注册表并直接与注册表交互。 另一种选择是为特定流定义 bean。 这些 Bean 会自动识别并添加到相应的注册表中。 最后一个选项是声明一个新的注册表 bean。 但是,请注意,定义新的注册表 Bean 会覆盖提供的自动配置。

5.6.1. 选项 1:自动连线注册表

以下示例配置服务绑定事件流:

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.GetLastServiceBindingOperationRequest;
import org.springframework.cloud.servicebroker.model.binding.GetLastServiceBindingOperationResponse;
import org.springframework.cloud.servicebroker.service.events.AsyncOperationServiceInstanceBindingEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.CreateServiceInstanceBindingEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.DeleteServiceInstanceBindingEventFlowRegistry;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceBindingCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceBindingErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceBindingInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceBindingCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceBindingErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceBindingInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceBindingCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceBindingErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceBindingInitializationFlow;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleServiceBindingEventFlowsConfiguration {

private final CreateServiceInstanceBindingEventFlowRegistry createRegistry;

private final DeleteServiceInstanceBindingEventFlowRegistry deleteRegistry;

private final AsyncOperationServiceInstanceBindingEventFlowRegistry asyncRegistry;

public ExampleServiceBindingEventFlowsConfiguration(
CreateServiceInstanceBindingEventFlowRegistry createRegistry,
DeleteServiceInstanceBindingEventFlowRegistry deleteRegistry,
AsyncOperationServiceInstanceBindingEventFlowRegistry asyncRegistry) {
this.createRegistry = createRegistry;
this.deleteRegistry = deleteRegistry;
this.asyncRegistry = asyncRegistry;

prepareCreateEventFlows()
.then(prepareDeleteEventFlows())
.then(prepareLastOperationEventFlows())
.subscribe();
}

private Mono<Void> prepareCreateEventFlows() {
return Mono.just(createRegistry)
.map(registry -> registry.addInitializationFlow(new CreateServiceInstanceBindingInitializationFlow() {
@Override
public Mono<Void> initialize(CreateServiceInstanceBindingRequest request) {
//
// do something before the instance is created
//
return Mono.empty();
}
})
.then(registry.addCompletionFlow(new CreateServiceInstanceBindingCompletionFlow() {
@Override
public Mono<Void> complete(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceBindingResponse response) {
//
// do something after the instance is created
//
return Mono.empty();
}
}))
.then(registry.addErrorFlow(new CreateServiceInstanceBindingErrorFlow() {
@Override
public Mono<Void> error(CreateServiceInstanceBindingRequest request, Throwable t) {
//
// do something if an error occurs while creating an instance
//
return Mono.empty();
}
})))
.then();
}

private Mono<Void> prepareDeleteEventFlows() {
return Mono.just(deleteRegistry)
.map(registry -> registry.addInitializationFlow(new DeleteServiceInstanceBindingInitializationFlow() {
@Override
public Mono<Void> initialize(DeleteServiceInstanceBindingRequest request) {
//
// do something before the instance is deleted
//
return Mono.empty();
}
})
.then(registry.addCompletionFlow(new DeleteServiceInstanceBindingCompletionFlow() {
@Override
public Mono<Void> complete(DeleteServiceInstanceBindingRequest request,
DeleteServiceInstanceBindingResponse response) {
//
// do something after the instance is deleted
//
return Mono.empty();
}
}))
.then(registry.addErrorFlow(new DeleteServiceInstanceBindingErrorFlow() {
@Override
public Mono<Void> error(DeleteServiceInstanceBindingRequest request, Throwable t) {
//
// do something if an error occurs while deleting an instance
//
return Mono.empty();
}
})))
.then();
}

private Mono<Void> prepareLastOperationEventFlows() {
return Mono.just(asyncRegistry)
.map(registry -> registry.addInitializationFlow(new AsyncOperationServiceInstanceBindingInitializationFlow() {
@Override
public Mono<Void> initialize(GetLastServiceBindingOperationRequest request) {
//
// do something before the instance is deleted
//
return Mono.empty();
}
})
.then(registry.addCompletionFlow(new AsyncOperationServiceInstanceBindingCompletionFlow() {
@Override
public Mono<Void> complete(GetLastServiceBindingOperationRequest request,
GetLastServiceBindingOperationResponse response) {
//
// do something after the instance is deleted
//
return Mono.empty();
}
}))
.then(registry.addErrorFlow(new AsyncOperationServiceInstanceBindingErrorFlow() {
public Mono<Void> error(GetLastServiceBindingOperationRequest request, Throwable t) {
//
// do something if an error occurs while deleting an instance
//
return Mono.empty();
}
})))
.then();
}

}

5.6.2. 选项 2:事件流 Bean

或者,您可以为各个流配置 bean,如下所示:

package com.example.servicebroker;

import reactor.core.publisher.Mono;

import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.CreateServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingRequest;
import org.springframework.cloud.servicebroker.model.binding.DeleteServiceInstanceBindingResponse;
import org.springframework.cloud.servicebroker.model.binding.GetLastServiceBindingOperationRequest;
import org.springframework.cloud.servicebroker.model.binding.GetLastServiceBindingOperationResponse;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceBindingCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceBindingErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.AsyncOperationServiceInstanceBindingInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceBindingCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceBindingErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.CreateServiceInstanceBindingInitializationFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceBindingCompletionFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceBindingErrorFlow;
import org.springframework.cloud.servicebroker.service.events.flows.DeleteServiceInstanceBindingInitializationFlow;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleServiceBindingEventFlowsConfiguration2 {

//
// Create Service Instance Binding flows
//

@Bean
public CreateServiceInstanceBindingInitializationFlow createServiceInstanceBindingInitializationFlow() {
return new CreateServiceInstanceBindingInitializationFlow() {
@Override
public Mono<Void> initialize(CreateServiceInstanceBindingRequest request) {
//
// do something before the service instance binding completes
//
return Mono.empty();
}
};
}

@Bean
public CreateServiceInstanceBindingCompletionFlow createServiceInstanceBindingCompletionFlow() {
return new CreateServiceInstanceBindingCompletionFlow() {
@Override
public Mono<Void> complete(CreateServiceInstanceBindingRequest request,
CreateServiceInstanceBindingResponse response) {
//
// do something after the service instance binding completes
//
return Mono.empty();
}
};
}

@Bean
public CreateServiceInstanceBindingErrorFlow createServiceInstanceBindingErrorFlow() {
return new CreateServiceInstanceBindingErrorFlow() {
@Override
public Mono<Void> error(CreateServiceInstanceBindingRequest request, Throwable t) {
//
// do something if an error occurs while creating a service instance binding
//
return Mono.empty();
}
};
}

//
// Delete Service Instance Binding flows
//

@Bean
public DeleteServiceInstanceBindingInitializationFlow deleteServiceInstanceBindingInitializationFlow() {
return new DeleteServiceInstanceBindingInitializationFlow() {
@Override
public Mono<Void> initialize(DeleteServiceInstanceBindingRequest request) {
//
// do something before the service instance binding is deleted
//
return Mono.empty();
}
};
}

@Bean
public DeleteServiceInstanceBindingCompletionFlow deleteServiceInstanceBindingCompletionFlow() {
return new DeleteServiceInstanceBindingCompletionFlow() {
@Override
public Mono<Void> complete(DeleteServiceInstanceBindingRequest request,
DeleteServiceInstanceBindingResponse response) {
//
// do something after the service instance binding is deleted
//
return Mono.empty();
}
};
}

@Bean
public DeleteServiceInstanceBindingErrorFlow deleteServiceInstanceBindingErrorFlow() {
return new DeleteServiceInstanceBindingErrorFlow() {
@Override
public Mono<Void> error(DeleteServiceInstanceBindingRequest request, Throwable t) {
//
// do something if an error occurs while deleting a service instance binding
//
return Mono.empty();
}
};
}

//
// Get Last Service Instance Binding Operation flows
//

@Bean
public AsyncOperationServiceInstanceBindingInitializationFlow getLastOperationServiceInstanceBindingInitializationFlow() {
return new AsyncOperationServiceInstanceBindingInitializationFlow() {
@Override
public Mono<Void> initialize(GetLastServiceBindingOperationRequest request) {
//
// do something before getting the last operation
//
return Mono.empty();
}
};
}

@Bean
public AsyncOperationServiceInstanceBindingCompletionFlow getLastOperationServiceInstanceBindingCompletionFlow() {
return new AsyncOperationServiceInstanceBindingCompletionFlow() {
@Override
public Mono<Void> complete(GetLastServiceBindingOperationRequest request,
GetLastServiceBindingOperationResponse response) {
//
// do something after getting the last operation
//
return Mono.empty();
}
};
}

@Bean
public AsyncOperationServiceInstanceBindingErrorFlow getLastOperationServiceInstanceBindingErrorFlow() {
return new AsyncOperationServiceInstanceBindingErrorFlow() {
@Override
public Mono<Void> error(GetLastServiceBindingOperationRequest request, Throwable t) {
//
// do something if an error occurs while getting the last operation
//
return Mono.empty();
}
};
}
}

6. API 版本验证

平台需要在每次调用开放服务代理 API 时提供HTTP 标头,以指示平台支持的 API 规范版本。 您可以配置 Spring Cloud Open Service Broker,以验证平台在每次调用服务代理时提供的版本。 默认情况下,此版本验证配置为允许任何 API 版本。

要自定义版本验证,请设置指定服务代理所需的 API 版本的属性,如下所示:​​apiVersion​

spring.cloud.openservicebroker.apiVersion=2.13

或者,您可以提供 aSpring bean,如下所示:​​BrokerApiVersion​

package com.example.servicebroker;

import org.springframework.cloud.servicebroker.model.BrokerApiVersion;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;

@Configuration
public class ExampleApiVersionConfiguration {
@Bean
public BrokerApiVersion brokerApiVersion() {
return new BrokerApiVersion("2.13");
}
}

在同时配置弹簧豆和属性的情况下,春豆优先于属性。

如果指定了 API 版本,并且平台在标头中提供了不同的版本,则框架会向平台返回错误。​​X-Broker-API-Version​​​​412 Precondition Failed​

如前所述,默认版本验证配置为允许任何 API 版本。 但是,若要完全禁用版本验证,可以将属性设置为,如下所示:​​api-version-check-endabled​​​​false​

spring.cloud.openservicebroker.api-version-check-enabled = false

7. 服务代理安全

开放服务代理 API 规范中未指定服务代理终结点的身份验证和授权,但某些平台要求或允许在向平台注册服务代理时提供基本身份验证或OAuth2凭据。

Spring 云开放服务代理项目未实现任何安全配置。 服务代理应用程序端点可以使用Spring 安全性和Spring 引导安全配置进行保护,方法是将安全性应用于具有路径匹配模式的应用程序端点:/v2/**

7.1. 配置示例

以下示例在Spring MVC中实现了一个安全配置,即阻止Webstack。Spring WebFlux反应式堆栈的类似配置是必要的,请参阅Spring 安全 webflux 支持

package com.example.servicebroker;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.provisioning.InMemoryUserDetailsManager;

@Configuration
@EnableWebSecurity
public class ExampleSecurityConfig extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
http
.csrf().disable()
.authorizeRequests()
.antMatchers("/v2/**").hasRole("ADMIN")
.and()
.httpBasic();
}

@Bean
public InMemoryUserDetailsManager userDetailsService() {
return new InMemoryUserDetailsManager(adminUser());
}

private UserDetails adminUser() {
return User
.withUsername("admin")
.password("{noop}supersecret")
.roles("ADMIN")
.build();
}
}

举报

相关推荐

0 条评论