简体   繁体   中英

.NET Core route based authentication with multiple B2C environments

Situation

We have clients that should be able to login into our application. Our clients do also have clients, who also may login. Therefore we have an Azure AD B2C environment per client.

So, we want to have one single application that can be used to authenticate against multiple Azure B2C environments. We want to have this route-based. So:

/client1 goes to B2C environment Client1B2C, with user flow B2C_1_Client1

/client2 goes to B2C environment Client2B2C, with user flow B2C_1_Client2

Challenge

So, we need to define multiple instances of AddOpenIdConnect. I do this inside a specific builder, so my Startup.cs keeps clean:

Startup.cs

            ...
            var AzureAdB2CSettings = new List<AzureAdB2COptions>();
            Configuration.GetSection("Authentication:AzureAdB2C").Bind(AzureAdB2CSettings, c => c.BindNonPublicProperties = true);

            services.AddAuthentication(sharedOptions =>
            {
                ...
            })
            .AddAzureAdB2C(options => Configuration.Bind("Authentication:AzureAdB2C", options), AzureAdB2CSettings)
            ...

And there is the builder:

AzureAdB2CAuthenticationBuilderExtensions.cs

        ...
        public static string policyToUse;
        
        public static AuthenticationBuilder AddAzureAdB2C(this AuthenticationBuilder builder, Action<AzureAdB2COptions> configureOptions, List<AzureAdB2COptions> openIdOptions)
        {
            ...
            foreach(var b2c in openIdOptions)
            {
                builder.AddOpenIdConnect(b2c.SignUpSignInPolicyId, b2c.SignUpSignInPolicyId, options =>
                {
                    options.Authority = b2c.Authority;
                    options.ClientId = b2c.ClientId;
                    options.CallbackPath = b2c.CallbackPath;
                    options.SignedOutCallbackPath = b2c.SignedOutCallbackPath;
                    options.ClientSecret = b2c.ClientSecret;
                });
            }

            return builder;
        }
        ...

        public Task OnRedirectToIdentityProvider(RedirectContext context)
        {
            ...
            string policyToUse = "B2C_1_" + context.Request.Query["area"];
            ...

            var b2cSettings = AzureAdB2CSettings.Find(x => x.SignUpSignInPolicyId.ToLower().Equals(policyToUse.ToLower()));

            AzureAdB2CAuthenticationBuilderExtensions.policyToUse = b2cSettings.DefaultPolicy;
            ...

Yippee ya yeeey! We can have a dynamic amount of add AddOpenIdConnect, based on a configuration file. The chosen authentication scheme has been set to the static string "AzureAdB2CAuthenticationBuilderExtension.policyToUse".

But now it comes... how to define the Authorization header?

BackofficeController.cs

        ...
        [Authorize(AuthenticationSchemes = AzureAdB2CAuthenticationBuilderExtensions.policyToUse)]
        public async Task<IActionResult> ChooseBackoffice()
        {
            ...
        }
        ...

AUTCH!! You can't use dynamic attributes... Have tried to set the chosen scheme as a default, but it seems we can only define a default at startup, not during runtime...

Any suggestions how to solve this challenge?

One suggestion is to set all possible values of AzureAdB2CAuthenticationBuilderExtensions.policyToUse in config and read from there.

For each action method/controller (as per your use case), define the attribute value from these configs.

It seems indeed impossible at the moment to have multiple B2C environments connected to one Azure App Service.

Therefore there is a choice:

  1. Don't do it. Just create one giant B2C environment.
  2. Make a multi-instance application instead of a multi-tenant application.

Our partner came with another solution. We haven't explored this route. Who knows does this help somebody:

  1. Orchard core. Seems like a multi-tenant .NET Core solution. Looks like a complete application, where this multi-tenant question will be handled.

We did choose option 2. This makes sure we have a good separation of data. There are more hosting costs, although with a multi-tenant application all the traffic does to one application. This does require better hardware, so is also more expensive. I do not know which option is more expensive.

Now comes the question how to deploy this efficiently, but that's another question...

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM