@ConditionalOnExpression
アノテーションを使用しないことをお勧めします。
代わりに@PreAuthorize
を使用することを検討してください。はい、それは春からのセキュリティです。
それが有効になっていて、動的にそれのために有効/無効状態を切り替えていない場合は、利用状況から各サービスを保護することができることをして
:
$ curl -u user:123 -XGET 'localhost:8080/api/work'
$ curl -u user:123 -XPOST 'localhost:8080/api/control/serviceC/enable'
true%
$ curl -u user:123 -XGET 'localhost:8080/api/work'
ServiceC doing some work%
$ curl -u user:123 -XPOST 'localhost:8080/api/control/serviceA/enable'
true%
$ curl -u user:123 -XGET 'localhost:8080/api/work'
ServiceA doing some work,ServiceC doing some work%
:
@SpringBootApplication
public class So44462763Application {
public static void main(String[] args) {
SpringApplication.run(So44462763Application.class, args);
}
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true) // <-- this is required for PreAuthorize annotation to work
public static class SecurityConfiguration extends WebSecurityConfigurerAdapter {
@Override
protected void configure(HttpSecurity http) throws Exception {
http.csrf().disable();
}
}
interface CxProperties {
boolean isServiceAEnabled();
boolean isServiceBEnabled();
boolean isServiceCEnabled();
boolean enableService(String service);
boolean disableService(String service);
}
@Component("cx")
public static class CxPropertiesImpl implements CxProperties {
private static final ConcurrentHashMap<String, Boolean> services = new ConcurrentHashMap<>(); //could be database/redis/property file/etc
@PostConstruct
private void init() {
//services.put("serviceA", true); //initial population from property file/network resource/whatever
}
public boolean isServiceAEnabled() {
return services.getOrDefault("serviceA", false);
}
public boolean isServiceBEnabled() {
return services.getOrDefault("serviceB", false);
}
public boolean isServiceCEnabled() {
return services.getOrDefault("serviceC", false);
}
//just a sample how you can dynamically control availability for each service
@Override
public boolean enableService(String service) {
services.put(service, true);
return services.getOrDefault(service, false);
}
@Override
public boolean disableService(String service) {
services.put(service, false);
return services.getOrDefault(service, false);
}
}
interface BusinessService {
String doSomething();
}
@Service("serviceA")
@PreAuthorize("@cx.serviceAEnabled")
public static class ServiceA implements BusinessService {
@Override
public String doSomething() {
return this.getClass().getSimpleName() + " doing some work";
}
}
@Service("serviceB")
@PreAuthorize("@cx.serviceBEnabled")
public static class ServiceB implements BusinessService {
@Override
public String doSomething() {
return this.getClass().getSimpleName() + " doing some work";
}
}
@Service("serviceC")
@PreAuthorize("@cx.serviceCEnabled")
public static class ServiceC implements BusinessService {
@Override
public String doSomething() {
return this.getClass().getSimpleName() + " doing some work";
}
}
@RestController
@RequestMapping("/api/work")
public static class WorkApi {
private static final Logger log = LoggerFactory.getLogger(WorkApi.class);
private final List<BusinessService> businessServices;
@Autowired
public WorkApi(final List<BusinessService> businessServices) {
this.businessServices = businessServices;
}
@GetMapping
public String doWork() {
final StringJoiner joiner = new StringJoiner(",");
for (BusinessService service : businessServices) {
try {
joiner.add(service.doSomething());
} catch (AccessDeniedException e) {
log.warn("Service {} is disabled.", service);
}
}
return joiner.toString();
}
}
@RestController
@RequestMapping("/api/control")
public static class ControlApi {
private final CxProperties cxProperties;
@Autowired
public ControlApi(final CxProperties cxProperties) {
this.cxProperties = cxProperties;
}
@PostMapping("{service}/enable")
public boolean enable(@PathVariable("service") String serviceName) {
return cxProperties.enableService(serviceName);
}
@PostMapping("{service}/disable")
public boolean disable(@PathVariable("service") String serviceName) {
return cxProperties.disableService(serviceName);
}
}
}
そしてここでは、サンプルの使用でありますこの方法を使用すると、再起動しなくてもサービスのアクセシビリティを制御できます。
これはすべて、春のセキュリティなしでも実行できますが、少し手作業が必要となり、コード全体の可読性がわずかに低下する可能性があります。
'@ ConditionalOnProperty'についてはどうですか? – fateddy
私はアプリケーションを使用していません。https://docs.spring.io/spring-boot/docs/current/reference/html/boot-features-developing-auto-configuration.html#boot-features-property-conditionsを参照してください。 ymlまたはプロパティファイル。私は、プロジェクト内で作られたカスタマイズされたファイルから設定データを読みました。したがって、クラスオブジェクトを評価する必要があります。しかし、とにかく、たとえ@ConditionalOnPropertyの場合でも、私たちはどのように評価を遅らせ/注文しますか? –
私はそれが少なくともあなたが記述した方法では不可能だと信じています。しかし、それはいくつかの回避策かもしれません。より大きなスケールで達成しようとしていることを説明できますか? –