AcquireTokenSilentAsync failed_to_acquire_token_silently

У меня есть веб-приложение .NET MVC Core 3.1, работающее на лазурном сервере. Это веб-приложение поддерживает единый вход в Azure AD и использует API Powerbi и API графиков в делегированном режиме.

Все работало нормально, но теперь у меня регулярно возникают исключения failed_to_acquire_token_silently при срабатывании AcquireTokenSilentAsync. Это не в 100% случаев и кажется мне случайным.

Позвольте мне попытаться выделить наиболее важные части кода.

Startup.cs / ConfigureServices:

                  services.AddAuthentication("Azures").AddPolicyScheme("Azures", "Authorize AzureAd or AzureAdBearer", options =>
            {
                options.ForwardDefaultSelector = context =>
                {
....
                };
            })

                 .AddJwtBearer(x =>
                 {
                     .....

                 })
                 // For browser access
                .AddAzureAD(options => Configuration.Bind("AzureAd", options));

Startup.cs / ConfigureTokenHandling:

             private void ConfigureTokenHandling(IServiceCollection services)
        {
            if (Configuration["AuthWithAppSecret:ClientSecret"] != "")
            {
                services.Configure<OpenIdConnectOptions>(AzureADDefaults.OpenIdScheme, options =>
                {
                    options.ResponseType = Configuration["AuthWithAppSecret:ResponseType"];
                    options.ClientSecret = Configuration["AuthWithAppSecret:ClientSecret"];


                    options.Events = new OpenIdConnectEvents
                    {
                        OnAuthorizationCodeReceived = async ctx =>
                        {

                            HttpRequest request = ctx.HttpContext.Request;
                            //We need to also specify the redirect URL used
                            string currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
                            //Credentials for app itself
                            var credential = new ClientCredential(ctx.Options.ClientId, ctx.Options.ClientSecret);

                            //Construct token cache
                            ITokenCacheFactory cacheFactory = ctx.HttpContext.RequestServices.GetRequiredService<ITokenCacheFactory>();
                            TokenCache cache = cacheFactory.CreateForUser(ctx.Principal);

                            var authContext = new AuthenticationContext(ctx.Options.Authority, cache);


                            string resource = Configuration["PowerBI:PowerBiResourceUrl"];
                            AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
                                ctx.ProtocolMessage.Code, new Uri(currentUri), credential, resource);



                            //Tell the OIDC middleware we got the tokens, it doesn't need to do anything
                            ctx.HandleCodeRedemption(result.AccessToken, result.IdToken);
                        }

                    };
                });

            }
        }

Контроллер такой:

          public class ProjectsController : BaseController
    {
        private readonly ITokenCacheFactory _tokenCacheFactory;


        public ProjectsController(MyContext context,  IConfiguration configuration, ITokenCacheFactory tokenCacheFactory)
        {
            _context = context;
            _tokenCacheFactory = tokenCacheFactory;
            _configuration = configuration;

        }

Позже запускается контроллером:

             static public async Task<string> GetAccessTokenAsync2(IConfiguration _configuration, ITokenCacheFactory _tokenCacheFactory, ClaimsPrincipal User, string resURL, Uri redirectURI)
        {

            string authority = _configuration["AzureAd:Authority"];
            string clientId = _configuration["AzureAd:ClientId"];
            string clientSecret = _configuration["AuthWithAppSecret:ClientSecret"];


            var cache = _tokenCacheFactory.CreateForUser(User);
            var authContext = new AuthenticationContext(authority, cache);


            var credential = new ClientCredential(clientId, clientSecret);
            var userId = User.GetObjectId();


            AuthenticationResult result;
            try
            {
                result = await authContext.AcquireTokenSilentAsync(
                    resURL,
                    credential,
                    new UserIdentifier(userId, UserIdentifierType.UniqueId));
            }
            catch (AdalException ex)
            {
                mylog.Info("GetAccessTokenAsync - Adal Ex:" + ex.ErrorCode);

                if (ex.ErrorCode == "failed_to_acquire_token_silently")
                {

                    // There are no tokens in the cache. 
                    try
                    {
                        PlatformParameters param = new PlatformParameters();

                        result = await authContext.AcquireTokenAsync(resURL, clientId, redirectURI, param, new UserIdentifier(userId, UserIdentifierType.UniqueId));
                    }
                    catch (Exception e)
                    {
                        mylog.Error("GetAccessTokenAsync - AcquireTokenAsync" + e.ToString());
                        throw e;
                    }
                    

                }
                else
                    throw ex;
            }



            return result.AccessToken;
        }

AcquireTokenAsync был добавлен, чтобы решить проблему failed_to_acquire_token_silently (но это полностью сбой).

Вы хоть представляете, почему время от времени он дает сбой? Есть еще идеи, как это исправить?

Спасибо!!! Христианин

1 ответ

Ошибка failed_to_acquire_token_silently возникает, когда токен доступа не может быть найден в кеше или токен доступа истек.

Пример кода здесь :

      // STS
string cloud = "https://login.microsoftonline.com";
string tenantId = "331e6716-26e8-4651-b323-2563936b416e";
string authority = $"{cloud}/{tenantId}";

// Application
string clientId = "65b27a1c-693c-44bf-bf92-c49e408ccc70";
Uri redirectUri = new Uri("https://TodoListClient");

// Application ID of the Resource (could also be the Resource URI)
string resource = "eab51d24-076e-44ee-bcf0-c2dce7577a6a";

AuthenticationContext ac = new AuthenticationContext(authority);
AuthenticationResult result=null;
try
{
 result = await ac.AcquireTokenSilentAsync(resource, clientId);
}
catch (AdalException adalException)
{
 if (adalException.ErrorCode == AdalError.FailedToAcquireTokenSilently
     || adalException.ErrorCode == AdalError.InteractionRequired)
  {
   result = await ac.AcquireTokenAsync(resource, clientId, redirectUri,
                                       new PlatformParameters(PromptBehavior.Auto));
  }
}

Обратите внимание, что AcquireTokenSilent не нужно вызывать в потоке учетных данных клиента (когда приложение получает токен без пользователя, но на свое собственное имя)

Но вы используете поток учетных данных клиента в своем коде, вы можете получить токен доступа через AcquireTokenAsync.

      clientCredential = new ClientCredential(clientId, appKey);

AuthenticationContext authenticationContext =
  new AuthenticationContext("https://login.microsoftonline.com/<tenantId>");
   AuthenticationResult result = 
      await authenticationContext.AcquireTokenAsync("https://resourceUrl",
                                                    clientCredential);
Другие вопросы по тегам