AcquireTokenByAuthorizationCode 使用 ASP.NET MVC 使用 Azure Active Directory 在单租户应用程序中抛出新异常

AcquireTokenByAuthorizationCode throw new exception in single tenant application using ASP.NET MVC using Azure Active Directory

我尝试了 this tutorial 因为我想使用 Microsoft Graph API 在 Microsoft Teams 中创建庞大的团队。 与本教程的唯一区别是我在 Azure AD 管理中心的身份验证部分使用了下一个选项:

"Accounts in this organizational directory only (myuniversity only - Single tenant)"

因此,我更改了我的代码以对单个租户使用端点

public void ConfigureAuth(IAppBuilder app)
{
    app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

    app.UseCookieAuthentication(new CookieAuthenticationOptions());

    app.UseOpenIdConnectAuthentication(
        new OpenIdConnectAuthenticationOptions
        {
            
            ClientId = appId,
            //Authority = "https://login.microsoftonline.com/common/v2.0",//
            Authority = "https://login.microsoftonline.com/{tenantid}/v2.0",
            Scope = $"openid email profile offline_access {graphScopes}",
            RedirectUri = redirectUri,
            PostLogoutRedirectUri = redirectUri,
            TokenValidationParameters = new TokenValidationParameters
            {
                // For demo purposes only, see below
                ValidateIssuer = false

                // In a real multi-tenant app, you would add logic to determine whether the
                // issuer was from an authorized tenant
                //ValidateIssuer = true,
                //IssuerValidator = (issuer, token, tvp) =>
                //{
                //  if (MyCustomTenantValidation(issuer))
                //  {
                //    return issuer;
                //  }
                //  else
                //  {
                //    throw new SecurityTokenInvalidIssuerException("Invalid issuer");
                //  }
                //}
            },
            Notifications = new OpenIdConnectAuthenticationNotifications
            {
                AuthenticationFailed = OnAuthenticationFailedAsync,
                AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
            }
        }
    );
}

用户身份验证后,代码我 运行 OnAuthorizationCodeReceivedAsync 方法但在 AcquireTokenByAuthorizationCode 方法

中出现异常

方法在这里

private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
{
    var idClient = ConfidentialClientApplicationBuilder.Create(appId)
        .WithRedirectUri(redirectUri)
        .WithClientSecret(appSecret)
        .Build();
    var accounts = await idClient.GetAccountsAsync();
    string message;
    string debug;

    try
    {
        string[] scopes = graphScopes.Split(' ');

        var result = await idClient.AcquireTokenByAuthorizationCode(scopes, notification.Code).ExecuteAsync();

        message = "Access token retrieved.";
        debug = result.AccessToken;
    }
    catch (MsalException ex)
    {
        message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
        debug = ex.Message;
    }

    var queryString = $"message={message}&debug={debug}";
    if (queryString.Length > 2048)
    {
        queryString = queryString.Substring(0, 2040) + "...";
    }

    notification.HandleResponse();
    notification.Response.Redirect($"/Home/Error?{queryString}");
}

例外情况是:

AcquireTokenByAuthorizationCodeAsync threw an exception

AADSTS50194: Application 'application id'(ASP.NET Graph Tutorial) is not configured as a multi-tenant application. Usage of the /common endpoint is not supported for such applications created after '10/15/2018'. Use a tenant-specific endpoint or configure the application to be multi-tenant. Trace ID: 5f0fbf2e-5d63-40d4-a833-ca8627a02d00

Correlation ID: 3ec4ec7b-0c86-4e2b-a053-9823f977499d Timestamp: 2021-02-16 20:21:03Z

我只想对我的组织使用单租户身份验证

如果你想通过MSAL.NET要求一个特定租户的AD令牌,你可以通过提及特定的权限来告诉SDK从哪个租户获取令牌。详情请参考here.

例如

 private static string appId = ConfigurationManager.AppSettings["ida:AppId"];
        private static string appSecret = ConfigurationManager.AppSettings["ida:AppSecret"];
        private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];
        private static string graphScopes = ConfigurationManager.AppSettings["ida:AppScopes"];
        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);

            app.UseCookieAuthentication(new CookieAuthenticationOptions());

            app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = appId,
                    Authority = "https://login.microsoftonline.com/<your tenant id>/v2.0",
                    Scope = $"openid email profile offline_access {graphScopes}",
                    RedirectUri = redirectUri,
                    PostLogoutRedirectUri = redirectUri,
                    TokenValidationParameters = new TokenValidationParameters
                    {
                        // For demo purposes only, see below
                        ValidateIssuer = false

                        // In a real multi-tenant app, you would add logic to determine whether the
                        // issuer was from an authorized tenant
                        //ValidateIssuer = true,
                        //IssuerValidator = (issuer, token, tvp) =>
                        //{
                        //  if (MyCustomTenantValidation(issuer))
                        //  {
                        //    return issuer;
                        //  }
                        //  else
                        //  {
                        //    throw new SecurityTokenInvalidIssuerException("Invalid issuer");
                        //  }
                        //}
                    },
                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthenticationFailed = OnAuthenticationFailedAsync,
                        AuthorizationCodeReceived = OnAuthorizationCodeReceivedAsync
                    }
                }
            );
        }

        private async Task OnAuthorizationCodeReceivedAsync(AuthorizationCodeReceivedNotification notification)
        {
            var idClient = ConfidentialClientApplicationBuilder.Create(appId)
                 .WithRedirectUri(redirectUri)
                 .WithClientSecret(appSecret)
                 .WithAuthority("https://login.microsoftonline.com/<your tenant id>")
                 .Build();

            string message;
            string debug;

            try
            {
                string[] scopes = graphScopes.Split(' ');

                var result = await idClient.AcquireTokenByAuthorizationCode(
                    scopes, notification.Code).ExecuteAsync();

                message = "Access token retrieved.";
                debug = result.AccessToken;
            }
            catch (MsalException ex)
            {
                message = "AcquireTokenByAuthorizationCodeAsync threw an exception";
                debug = ex.Message;
            }

            var queryString = $"message={message}&debug={debug}";
            if (queryString.Length > 2048)
            {
                queryString = queryString.Substring(0, 2040) + "...";
            }

            notification.HandleResponse();
            notification.Response.Redirect($"/Home/Error?{queryString}");
        }

        private Task OnAuthenticationFailedAsync(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
        {
            notification.HandleResponse();
            string redirect = $"/Home/Error?message={notification.Exception.Message}";
            if (notification.ProtocolMessage != null && !string.IsNullOrEmpty(notification.ProtocolMessage.ErrorDescription))
            {
                redirect += $"&debug={notification.ProtocolMessage.ErrorDescription}";
            }
            notification.Response.Redirect(redirect);
            return Task.FromResult(0);
        }