如何使用 msal4j 和 Azure Blob 存储库更新令牌
How to renew token using msal4j and Azure Blob Storage library
我们使用 Microsoft 的 Java 库访问 Azure Blob 存储,并使用 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();
}
这工作正常,但访问令牌最终会过期。此时操作开始失败。理论上有一个refresh token可以用来更新access token,但是好像不是IAuthenticationResult接口的一部分。我的问题是:
- 可以使用此模式更新令牌吗?
- 如果不行,怎么办?是否有另一种模式支持更新?或者我应该忽略更新并只获取一个全新的访问令牌?
- 如果我得到一个新的访问令牌,我该如何将它安装到现有的
storageAccount
客户端中?我可以只调用 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) {
}
}
}
}
AuthenticationContext.acquireTokenSilent:
该函数将首先查看缓存并自动检查令牌是否过期。此外,如果在缓存中找不到合适的访问令牌,但刷新令牌可用,该函数将自动使用刷新令牌。此方法不会为用户显示 UI。如果需要提示,该方法将 return 异常
如果使用MSAL获取token,refresh token会存储在不暴露的缓存中。我们可以使用 acquireTokenSilently
获取新的访问令牌
SilentParameters parameters = SilentParameters.builder(
Collections.singleton("User.ReadBasic.All"),
result.account()).build();
CompletableFuture<IAuthenticationResult> future = app.acquireTokenSilently(parameters);
IAuthenticationResult updatedResult = future.get();
参考:SO Thread
我们使用 Microsoft 的 Java 库访问 Azure Blob 存储,并使用 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();
}
这工作正常,但访问令牌最终会过期。此时操作开始失败。理论上有一个refresh token可以用来更新access token,但是好像不是IAuthenticationResult接口的一部分。我的问题是:
- 可以使用此模式更新令牌吗?
- 如果不行,怎么办?是否有另一种模式支持更新?或者我应该忽略更新并只获取一个全新的访问令牌?
- 如果我得到一个新的访问令牌,我该如何将它安装到现有的
storageAccount
客户端中?我可以只调用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) {
}
}
}
}
AuthenticationContext.acquireTokenSilent:
该函数将首先查看缓存并自动检查令牌是否过期。此外,如果在缓存中找不到合适的访问令牌,但刷新令牌可用,该函数将自动使用刷新令牌。此方法不会为用户显示 UI。如果需要提示,该方法将 return 异常
如果使用MSAL获取token,refresh token会存储在不暴露的缓存中。我们可以使用 acquireTokenSilently
获取新的访问令牌SilentParameters parameters = SilentParameters.builder(
Collections.singleton("User.ReadBasic.All"),
result.account()).build();
CompletableFuture<IAuthenticationResult> future = app.acquireTokenSilently(parameters);
IAuthenticationResult updatedResult = future.get();
参考:SO Thread