Microsoft.Identity.Web 抽象化了 MSAL.NET 的复杂性。 它提供更高级别的 API,可用于处理 MSAL.NET 的内部功能,例如处理条件访问错误、高速缓存。
下面是调用下游 API 的守护程序应用的 Program.cs:
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Identity.Abstractions;
using Microsoft.Identity.Web;
// In the Program.cs, acquire a token for your downstream API
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.AddDownstreamApi("MyApi",
tokenAcquirerFactory.Configuration.GetSection("MyWebApi"));
var sp = tokenAcquirerFactory.Build();
var api = sp.GetRequiredService<IDownstreamApi>();
var result = await api.GetForAppAsync<IEnumerable<TodoItem>>("MyApi");
Console.WriteLine($"result = {result?.Count()}");
下面是调用 Microsoft Graph 的守护程序应用的 Program.cs:
var tokenAcquirerFactory = TokenAcquirerFactory.GetDefaultInstance();
tokenAcquirerFactory.Services.AddMicrosoftGraph();
var serviceProvider = tokenAcquirerFactory.Build();
try
{
GraphServiceClient graphServiceClient = serviceProvider.GetRequiredService<GraphServiceClient>();
var users = await graphServiceClient.Users
.GetAsync(r => r.Options.WithAppOnly());
Console.WriteLine($"{users.Count} users");
Console.ReadKey();
}
catch (Exception ex) { Console.WriteLine("We could not retrieve the user's list: " + $"{ex}"); }
HttpURLConnection conn = (HttpURLConnection) url.openConnection();
// Set the appropriate header fields in the request header.
conn.setRequestProperty("Authorization", "Bearer " + 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);
使用 HTTP 客户端(例如 Axios),作为授权持有者通过访问令牌调用 API 终结点 URI。
const axios = require('axios');
async function callApi(endpoint, accessToken) {
const options = {
headers: {
Authorization: `Bearer ${accessToken}`
}
};
console.log('request made to web API at: ' + new Date().toString());
try {
const response = await axios.default.get(endpoint, options);
return response.data;
} catch (error) {
console.log(error)
return error;
}
};
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()
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);
...
对于守护程序应用,需要预先批准所调用的 Web API。 守护程序应用没有增量同意。 (没有用户交互。)租户管理员需要预先为应用程序提供同意和所有 API 权限。 如果要调用多个 API,则每次调用 AcquireTokenForClient
时都需要为每个资源获取一个令牌。 MSAL 将使用应用程序令牌缓存来避免不必要的服务调用。