В моем program.cs в .NET 6 это код, который я использую для проверки подлинности Azure AD.
string[] initialScopes = builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options => {
builder.Configuration.GetSection("AzureAd").Bind(options);
options.NonceCookie.SecurePolicy = CookieSecurePolicy.Always;
options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
});
Как получить токен доступа после проверки подлинности с использованием потока проверки подлинности платформы Microsoft Identity? Мне нужен токен доступа в последующих запросах для доступа к защищенным ресурсам без необходимости использовать JavaScript для получения нового токена доступа каждый раз.
У меня уже есть clientId, tenantId и clientSecret.
Этот код взят из https://learn.microsoft.com/en-us/azure/active-directory/develop/scenario-web-api-call-api-acquire-token?tabs=aspnetcore
[Authorize]
public class MyApiController : Controller
{
/// <summary>
/// The web API will accept only tokens 1) for users, 2) that have the `access_as_user` scope for
/// this API.
/// </summary>
static readonly string[] scopeRequiredByApi = new string[] { "access_as_user" };
static readonly string[] scopesToAccessDownstreamApi = new string[] { "api://MyTodolistService/access_as_user" };
private readonly ITokenAcquisition _tokenAcquisition;
public MyApiController(ITokenAcquisition tokenAcquisition)
{
_tokenAcquisition = tokenAcquisition;
}
public IActionResult Index()
{
HttpContext.VerifyUserHasAnyAcceptedScope(scopeRequiredByApi);
string accessToken = _tokenAcquisition.GetAccessTokenForUserAsync(scopesToAccessDownstreamApi);
return await callTodoListService(accessToken);
}
}
Как получить scopeRequiredByApi
и scopesToAccessDownstreamApi
?
В своем запуске добавьте строку .EnableTokenAcquisitionToCallDownstreamApi()
и выберите реализацию кэша токенов, например .AddInMemoryTokenCaches()
.
builder.Services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApp(options => {
builder.Configuration.GetSection("AzureAd").Bind(options);
options.NonceCookie.SecurePolicy = CookieSecurePolicy.Always;
options.CorrelationCookie.SecurePolicy = CookieSecurePolicy.Always;
})
.EnableTokenAcquisitionToCallDownstreamApi()
.AddDownstreamWebApi("MyApi", Configuration.GetSection("MyApiConfig"))
.AddInMemoryTokenCaches();
Внедрите интерфейс ITokenAcquisition
в свой контроллер/сервис. Чтобы получить токен доступа, вызовите:
string token = await _tokenAcquisition.GetAccessTokenForUserAsync(scopes);
Из справки Microsoft :
Обновлено: для последующего вопроса, добавленного позже
Как получить
scopeRequiredByApi
иscopesToAccessDownstreamApi
?
На портале Azure перейдите к App Registrations
и откройте регистрацию приложения API. Перейти в раздел Expose an API
. Вы должны найти свои прицелы там.
это будет задокументировано в API, к которому вы пытаетесь получить доступ
Я уже вижу эту строку в вашем коде: string[] initialScopes = builder.Configuration.GetValue<string>("DownstreamApi:Scopes")?.Split(' ');
Меня немного смущает scopes
. Да, у меня есть initialScopes
, и я поставил значение «user.read», которое, как мне кажется, и есть scopeRequiredByApi
. А как же scopesToAccessDownstreamApi
? Как мне это получить?
На портале Azure перейдите к App Registrations
и откройте регистрацию приложения API. Перейти к Expose an API
. Вы должны найти свой диапазон там.
Не уверен, что хорошо начинать отсюда. Для авторизации Azure AD (создания токена доступа) существует несколько потоков, наиболее часто используется поток кода аутентификации . Позвольте пользователю войти в систему, затем он может использовать учетные данные для создания токена доступа с разрешением delegated
API, токен будет иметь scp
претензия. Поток учетных данных клиента - не нужно входить в систему, сгенерируйте токен с application
разрешением API от имени самого приложения, токен будет содержать roles
требование). Поток от имени — используется, когда API requires to call another API
обоим API требуется токен доступа).
О API permission type
, например, Microsoft graph создает API календаря , используя делегированное разрешение API, можно обновлять ресурс для самого пользователя. Но с помощью API приложения приложение может изменить любое событие календаря пользователя, находящегося в целевом арендаторе. Поскольку мы можем set Azure AD to protect our own API
, мы также можем создавать разрешения API в Azure AD, выбирая предоставление делегированного разрешения API или предоставление разрешения API приложения.
Согласно ссылке, которой вы поделились в вопросе, вы пытаетесь использовать поток от имени, поскольку документ представляет собой руководство для одного API, вызывающего другой API. Тогда, пожалуйста, позвольте мне сделать предположение здесь. У вас есть клиентское приложение, которое интегрировало MSAL, чтобы вы могли позволить пользователям входить в систему и получать токен доступа, вы использовали этот токен для вызова собственного API, ваш API требует вызова другого API для получения некоторой другой информации.
Как я уже сказал, Azure AD может защитить наш собственный веб-API. Итак, мы можем перейти к Azure AD -> App Registrations -> create an Azure AD app or choose an existing one -> Expose an API -> after create the API, add a scope and name it like Steve_Allowed
, поскольку предполагается, что пользователь вызывает API, поэтому я создаю область для предоставления делегированного API. Тогда в same Azure AD application -> API permissions -> Add a permission -> My APIs -> choose the AAD app -> Delegated permissions -> choose Steve_Allowed and click Add permissions -> click grant admin consent button beside add api permission button
. Далее вам также необходимо создать секрет клиента в Certificates & secrets
лезвии, если у вас его нет.
Теперь с настройками в Azure AD мы уже закончили, переходим к приложению API. Как вы знаете, когда вы хотите вызвать API, защищенный Azure AD, вам нужно добавить заголовок запроса, например Authorization: Bearer xxxx
. В наш веб-API нам нужно интегрировать Azure AD для проверки запроса, чтобы он мог дать вам правильный ответ или ошибку 401. Итак, в проекте API добавьте код, как показано ниже, но, возможно, вы уже сделали это.
using Microsoft.AspNetCore.Authentication.JwtBearer;
using Microsoft.Identity.Web;
...
builder.Services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme)
.AddMicrosoftIdentityWebApi(builder.Configuration.GetSection("AzureAd"))
.EnableTokenAcquisitionToCallDownstreamApi()//this 2 lines for using _tokenAcquisition to generate another access token
.AddInMemoryTokenCaches();
builder.Services.AddHttpClient();
...
app.UseAuthentication();
app.UseAuthorization();
"AzureAd": {
"Instance": "https://login.microsoftonline.com/",
"ClientId": "azure_ad_app_id",
"ClientSecret": "client_secret",
"Domain": "tenant_id",
"TenantId": "tenant_id",
"Audience": "api://client_id"
},
Предположим, что он содержит API, который добавил атрибут [Authorize]
с URL-адресом https://localhost:7072/WeatherForecast
, затем добавьте заголовок запроса. В своем коде API вы можете использовать приведенный ниже код, чтобы получить токен в заголовке запроса.
StringValues authorizationToken;
HttpContext.Request.Headers.TryGetValue("Authorization", out authorizationToken);
string incomingToken = authorizationToken.ToString().Replace("Bearer ", "");
И здесь входящий Токен содержал нужный вам scopeRequiredByApi
. Но он уже валидирован к середине, так что метод писать не нужно
VerifyUserHasAnyAcceptedScope для проверки токена.
Теперь мы успешно получили доступ к API, а затем нам нужно использовать поток on_behalf_of для доступа к другому API. Поскольку промежуточное ПО уже выполнило проверку за нас, мы можем напрямую использовать _tokenAcquisition
в нашем коде, чтобы сгенерировать еще один токен доступа и использовать его для вызова другого API. Таким образом, в вашем API вы можете иметь код, как показано ниже. Обратите внимание, что поскольку вы пытаетесь вызвать другой API, если этот API также управляется вами, вам может потребоваться открыть другой API, тогда вы сможете получить новую область действия. Если этот API управляется другими, например API создания календаря, вам нужно перейти к документу API, чтобы получить область действия Calendars.ReadWrite
. Поставщик API должен предоставить вам область, и эта область — это то, что вам нужно, scopesToAccessDownstreamApi.
private readonly ITokenAcquisition _tokenAcquisition;
private readonly IHttpClientFactory _httpClientFactory;
public WeatherForecastController(ITokenAcquisition tokenAcquisition, IHttpClientFactory httpClientFactory)
{
_tokenAcquisition = tokenAcquisition;
_httpClientFactory = httpClientFactory;
}
[HttpGet(Name = "GetWeatherForecast")]
public async Task<string> GetAsync()
{
var accessToken = await _tokenAcquisition.GetAccessTokenForUserAsync(new string[] { "api://client_id/scopeName" });
var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, "https://localhost:7212/WeatherForecast")
{
Headers =
{
{ HeaderNames.Authorization, "Bearer "+ accessToken}
}
};
var httpClient = _httpClientFactory.CreateClient();
var response = await httpClient.SendAsync(httpRequestMessage);
var res = "";
if (response.StatusCode == HttpStatusCode.OK)
{
res = await response.Content.ReadAsStringAsync();
}
return "hello";
}
===========================Резюме====================== ====
Вам нужно, чтобы один API вызывал другой API, если оба API управляются вами, вам лучше создать 2 приложения Azure AD и предоставить разрешение API в обоих из них. Если вы хотите вызвать какой-либо API, вам необходимо установить область действия для создания маркера доступа для API. Например, вы предоставили разрешение API для API 1, область действия которого должна выглядеть как api://client_id1/scope_name_for_API1
. Затем используйте его в заголовке запроса и вызовите API 1, в API 1 вы хотите вызвать API 2, затем вам нужно использовать _tokenAcquisition
для генерации с помощью api://client_id2/scope_name_for_API2
для API 2 и вызвать его.
откуда я могу получить значение
scopes
? я обновил свой пост