Azure B2C 拒绝="?"在 asp.net 个 MVC 中

Azure B2C deny="?" in asp.net MVC

我有一个 MVC 应用程序,我正在尝试向 Azure AD B2C 进行身份验证。我想使用 deny="?"我的 web.config 中的属性。一切都很好,直到我在身份验证后被重定向回我的应用程序,在这种情况下 asp.net 没有看到我的用户已获得授权并且我被发送回 B2C 登录页面,这导致无限循环.

Startup.Auth.cs

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

// The following using statements were added for this sample
using Owin;
using Microsoft.Owin.Security;
using Microsoft.Owin.Security.Cookies;
using Microsoft.Owin.Security.OpenIdConnect;
using System.Threading.Tasks;
using Microsoft.Owin.Security.Notifications;
using Microsoft.IdentityModel.Protocols;
using System.Web.Mvc;
using System.Configuration;
using System.IdentityModel.Tokens;
using WebApp_OpenIDConnect_DotNet_B2C.Policies;
using System.Threading;
using System.Globalization;
using Microsoft.Owin;

namespace WebApp_OpenIDConnect_DotNet_B2C
{
    public partial class Startup
    {
        // The ACR claim is used to indicate which policy was executed
        public const string AcrClaimType = "http://schemas.microsoft.com/claims/authnclassreference";
        public const string PolicyKey = "b2cpolicy";
        public const string OIDCMetadataSuffix = "/.well-known/openid-configuration";

        // App config settings
        private static string clientId = ConfigurationManager.AppSettings["ida:ClientId"];
        private static string aadInstance = ConfigurationManager.AppSettings["ida:AadInstance"];
        private static string tenant = ConfigurationManager.AppSettings["ida:Tenant"];
        private static string redirectUri = ConfigurationManager.AppSettings["ida:RedirectUri"];

        // B2C policy identifiers
        public static string SignUpPolicyId = ConfigurationManager.AppSettings["ida:SignUpPolicyId"];
        public static string SignInPolicyId = ConfigurationManager.AppSettings["ida:SignInPolicyId"];
        public static string ProfilePolicyId = ConfigurationManager.AppSettings["ida:UserProfilePolicyId"];

        public void ConfigureAuth(IAppBuilder app)
        {
            app.SetDefaultSignInAsAuthenticationType(CookieAuthenticationDefaults.AuthenticationType);
            System.Web.Mvc.UrlHelper url = new System.Web.Mvc.UrlHelper(HttpContext.Current.Request.RequestContext);

            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                LoginPath = new PathString(url.Action("SignIn", "Account"))
            });

            OpenIdConnectAuthenticationOptions options = new OpenIdConnectAuthenticationOptions
            {
                // These are standard OpenID Connect parameters, with values pulled from web.config
                ClientId = clientId,
                RedirectUri = redirectUri,
                PostLogoutRedirectUri = redirectUri,
                Notifications = new OpenIdConnectAuthenticationNotifications
                { 
                    AuthenticationFailed = AuthenticationFailed,
                    RedirectToIdentityProvider = OnRedirectToIdentityProvider,
                },
                Scope = "openid",
                ResponseType = "id_token",

                // The PolicyConfigurationManager takes care of getting the correct Azure AD authentication
                // endpoints from the OpenID Connect metadata endpoint.  It is included in the PolicyAuthHelpers folder.
                ConfigurationManager = new PolicyConfigurationManager(
                    String.Format(CultureInfo.InvariantCulture, aadInstance, tenant, "/v2.0", OIDCMetadataSuffix),
                    new string[] { SignUpPolicyId, SignInPolicyId, ProfilePolicyId }),

                // This piece is optional - it is used for displaying the user's name in the navigation bar.
                TokenValidationParameters = new TokenValidationParameters
                {  
                    NameClaimType = "name",
                },
            };

            app.UseOpenIdConnectAuthentication(options);

        }

        // This notification can be used to manipulate the OIDC request before it is sent.  Here we use it to send the correct policy.
        private async Task OnRedirectToIdentityProvider(RedirectToIdentityProviderNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
        {
            PolicyConfigurationManager mgr = notification.Options.ConfigurationManager as PolicyConfigurationManager;
            if (notification.ProtocolMessage.RequestType == OpenIdConnectRequestType.LogoutRequest)
            {
                OpenIdConnectConfiguration config = await mgr.GetConfigurationByPolicyAsync(CancellationToken.None, notification.OwinContext.Authentication.AuthenticationResponseRevoke.Properties.Dictionary[Startup.PolicyKey]);
                notification.ProtocolMessage.IssuerAddress = config.EndSessionEndpoint;
            }
            else
            {
                OpenIdConnectConfiguration config = await mgr.GetConfigurationByPolicyAsync(CancellationToken.None, notification.OwinContext.Authentication.AuthenticationResponseChallenge.Properties.Dictionary[Startup.PolicyKey]);
                notification.ProtocolMessage.IssuerAddress = config.AuthorizationEndpoint;
            }
        }

        // Used for avoiding yellow-screen-of-death
        private Task AuthenticationFailed(AuthenticationFailedNotification<OpenIdConnectMessage, OpenIdConnectAuthenticationOptions> notification)
        {
            notification.HandleResponse();
            notification.Response.Redirect("/Home/Error?message=" + notification.Exception.Message);
            return Task.FromResult(0);
        }
    }
}

web.config

  <?xml version="1.0" encoding="utf-8"?>
  <!--
    For more information on how to configure your ASP.NET application, please visit
    http://go.microsoft.com/fwlink/?LinkId=301880
    -->
  <configuration>
    <appSettings>
      <add key="webpages:Version" value="3.0.0.0" />
      <add key="webpages:Enabled" value="false" />
      <add key="ClientValidationEnabled" value="true" />
      <add key="UnobtrusiveJavaScriptEnabled" value="true" />
      <add key="ida:Tenant" value="xxxx.onmicrosoft.com" />
      <add key="ida:ClientId" value="Myguid" />
      <add key="ida:AadInstance" value="https://login.microsoftonline.com/{0}{1}{2}" />
      <add key="ida:RedirectUri" value="https://localhost:44316/" />
      <add key="ida:SignUpPolicyId" value="B2C_1_JHA.SignUp" />
      <add key="ida:SignInPolicyId" value="B2C_1_JHA.SignIn" />
      <add key="ida:UserProfilePolicyId" value="B2C_1_JHA.Profile" />
    </appSettings>
    <location path="account/signin">
      <system.web>
        <authorization>
          <allow users="*" />
        </authorization>
      </system.web>
    </location>
    <system.web>
      <authorization>
        <deny users="?" />
      </authorization>
      <compilation debug="true" targetFramework="4.5" />
      <httpRuntime targetFramework="4.5" />
    </system.web>
    <runtime>
      <assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
        <dependentAssembly>
          <assemblyIdentity name="System.Web.Optimization" publicKeyToken="31bf3856ad364e35" />
          <bindingRedirect oldVersion="1.0.0.0-1.1.0.0" newVersion="1.1.0.0" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="WebGrease" publicKeyToken="31bf3856ad364e35" />
          <bindingRedirect oldVersion="0.0.0.0-1.6.5135.21930" newVersion="1.6.5135.21930" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="System.IdentityModel.Tokens.Jwt" publicKeyToken="31bf3856ad364e35" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-4.0.20622.1351" newVersion="4.0.20622.1351" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="Microsoft.IdentityModel.Protocol.Extensions" publicKeyToken="31bf3856ad364e35" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-1.0.2.33" newVersion="1.0.2.33" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-7.0.0.0" newVersion="7.0.0.0" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="Antlr3.Runtime" publicKeyToken="eb42632606e9261f" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-3.5.0.2" newVersion="3.5.0.2" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="System.Web.Helpers" publicKeyToken="31bf3856ad364e35" />
          <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="System.Web.WebPages" publicKeyToken="31bf3856ad364e35" />
          <bindingRedirect oldVersion="1.0.0.0-3.0.0.0" newVersion="3.0.0.0" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="System.Web.Mvc" publicKeyToken="31bf3856ad364e35" />
          <bindingRedirect oldVersion="1.0.0.0-5.2.3.0" newVersion="5.2.3.0" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="Microsoft.Owin" publicKeyToken="31bf3856ad364e35" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="Microsoft.Owin.Security" publicKeyToken="31bf3856ad364e35" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
        </dependentAssembly>
        <dependentAssembly>
          <assemblyIdentity name="Microsoft.Owin.Security.Cookies" publicKeyToken="31bf3856ad364e35" culture="neutral" />
          <bindingRedirect oldVersion="0.0.0.0-3.0.1.0" newVersion="3.0.1.0" />
        </dependentAssembly>
      </assemblyBinding>
    </runtime>
  </configuration>

出现此问题的原因:

对于DotNet的OpenIDConnect,认证和重定向是同时进行的。在您的情况下,身份验证总是比重定向慢。并且,您的应用程序中的重定向 URI 是“https://localhost:44316/”,这需要再次进行身份验证,因为 Request.IsAuthenticated 尚未设置为 true。新的认证将覆盖旧的认证;因此它只是不断地循环。

解决方法很简单。将您的重定向 URI 更改为不需要身份验证的页面。例如:

<configuration>
<appSettings>
  <add key="webpages:Version" value="3.0.0.0" />
  <add key="webpages:Enabled" value="false" />
  <add key="ClientValidationEnabled" value="true" />
  <add key="UnobtrusiveJavaScriptEnabled" value="true" />
  <add key="ida:Tenant" value="xxxx.onmicrosoft.com" />
  <add key="ida:ClientId" value="Myguid" />
  <add key="ida:AadInstance" value="https://login.microsoftonline.com/{0}{1}{2}" />
  <add key="ida:RedirectUri" value="https://localhost:44316/Home/loginsuccess" />
  <add key="ida:SignUpPolicyId" value="B2C_1_JHA.SignUp" />
  <add key="ida:SignInPolicyId" value="B2C_1_JHA.SignIn" />
  <add key="ida:UserProfilePolicyId" value="B2C_1_JHA.Profile" />
</appSettings>
<location path="account/signin">
  <system.web>
    <authorization>
      <allow users="*" />
    </authorization>
  </system.web>
</location>
<location path="Home/loginsuccess">
  <system.web>
    <authorization>
      <allow users="*" />
    </authorization>
  </system.web>
</location>
<system.web>
  <authorization>
    <deny users="?" />
  </authorization>
  <compilation debug="true" targetFramework="4.5" />
  <httpRuntime targetFramework="4.5" />
</system.web>

...

注意:这里,https://localhost:44316/Home/loginsuccess 应该是一个向用户显示其身份验证状态的页面。顺便说一句,您应该将此重定向 URI 添加到新门户中的 AD 应用程序中。