如何使用msal4j与Azure Blob Storage库实现访问令牌更新
我们使用微软的Java库访问Azure Blob Storage,通过msal4j库采用OAuth2客户端访问模式获取访问令牌,代码片段如下:
StorageCredentialsToken storageCredentialsToken = new StorageCredentialsToken(account_name, generateOAuthToken()); storageAccount = new CloudStorageAccount(storageCredentialsToken, true); private String generateOAuthToken() throws MalformedURLException { String authority = String.format(ACTIVE_DIRECTORY_ENDPOINT + "/%s/oauth2/v2.0/token", tenant_id); Set<String> scope = Collections.singleton(String.format("https://%s.blob.core.windows.net/.default", account_name)); IClientCredential credential = ClientCredentialFactory.createFromSecret(client_secret); ConfidentialClientApplication cca = ConfidentialClientApplication .builder(client_id, credential) .authority(authority) .build(); ClientCredentialParameters parameters = ClientCredentialParameters .builder(scope) .build(); IAuthenticationResult result = cca.acquireToken(parameters).join(); return result.accessToken(); }
上述代码可正常运行,但访问令牌最终会过期,此时相关操作会开始报错。理论上存在刷新令牌可用于更新访问令牌,但刷新令牌似乎未被包含在IAuthenticationResult接口中。我的疑问如下:
- 采用当前模式能否实现令牌更新?
- 如果不行,有什么解决方案?是否存在其他支持令牌更新的模式?还是应该忽略更新逻辑,直接重新获取全新的访问令牌?
- 如果获取了新的访问令牌,如何将其配置到已有的
storageAccount客户端中?如果保留了StorageCredentialsToken实例,是否可以直接调用StorageCredentialsToken.updateToken()完成更新?
更新:收到的回复很有帮助,但最终我发现在使用clientId/tenantId的场景下无法实现真正的令牌更新,这可能是设计使然?不过在令牌过期前重新获取新令牌的方案是可行的,代码片段如下:
IAuthenticationResult authResult = generateOAuthToken(); StorageCredentialsToken storageCredentialsToken = new StorageCredentialsToken(account_name, authResult.accessToken()); new Thread(new OAuthTokenRenewer(authResult, storageCredentialsToken)).start(); storageAccount = new CloudStorageAccount(storageCredentialsToken, true); private IAuthenticationResult generateOAuthToken() throws MalformedURLException { String authority = String.format(ACTIVE_DIRECTORY_ENDPOINT + "/%s/oauth2/v2.0/token", tenant_id); Set<String> scope = Collections.singleton(String.format("https://%s.blob.core.windows.net/.default", account_name)); IClientCredential credential = ClientCredentialFactory.createFromSecret(client_secret); ConfidentialClientApplication cca = ConfidentialClientApplication .builder(client_id, credential) .authority(authority) .build(); ClientCredentialParameters parameters = ClientCredentialParameters .builder(scope) .build(); return cca.acquireToken(parameters).join(); } private class OAuthTokenRenewer implements Runnable { IAuthenticationResult authResult; final StorageCredentialsToken storageCredentialsToken; public OAuthTokenRenewer(IAuthenticationResult authResult, StorageCredentialsToken storageCredentialsToken) { this.authResult = authResult; this.storageCredentialsToken = storageCredentialsToken; } @Override public void run() { while (true) { try { Thread.sleep(60 * 1000L); long now = System.currentTimeMillis(); if (authResult.expiresOnDate().getTime() - now < RENEWAL_WINDOW_MS) { authResult = generateOAuthToken(); storageCredentialsToken.updateToken(authResult.accessToken()); } } catch (Exception ex) { } } } }
内容的提问来源于stack exchange,提问作者Wheezil
相关产品推荐
相关产品推荐

