MSAL.NET 中的 AuthenticationResult 属性
用于获取令牌的方法返回 AuthenticationResult
。 对于异步方法,将返回 Task<AuthenticationResult>
。
在 MSAL.NET 中,AuthenticationResult
会公开
AccessToken
,以便 Web API 访问资源。 此参数是一个字符串,通常是一个 Base-64 编码的 JWT。 客户端不应该查看访问令牌的内部。 不保证格式稳定,并且可以为资源加密令牌。 编写的代码依赖于客户端上的访问令牌内容是最大的错误来源之一,并且会违反客户端逻辑。 有关详细信息,请参阅访问令牌。
- 用户的
IdToken
。 此参数是编码的 JWT。 有关详细信息,请参阅 ID 令牌。
ExpiresOn
会告知令牌过期的日期和时间。
TenantId
包含用户所在的租户。 对于来宾用户(Microsoft Entra B2B 方案),租户 ID 是来宾租户,而不是唯一的租户。
为用户传送令牌时,AuthenticationResult
还包含有关此用户的信息。 对于在请求令牌时未提供应用用户的机密客户端流,此用户信息为 null。
- 令牌的颁发
Scopes
。
- 用户的唯一 ID。
IAccount
MSAL.NET 通过 IAccount
接口定义了帐户的概念。 此中断性变更提供了正确的语义。 同一用户可以在不同的 Microsoft Entra 目录中拥有多个帐户。 此外,由于会提供主帐户信息,MSAL.NET 可以在使用来宾方案的情况下提供更有用的信息。
下图显示了 IAccount
接口的结构。
AccountId
类使用下表中显示的属性标识特定租户中的帐户。
属性 |
说明 |
TenantId |
GUID 的字符串表示形式,是帐户所在租户的 ID。 |
ObjectId |
GUID 的字符串表示形式,是拥有租户中的帐户的用户的 ID。 |
Identifier |
帐户的唯一标识符。 Identifier 是 ObjectId 和 TenantId 的串联,由逗号分隔。 它们不是 Base 64 编码的。 |
IAccount
接口表示单个帐户的相关信息。 同一用户可以存在于不同的租户中,这意味着一个用户可以有多个帐户。 其成员显示在下表中。
属性 |
说明 |
Username |
一个字符串,包含 UserPrincipalName (UPN) 格式的可显示值,例如 john.doe@contoso.com。 此字符串可以为 null,这不同于 HomeAccountId 和 HomeAccountId.Identifier,后两者不会为 null。 此属性替换 MSAL.NET 旧版本中 IUser 的 DisplayableId 属性。 |
Environment |
一个字符串,包含此帐户的标识提供者,例如 login.partner.microsoftonline.cn 。 此属性替换 IUser 的 IdentityProvider 属性,不同之处是 IdentityProvider 还包含除云环境以外的租户信息。 而此处的该值仅仅是主机。 |
HomeAccountId |
用户的主帐户的帐户 ID。 此属性在 Microsoft Entra 租户中唯一标识用户。 |
使用令牌调用受保护的 API
在 MSAL 在 result
中返回 AuthenticationResult
后,将它添加到 HTTP 授权标头,然后再调用该令牌以访问受保护的 Web API。
httpClient = new HttpClient();
httpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);
// Call the web API.
HttpResponseMessage response = await _httpClient.GetAsync(apiUri);
...
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
PublicClientApplication pca = PublicClientApplication.builder(clientId)
.authority(authority)
.build();
// Acquire a token, acquireTokenHelper would call publicClientApplication's acquireTokenSilently then acquireToken
// see https://github.com/Azure-Samples/ms-identity-java-desktop for a full example
IAuthenticationResult authenticationResult = acquireTokenHelper(pca);
// Set the appropriate header fields in the request header.
conn.setRequestProperty("Authorization", "Bearer " + authenticationResult.accessToken);
conn.setRequestProperty("Accept", "application/json");
String response = HttpClientHelper.getResponseStringFromConn(conn);
int responseCode = conn.getResponseCode();
if(responseCode != HttpURLConnection.HTTP_OK) {
throw new IOException(response);
}
JSONObject responseObject = HttpClientHelper.processResponse(responseCode, response);
在适用于 iOS 和 macOS 的 MSAL 中调用 Web API
用于获取令牌的方法返回一个 MSALResult
对象。 MSALResult
公开可用于调用 Web API 的 accessToken
属性。 将访问令牌添加到 HTTP 授权标头,然后再调用该令牌以访问受保护的 Web API。
Objective-C:
NSMutableURLRequest *urlRequest = [NSMutableURLRequest new];
urlRequest.URL = [NSURL URLWithString:"https://contoso.api.com"];
urlRequest.HTTPMethod = @"GET";
urlRequest.allHTTPHeaderFields = @{ @"Authorization" : [NSString stringWithFormat:@"Bearer %@", accessToken] };
NSURLSessionDataTask *task =
[[NSURLSession sharedSession] dataTaskWithRequest:urlRequest
completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable error) {}];
[task resume];
Swift:
let urlRequest = NSMutableURLRequest()
urlRequest.url = URL(string: "https://contoso.api.com")!
urlRequest.httpMethod = "GET"
urlRequest.allHTTPHeaderFields = [ "Authorization" : "Bearer \(accessToken)" ]
let task = URLSession.shared.dataTask(with: urlRequest as URLRequest) { (data: Data?, response: URLResponse?, error: Error?) in }
task.resume()
调用多个 API:增量同意和条件访问
若要为同一用户调用多个 API,请在获得第一个 API 的令牌后调用 AcquireTokenSilent
。 大多数情况下,你会以静默方式获得其他 API 的令牌。
var result = await app.AcquireTokenXX("scopeApi1")
.ExecuteAsync();
result = await app.AcquireTokenSilent("scopeApi2")
.ExecuteAsync();
以下情况需要交互:
- 用户已许可第一个 API,但现在需要许可更多范围。 这种许可称为增量许可。
- 第一个 API 不需要多重身份验证,但下一个 API 需要。
var result = await app.AcquireTokenXX("scopeApi1")
.ExecuteAsync();
try
{
result = await app.AcquireTokenSilent("scopeApi2")
.ExecuteAsync();
}
catch(MsalUiRequiredException ex)
{
result = await app.AcquireTokenInteractive("scopeApi2")
.WithClaims(ex.Claims)
.ExecuteAsync();
}
使用 HTTP 客户端(例如 Axios),作为授权持有者通过访问令牌调用 API 终结点 URI。
const axios = require('axios');
async function callEndpointWithToken(endpoint, accessToken) {
const options = {
headers: {
Authorization: `Bearer ${accessToken}`
}
};
console.log('Request made at: ' + new Date().toString());
const response = await axios.default.get(endpoint, options);
return response.data;
}
endpoint = "url to the API"
http_headers = {'Authorization': 'Bearer ' + result['access_token'],
'Accept': 'application/json',
'Content-Type': 'application/json'}
data = requests.get(endpoint, headers=http_headers, stream=False).json()