简体   繁体   中英

Configure redirect URI in Asp.NET Core Azure AD authentication

How can I tell my app to generate redirect URI with host that I provide? ( foobar.com )

Context:

I have Server-Side Blazor Web App, generated from from recent (VS 16.7.5) template, with Azure AD (Single tenant, Work and Schools) authentication.

I use <PackageReference Include="Microsoft.AspNetCore.Authentication.AzureAD.UI" Version="3.1.8" />

I've configured accepted redirected URLs at Az Portal and etc. and I'm able to log in with Azure AD while running my app localy.

流动

The redirect URI is sent in query params while being redirected to Azure AD site and it points to website host which is actualy foobar.azurewebsites.net .

How can I tell my app to generate redirect URI with host that I provide? ( foobar.com )

The only solution I've found is relevant for former ASP.NET.

<add key="ida:RedirectUri" value="https://localhost:44326/" />

Which does not work for in my case.

As a workaround I added a middleware that replaces redirect_uri param in callback URL sent to Azure AD.

public class ResponseInspectMiddleware
{
    private readonly RequestDelegate _next;
    private readonly AzureADSettings _azureAdSettings;

    public ResponseInspectMiddleware(RequestDelegate next, AzureADSettings azureAdSettings)
    {
        _next = next;
        _azureAdSettings = azureAdSettings;
    }

    public async Task Invoke(HttpContext context)
    {
        await _next(context);

        var headers = context.Response.Headers;
        const string LOCATION_HEADER = "location", REDIRECT_URI_PARAM = "redirect_uri";

        if (context.Response.StatusCode == 302
            && headers.ContainsKey(LOCATION_HEADER)
            && Uri.TryCreate(headers[HeaderNames.Location], UriKind.RelativeOrAbsolute, out var locationHeader))
        {
            Url locationUrl = locationHeader;

            if (locationUrl.ToString().StartsWith(_azureAdSettings.Instance)
                && locationUrl.QueryParams.ContainsKey(REDIRECT_URI_PARAM))
            {
                // Update redirect_url query param

                // Make new redirect url
                var callbackHost = _azureAdSettings?.CallbackHost ?? throw new ArgumentNullException($"{_azureAdSettings.CallbackHost} is not set.");
                var callbackPath = _azureAdSettings?.CallbackPath ?? throw new ArgumentNullException($"{_azureAdSettings.CallbackPath} is not set.");
                Url newRedirectUrl = callbackHost + callbackPath;

                locationUrl.SetQueryParam(REDIRECT_URI_PARAM, newRedirectUrl, isEncoded: false);

                // Swap location headers
                headers.Remove(LOCATION_HEADER);
                headers.Add(LOCATION_HEADER, new StringValues(locationUrl.ToString()));
            }
        }
    }
}

When the Web App sits behind Azure Front Door or an App Gateway, we need to configure the redirect_uri in the /authorize request to be the the Gateway/Front Door's address.

In the code below we override the "OnRedirectToIdentityProvider" event and inject the Front Door/Gateway's address. When I was trying this out I simply hardcoded the address but ideally you'd extract it from the headers that Front Door or App Gateway inject into the request.

This is the code I used when trying to authenticate my Blazor Server App (.net 5) running on an Azure App Service, Protected by Azure AD, running behind Azure Front Door.

public void ConfigureServices(IServiceCollection services)
{
    // ... existing code

    services.AddAuthentication(OpenIdConnectDefaults.AuthenticationScheme)
                .AddMicrosoftIdentityWebApp(Configuration.GetSection("AzureAd"))
                .EnableTokenAcquisitionToCallDownstreamApi(new[] { "User.Read" })
                .AddInMemoryTokenCaches();

    services.Configure<OpenIdConnectOptions>(OpenIdConnectDefaults.AuthenticationScheme, options =>
    {
        options.Events = new OpenIdConnectEvents
        {
            OnRedirectToIdentityProvider = (context) =>
            {   
                // Override the redirect_uri
                //  Ideally extract this from config 
                //  Or context.Request.Headers["X-Forwarded-Host"]
                //  see: https://docs.microsoft.com/en-us/azure/frontdoor/front-door-http-headers-protocol#front-door-to-backend

                context.ProtocolMessage.RedirectUri 
                    = "https://YOUR-FRONT-DOOR-or-APP-GATEWAY/signin-oidc";
                return Task.FromResult(0);
            }
        };
    });

    services.Configure<ForwardedHeadersOptions>(options =>
    {
        options.ForwardedHeaders = ForwardedHeaders.XForwardedFor |
                        ForwardedHeaders.XForwardedProto;
        options.KnownNetworks.Clear();
        options.KnownProxies.Clear();
    });

    // ... existing code
}

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
{
    // ... existing code
    
    // Don't forget to add this ...
    app.UseForwardedHeaders();
    
    // ... existing code
}

When the code works, the "redirect_uri" param should point to your Front Door/Gateway as shown here.

OAuth 流程

Hope that helped. ❤️

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