Как получить токен доступа для тестирования интеграции с внешним API - PullRequest
0 голосов
/ 26 февраля 2019

Для интеграционного теста У меня есть авторизованный контроллер .NET Core 2.2, который вызывает другой авторизованный контроллер (другой проект) или внешний API (например, Microsoft Graph).

Оба apis проходят проверку подлинности на Azure AD.Во всех действиях контроллера нам нужен аутентифицированный пользователь.Мы можем войти в первый API, получив токен на основе имени пользователя и пароля (grant_type = password).Когда вызов продолжается до второго API, он прерывается из-за интерактивного приглашения к входу в систему (мы используем ADAL).

Обычно пользователь аутентифицируется с помощью открытого идентификатора соединения, затем мы получаем код аутентификации и получаем токен доступа + токен обновления с кодом аутентификации.С помощью токена обновления мы можем получить токен доступа для второго API.

Мы создали небольшой пример проекта с контроллерами значений по умолчанию, чтобы объяснить нашу проблему.

Получить токен доступа перед вызовом первого APIс собственной регистрацией приложения:

public static async Task<string> AcquireTokenAsync(string username, string password)
{
    var aadInstance = "https://login.windows.net/{0}";
    var tenantId = "put id here";

    var authority = string.Format(aadInstance, tenantId);
    var clientId = "clientid here";
    var resource = "put resource here";

    var client = new HttpClient();
    var tokenEndpoint = $"https://login.microsoftonline.com/{tenantId}/oauth2/token";
    var body = $"resource={resource}&client_id={clientId}&grant_type=password&username={username}&password={password}";
    var stringContent = new StringContent(body, Encoding.UTF8, "application/x-www-form-urlencoded");

    var result = await client.PostAsync(tokenEndpoint, stringContent).ContinueWith((response) =>
    {
        return response.Result.Content.ReadAsStringAsync().Result;
    });

    JObject jobject = JObject.Parse(result);
    var token = jobject["access_token"].Value<string>();

    return token;
}

Первый API:

[Authorize]
[HttpGet]
public async Task<IActionResult> Get()
{
    string name = User.Identity.Name;

    var result = await AcquireTokenSilentWithImpersonationAsync();

    string BaseUrl = "https://localhost:44356/";


    var client = new HttpClient
    {
        BaseAddress = new Uri(BaseUrl)
    };
    client.DefaultRequestHeaders.Accept.Clear();
    client.DefaultRequestHeaders.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", result.AccessToken);

    var url = "api/values";

    HttpResponseMessage response = await client.GetAsync(url);

    switch (response.StatusCode)
    {
        case HttpStatusCode.OK:

            int x = 1;

            break;
        default:
            throw new HttpRequestException($"Error - {response.StatusCode} in response with message '{response.RequestMessage}'");
    }


    return Ok();
}
private const string BackendResource = "Second api resource here";

/// <summary>
/// For more information: https://docs.microsoft.com/en-us/azure/active-directory/develop/active-directory-devhowto-adal-error-handling
/// </summary>
/// <returns></returns>
public async Task<AuthenticationResult> AcquireTokenSilentWithImpersonationAsync()
{
    const string ClientId = "client id of first api here";
    const string ClientSecret = "secret of first api here";
    ClientCredential credential = new ClientCredential(ClientId, ClientSecret);
    string userObjectId = _httpContextAccessor.HttpContext.User.FindFirst("http://schemas.microsoft.com/identity/claims/objectidentifier")?.Value;

    var authContext = GetAuthenticationContext(userObjectId);
    AuthenticationResult authResult = null;

    try
    {
        authResult = await authContext.AcquireTokenSilentAsync(BackendResource, credential, new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));
    }
    catch (AdalSilentTokenAcquisitionException ex)
    {
        // Exception: AdalSilentTokenAcquisitionException
        // Caused when there are no tokens in the cache or a required refresh failed. 

        // Action: Case 1, resolvable with an interactive request. 

        try
        {
            authResult = await authContext.AcquireTokenAsync(BackendResource, ClientId, new Uri("https://backurl.org"), new PlatformParameters(), new UserIdentifier(userObjectId, UserIdentifierType.UniqueId));
        }
        catch (Exception exs)
        {

            throw;
        }
    }
    catch (AdalException e)
    {
        // Exception: AdalException 
        // Represents a library exception generated by ADAL .NET. 
        // e.ErrorCode contains the error code. 

        // Action: Case 2, not resolvable with an interactive request.
        // Attempt retry after a timed interval or user action.
        // Example Error: network_not_available, default case.
        throw;
    }

    return authResult;
}

Второй API:

[Authorize]
[HttpGet]
public ActionResult<IEnumerable<string>> Get()
{
    string name = User.Identity.Name;

    return new string[] { "value1", "value2" };
}

1 Ответ

0 голосов
/ 06 марта 2019

Вам необходимо использовать поток «от имени» в своем веб-API (не нужно интерактивное получение токена). Если вы хотите использовать ADAL.NET, образец есть: https://github.com/azure-samples/active-directory-dotnet-webapi-onbehalfof

но я бы сейчас порекомендовал вам использовать MSAL.NET.Пример: active-directory-dotnet-native-aspnetcore-v2 / 2.Веб-API теперь вызывает Microsoft Graph и документацию: https://aka.ms/msal-net-on-behalf-of

Также обратите внимание, что для веб-API мы не используем OIDC (это для входа в систему пользователей), а JWTпромежуточное ПО на предъявителя

...