我使用用户名-密码流来获取令牌。下面是我的示例代码:
public class UsernamePasswordFlowTest {
private static String authority;
private static Set<String> scope;
private static String clientId;
private static String username;
private static String password;
public static void main(String args[]) throws Exception {
setUpSampleData();
PublicClientApplication pca = PublicClientApplication.builder(clientId)
.authority(authority)
.build();
//Get list of accounts from the application's token cache, and search them for the configured username
//getAccounts() will be empty on this first call, as accounts are added to the cache when acquiring a token
Set<IAccount> accountsInCache = pca.getAccounts().join();
IAccount account = getAccountByUsername(accountsInCache, username);
//Attempt to acquire token when user's account is not in the application's token cache
IAuthenticationResult result = acquireTokenUsernamePassword(pca, scope, account, username, password);
System.out.println("Account username: " + result.account().username());
System.out.println("Access token: " + result.accessToken());
System.out.println("Id token: " + result.idToken());
System.out.println();
accountsInCache = pca.getAccounts().join();
account = getAccountByUsername(accountsInCache, username);
//Attempt to acquire token again, now that the user's account and a token are in the application's token cache
result = acquireTokenUsernamePassword(pca, scope, account, username, password);
System.out.println("Account username: " + result.account().username());
System.out.println("Access token: " + result.accessToken());
System.out.println("Id token: " + result.idToken());
}
private static IAuthenticationResult acquireTokenUsernamePassword(PublicClientApplication pca,
Set<String> scope,
IAccount account,
String username,
String password) throws Exception {
IAuthenticationResult result;
try {
SilentParameters silentParameters =
SilentParameters
.builder(scope)
.account(account)
.build();
// Try to acquire token silently. This will fail on the first acquireTokenUsernamePassword() call
// because the token cache does not have any data for the user you are trying to acquire a token for
result = pca.acquireTokenSilently(silentParameters).join();
System.out.println("==acquireTokenSilently call succeeded");
} catch (Exception ex) {
if (ex.getCause() instanceof MsalException) {
System.out.println("==acquireTokenSilently call failed: " + ex.getCause());
UserNamePasswordParameters parameters =
UserNamePasswordParameters
.builder(scope, username, password.toCharArray())
.build();
// Try to acquire a token via username/password. If successful, you should see
// the token and account information printed out to console
result = pca.acquireToken(parameters).join();
System.out.println("==username/password flow succeeded");
} else {
// Handle other exceptions accordingly
throw ex;
}
}
return result;
}
/**
* Helper function to return an account from a given set of accounts based on the given username,
* or return null if no accounts in the set match
*/
private static IAccount getAccountByUsername(Set<IAccount> accounts, String username) {
if (accounts.isEmpty()) {
System.out.println("==No accounts in cache");
} else {
System.out.println("==Accounts in cache: " + accounts.size());
for (IAccount account : accounts) {
if (account.username().equals(username)) {
return account;
}
}
}
return null;
}
/**
* Helper function unique to this sample setting. In a real application these wouldn't be so hardcoded, for example
* values such as username/password would come from the user, and different users may require different scopes
*/
private static void setUpSampleData() throws IOException {
authority = "https://login.microsoftonline.com/{tenantId}"; // tenantid = xxxxxxxx
scope = Collections.singleton("user.read");
clientId = "ebxxxx1c-e1xxx-4xxx-bxxx-dxxxxeaxxxx";
username = "testuser";
password = "xxxx";
}
}
但是得到异常:
com.microsoft.aad.msal4j。MsalClientException:在缓存中找不到令牌com.microsoft.aad.msal4j.AcquireTokenSilentSupplier.execute (AcquireTokenSilentSupplier.java: 98)com.microsoft.aad.msal4j.AuthenticationResultSupplier.get (AuthenticationResultSupplier.java: 59)在com.microsoft.aad.msal4j.AuthenticationResultSupplier.get (AuthenticationResultSupplier.java: 17)在java.base/java.util.concurrent.CompletableFuture AsyncSupply.run美元(CompletableFuture.java: 1700)
所致:com.microsoft.aad.msal4j。MsalServiceException:未知的服务异常。Http请求返回状态码404,没有响应体com.microsoft.aad.msal4j.MsalServiceExceptionFactory.fromHttpResponse (MsalServiceExceptionFactory.java: 52)在com.microsoft.aad.msal4j.UserDiscoveryRequest.execute (UserDiscoveryRequest.java: 34)com.microsoft.aad.msal4j.AcquireTokenByAuthorizationGrantSupplier.processPasswordGrant (AcquireTokenByAuthorizationGrantSupplier.java: 91)
有人能帮我理解这个异常吗?
com.microsoft.aad.msal4j.MsalServiceException
如果您的应用程序未在Azure AD中注册为公共客户端应用程序,则可能引发此异常。在Azure门户中,编辑应用程序的清单并设置allowPublicClient真的。
并检查指定的client_secret与此客户端的期望值不匹配。修改client_secret,然后重试。
MsalClientException
在库或设备本地发生错误时抛出。
更多细节请参考本文档
您可以在Github中遵循以下代码示例:https://github.com/Azure-Samples/ms-identity-java-desktop/blob/master/Username-Password-Flow/README.md