微信公众号搜"智元新知"关注
微信扫一扫可直接关注哦!

AcquireTokenSilentAsync failed_to_acquire_token_silently

如何解决AcquireTokenSilentAsync failed_to_acquire_token_silently

我有一个在 azure 上运行的 .NET MVC Core 3.1 Webapp。此 Web 应用程序使用针对 Azure AD 的 SSO,并在委托模式下使用 powerbi API 和图形 API。

一切正常,但现在我经常在触发 AcquiretokenSilentAsync 时出现 Failed_to_acquire_token_silently 异常。这不是 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,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,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 问题(但完全失败)。

你知道为什么它不时失败吗? 任何其他想法如何解决它?

谢谢!!! 克里斯蒂安

编辑 07/04: 举个例子:

2021-04-07 15:18:24.674 +00:00 OnAuthorizationCodeReceived is triggered for user fd918ddf-fbb9-40d2-812b-b01876118f42
2021-04-07 15:18:31.675 +00:00  AcquiretokenSilentAsync - trigger exception userId 'fd918ddf-fbb9-40d2-812b-b01876118f42'

用户已正确通过 AD 身份验证。收到一个代码,几秒钟后出现 Failed_to_acquire_token_silently 异常。

解决方法

错误 failed_to_acquire_token_silently 在缓存中找不到访问令牌或访问令牌已过期时发生。

代码示例 here

// 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(当应用程序在没有 用户,但以自己的名义)

但是您在代码中使用了 client credentials flow,您可以通过 AcquireTokenAsync 获取访问令牌。

clientCredential = new ClientCredential(clientId,appKey);

AuthenticationContext authenticationContext =
  new AuthenticationContext("https://login.microsoftonline.com/<tenantId>");
   AuthenticationResult result = 
      await authenticationContext.AcquireTokenAsync("https://resourceUrl",clientCredential);

版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 dio@foxmail.com 举报,一经查实,本站将立刻删除。