如何适应@Value(类路径:...)注入,如果不确定文件是否存在



我使用的是Spring Boot 2.4。在我的WebSecurityConfig(扩展WebSecurityCConfigurerAdapter(中,我有下面一段用于开发环境的代码:

@Bean
RelyingPartyRegistrationRepository replyingPartyRegistrationRepository() {
System.err.println("Metadatalocation is ||" + metadataLocation + "||");
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(metadataLocation)
.registrationId("my-id-here")
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}

对于暂存/生产,我需要基于https://github.com/spring-projects/spring-security-samples/blob/b2310d91fe198138d07bad17b5c86a2f13b698ae/servlet/spring-boot/java/saml2/login/src/main/java/example/SecurityConfiguration.java#L76因为我们会在那里与真正的idp联系。

@Bean
RelyingPartyRegistrationRepository replyingPartyRegistrationRepository(
@Value("classpath:credentials/tls.key") RSAPrivateKey privateKey) {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(metadataLocation)
.registrationId("my-other-id-here")
.signingX509Credentials(
(c) -> c.add(Saml2X509Credential.signing(privateKey, relyingPartyCertificate())))
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}

我的问题是如何将其集成到一种既适用于两种环境的方法中。可以使用基于指示环境的application.properties值的if语句(或者可以简单地通过检查RSAPrivateKey是否存在于该环境中(来执行任意一个版本(有或没有密钥/证书(的正确代码

然而,问题是注入@Value("classpath:credentials/tls.key") RSAPrivateKey privateKey,如果类路径位置不存在,它将抛出错误。

尝试的解决方案

  • 我曾尝试使用@Value("#{"classpath:credentials/tls.key" ?: null}")(以及它的许多变体(传递默认值,希望如果找不到文件,它会插入"null",但我想一旦尝试,就会出现"未找到文件"异常,所以这不起作用。

  • 我也尝试过Resource resource = resourceLoader.getResource("classpath:credentials/tls.key");的变体,但如何将该Resource转换为RSAPrivateKey?

  • 我想一个解决办法是在开发环境中的那个位置放一个假的/空的RSA密钥文件,加载它,然后忽略它,但这感觉很麻烦。。

PS:我的部分问题是,我不明白Spring Boot如何将类路径文件"强制"/转换为RSAPrivateKey对象?它之所以有效,是因为如果存在RSA文件,则注入会成功。我似乎找不到任何关于classpath:-前缀是如何发挥其魔力的文档。@Value("classpath:...")的所有示例都涉及加载Resource

感谢您提供的任何见解。

您可以将两个bean定义方法分开,并使用ConditionalOnProperty注释根据环境有条件地激活它们。代码如下所示:

@Bean
@ConditionalOnProperty(name = "env.name", havingValue = "dev")
RelyingPartyRegistrationRepository replyingPartyRegistrationRepositoryDev() {
System.err.println("Metadatalocation is ||" + metadataLocation + "||");
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(metadataLocation)
.registrationId("my-id-here")
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}
@Bean
@ConditionalOnMissingBean
RelyingPartyRegistrationRepository replyingPartyRegistrationRepositoryNonDev(
@Value("classpath:credentials/tls.key") RSAPrivateKey privateKey) {
RelyingPartyRegistration relyingPartyRegistration = RelyingPartyRegistrations
.fromMetadataLocation(metadataLocation)
.registrationId("my-other-id-here")
.signingX509Credentials(
(c) -> c.add(Saml2X509Credential.signing(privateKey, relyingPartyCertificate())))
.build();
return new InMemoryRelyingPartyRegistrationRepository(relyingPartyRegistration);
}

当环境是dev时,env.name属性需要设置为dev,然后使用不需要RSAPrivateKeyreplyingPartyRegistrationRepositoryDev方法初始化bean。当环境不是dev时,bean将使用replyingPartyRegistrationRepositoryNonDev方法和RSAPrivateKey进行初始化。这样就不需要在dev.中添加一个空的RSA密钥文件

更新:

下面这样的bean定义可以用于在文件存在时以一种方式初始化bean,在文件不存在时以另一种方式进行初始化,所有这些都使用相同的方法:

@Bean
public Resource resourceDefault(@Value("file:logback.xml") Resource inputResource) {
Resource resource = null;
if (inputResource.exists()) {
resource = inputResource;
} else {
resource = new ClassPathResource("logback-dev.xml");
}
return resource;
}

相关内容

最新更新