You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

ASP.NET Core MVC中如何处理AdalClaimChallengeException?

解决MVC应用中ADAL的AdalClaimChallengeException(AADSTS50079)问题

你遇到的这个问题是因为用户触发了Azure AD的条件访问策略(需要MFA),但当前的令牌请求没有提供满足策略所需的声明挑战。下面是在MVC应用中处理这个异常的正确流程:

核心问题分析

你当前代码里的误区是在OnAuthenticationFailed中使用了**应用权限流(Client Credentials)**来获取令牌,这是不对的——因为MFA是需要用户亲自完成的交互操作,必须重新引导用户到Azure AD的授权页面,带上声明挑战参数,让用户完成MFA验证后再获取符合要求的令牌。

正确的处理步骤

当捕获到AdalClaimChallengeException时,你需要:

  1. 从异常中提取声明挑战信息
  2. 构建包含声明挑战的授权请求URL,重定向用户到该URL完成MFA
  3. 用户完成验证后,会回调到你的应用,后续流程和正常授权一致(在OnAuthorizationCodeReceived中处理授权码)

修改后的代码实现

services.AddOpenIdConnect(opts => {
    Configuration.GetSection("Authentication").Bind(opts);
    opts.ClientSecret = aadClientSecret.Value;
    opts.Events = new OpenIdConnectEvents {
        OnAuthorizationCodeReceived = async ctx => {
            HttpRequest request = ctx.HttpContext.Request;
            string currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
            var credential = new ClientCredential(ctx.Options.ClientId, ctx.Options.ClientSecret);
            
            ITokenCacheFactory cacheFactory = ctx.HttpContext.RequestServices.GetRequiredService<ITokenCacheFactory>();
            TokenCache cache = cacheFactory.CreateForUser(ctx.Principal);
            var authContext = new AuthenticationContext(ctx.Options.Authority, cache);
            
            string resource = "https://graph.microsoft.com";
            AuthenticationResult result = await authContext.AcquireTokenByAuthorizationCodeAsync(
                ctx.ProtocolMessage.Code, new Uri(currentUri), credential, resource);
            
            ctx.HandleCodeRedemption(result.AccessToken, result.IdToken);
        },
        OnAuthenticationFailed = async ctx => {
            var adalException = ctx.Exception as AdalClaimChallengeException;
            if (adalException != null) {
                // 1. 提取并编码声明挑战(需要转义为URL安全格式)
                string claimsChallenge = JsonConvert.SerializeObject(adalException.Claims);
                string encodedClaims = Uri.EscapeDataString(claimsChallenge);
                
                HttpRequest request = ctx.HttpContext.Request;
                string currentUri = UriHelper.BuildAbsolute(request.Scheme, request.Host, request.PathBase, request.Path);
                
                // 2. 构建授权请求URL,包含声明挑战参数
                var authorizationRequest = new UriBuilder($"{ctx.Options.Authority}/oauth2/authorize")
                {
                    Query = string.Join("&", new[]
                    {
                        $"client_id={ctx.Options.ClientId}",
                        $"redirect_uri={Uri.EscapeDataString(currentUri)}",
                        $"response_type=code",
                        $"scope={Uri.EscapeDataString(ctx.Options.Scope.Aggregate((a,b) => $"{a} {b}"))}",
                        $"state={ctx.ProtocolMessage.State}",
                        $"claims={encodedClaims}"
                    })
                };
                
                // 3. 重定向用户到Azure AD授权页面完成MFA
                ctx.Response.Redirect(authorizationRequest.ToString());
                ctx.HandleResponse(); // 终止当前管道流程
                return;
            }
            
            // 处理其他认证失败情况
            ctx.Response.Redirect("/Home/Error");
            ctx.HandleResponse();
        }
    };
});

关键细节说明

  • 声明挑战的编码:必须将claims对象序列化为JSON后进行URL编码,确保能安全传递到Azure AD。
  • 状态参数保留:ctx.ProtocolMessage.State是OIDC中间件生成的状态值,必须包含在新的授权请求中,这样回调时中间件能验证请求的合法性。
  • 重定向URI一致性:确保redirect_uri和你在Azure AD应用注册中配置的回调地址完全一致。
  • 终止当前流程:调用ctx.HandleResponse()告诉中间件不要再处理后续的认证逻辑,直接执行重定向。

当用户完成MFA后,Azure AD会将新的授权码回调到你的应用,OnAuthorizationCodeReceived事件会再次触发,此时获取的令牌就会满足条件访问策略的要求,不会再抛出AdalClaimChallengeException。

内容的提问来源于stack exchange,提问作者Dylan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.29 08:09:21