我正在使用 azure keyvault 来提取我的应用程序属性。我正在使用 spring @value
注释通过将占位符放置在 application.properties
文件中来设置密钥库中的属性值。在我的主应用程序上下文中,我能够提取属性并测试应用程序流程。在测试上下文中,它抛出了一些问题,说没有注入保险库属性。这是我的属性 bean 类的样子,以及问题的堆栈跟踪。我试图模拟 ControllerTest 类中的 KeyVaultProperties 仍然有同样的问题。
KeyVault.java
@Data
@Component
public class KeyVaultProperties {
@Value("${by-pass-token}")
private String token;
@Value("${backend-clients}")
private String clients;
}
ControllerTest.java
@SpringBootTest
@SpringBootConfiguration
@AutoConfigureMockMvc
public class ControllerTest {
@Autowired
Controller controller;
@Autowired
private MockMvc mockMvc;
@Test
public void contextLoads() throws Exception {
assertThat(controller).isNotNull();
}
}
Controller.java
@RestController
@Slf4j
@RequestMapping("/api/test")
public class Controller {
@GetMapping(value = "/hello")
public String getString() {
return "Hello";
}
}
AuthConfiguration.java
@Slf4j
@Component
public class AuthConfiguration extends HandlerInterceptorAdapter {
@Autowired
private KeyVaultProperties keyVaultProperties;
private static final String CORRELATION_ID_LOG_VAR_NAME = "correlationId";
private static final String CORRELATION_ID_HEADER_NAME = "Correlation-Id";
@PostConstruct
public void setup() {
System.out.println("-------@PostConstruct------setup----------------");
sub = keyVaultProperties.getClients();
ByPass = keyVaultProperties.getAuthByPassToken();
}
@Override
public boolean preHandle(final HttpServletRequest request, final HttpServletResponse response, final Object handler)
throws Exception {
System.out.println("-------preHandle----------------------");
final Boolean isValidToken;
final String correlationId = getCorrelationIdFromHeader(request);
log.info("correlationId:{}",correlationId);
MDC.put(CORRELATION_ID_LOG_VAR_NAME, correlationId);
return true;
}
@Override
public void afterCompletion(final HttpServletRequest request, final HttpServletResponse response,
final Object handler, final Exception ex) {
System.out.println("-------afterCompletion----------------------");
MDC.remove(CORRELATION_ID_LOG_VAR_NAME);
}
private String getCorrelationIdFromHeader(final HttpServletRequest request) {
String correlationId = request.getHeader(CORRELATION_ID_HEADER_NAME);
if (correlationId == null) {
correlationId = generateUniqueCorrelationId();
}
return correlationId;
}
}
app/src/main/resources/application.properties
by-pass-token = ${BY-PASS-TOKEN}
backend-clients = ${CLIENTS}
azure.keyvault.enabled=true
堆栈跟踪:
2021-04-04 13:28:03.640 [main] ERROR org.springframework.boot.SpringApplication - Application run failed
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'AuthConfiguration': Unsatisfied dependency expressed through field 'KeyVaultProperties'; nested exception is org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'KeyVaultProperties': Injection of autowired dependencies failed; nested exception is java.lang.IllegalArgumentException: Could not resolve placeholder 'by-pass-token' in value "${by-pass-token}"
at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject
答案 0 :(得分:1)
您可以通过 Azure AD 进行身份验证,将属性值设置为 Azure Key Vault。
注意:为了让您的应用程序能够访问 Key Vault 内容,您必须在 Key Vault 中为您的应用程序设置适当的权限。导航到 Azure Key Vault > 访问策略 > 添加访问策略 > 在选择主体中选择您的应用程序。
依赖关系:
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure</artifactId>
<version>1.3.0</version>
</dependency>
<dependency>
<groupId>com.microsoft.azure</groupId>
<artifactId>azure-keyvault</artifactId>
<version>1.0.0</version>
</dependency>
通过基于 client credentials flow 的 AzureAD 连接到 Key Vault:
public class ClientSecretKeyVaultCredential extends KeyVaultCredentials
{
private String clientId;
private String clientKey;
public ClientSecretKeyVaultCredential( String clientId, String clientKey ) {
this.clientId = clientId;
this.clientKey = clientKey;
}
@Override
public String doAuthenticate(String authorization, String resource, String scope) {
AuthenticationResult token = getAccessTokenFromClientCredentials(
authorization, resource, clientId, clientKey);
return token.getAccessToken();
}
private static AuthenticationResult getAccessTokenFromClientCredentials(
String authorization, String resource, String clientId, String clientKey) {
AuthenticationContext context = null;
AuthenticationResult result = null;
ExecutorService service = null;
try {
service = Executors.newFixedThreadPool(1);
context = new AuthenticationContext(authorization, false, service);
ClientCredential credentials = new ClientCredential(clientId, clientKey);
Future<AuthenticationResult> future = context.acquireToken(
resource, credentials, null);
result = future.get();
} catch (Exception e) {
throw new RuntimeException(e);
} finally {
service.shutdown();
}
if (result == null) {
throw new RuntimeException("authentication result was null");
}
return result;
}
}
访问密钥保管库:
您可以使用 client.setSecret("Secret-Name", "value")
来设置您的属性。
// ClientSecretKeyVaultCredential is the implementation of KeyVaultCredentials
KeyVaultClient client = new KeyVaultClient(
new ClientSecretKeyVaultCredential(clientId, clientKey));
// KEYVAULT_URL is the location of the keyvault to use: https://<yourkeyvault>.vault.azure.net
SecretBundle secret = client.getSecret( KEYVAULT_URL, "Secret-name" );
log( secret.value() );