简体   繁体   中英

Pass query string parameter through OpenId Connect authentication

Let me put the problem with a bit of structure.

Context

We have a web application build with Web Forms and hosted in an Azure Web App that authenticates the users against an Azure Active Directory using the OWIN + OpenId Connect standards.

The authentication process works like a charm and users are able to access the application without any problem.

So, whats the issue?

After struggling for many days with it I'm unable to pass any query string parameter to the application through the authentication process. For example, if I try to access the application for the first time through the URL: https://myapp.azurewebsites.net/Default.aspx?param=value . The reason I need to pass this parameter is that it triggers some specific actions in the main page.

The problem is that after the authentication redirects to the webapp's main page the original query string parameters of the request are gone.

The code

The startup class looks like this:

app.UseOpenIdConnectAuthentication(
                new OpenIdConnectAuthenticationOptions
                {
                    ClientId = Constants.ADTenant.ClientId,
                    Authority = Constants.ADTenant.Authority,
                    PostLogoutRedirectUri = Constants.ADTenant.PostLogoutRedirectUri,

                    Notifications = new OpenIdConnectAuthenticationNotifications
                    {
                        AuthorizationCodeReceived = context =>
                        {
                            var code = context.Code;

                            ClientCredential credential = new ClientCredential(Constants.ADTenant.ClientId,
                                Constants.ADTenant.AppKey);
                            string userObjectID = context.AuthenticationTicket.Identity.FindFirst(
                                Constants.ADTenant.ObjectIdClaimType).Value;
                            AuthenticationContext authContext = new AuthenticationContext(Constants.ADTenant.Authority,
                                new NaiveSessionCache(userObjectID));
                            if (HttpContext.Current != null)
                            {
                                AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                                    code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential,
                                    Constants.ADTenant.GraphResourceId);
                                AuthenticationHelper.token = result.AccessToken;
                                AuthenticationHelper.refreshToken = result.RefreshToken;
                            }
                            return Task.FromResult(0);
                        }
                    }
                });

And it works properly!

What I already tried

I've got access to the original request Url by adding an overwrite of the RedirectToIdentityProvider notification:

RedirectToIdentityProvider = (context) =>
                        {
                            // Ensure the URI is picked up dynamically from the request;
                            string appBaseUrl = context.Request.Scheme + "://" + context.Request.Host + context.Request.PathBase + context.Request.Uri.PathAndQuery;
                            context.ProtocolMessage.RedirectUri = appBaseUrl;
                            return Task.FromResult(0);
                        }

With this I tried to force the redirect to the main page including the original query string parameter, but then the redirection after authentication breaks and gets stuck in an infinite loop.

I've also tried with changing the redirect url of the application configuration in Azure AD without luck. Also tried to store the query string parameters somewhere else, but the Session is not accessible that early in the process.

Does anyone know what am I doing wrong? Or I'm just asking for something impossible? Any help would be appreciated.

Thank you very much in advance!

I recently had a need to do the exact same thing. My solution may not be the most sophisticated, but simple isn't always bad either.

I have two Authentication Filters...

  1. The first filter is applied to all controllers that could potentially be hit with query string parameters prior to authorization. It checks if the principal is authenticated. If false it caches the complete url string in a cookie. If true it looks for any cookies present and clears them, just for cleanup.
public class AuthCheckActionFilter : ActionFilterAttribute, IAuthenticationFilter
    {
        public void OnAuthentication(AuthenticationContext filterContext)
        {
            if (!filterContext.Principal.Identity.IsAuthenticated)
            {

                HttpCookie cookie = new HttpCookie("OnAuthenticateAction");
                cookie.Value = filterContext.HttpContext.Request.Url.OriginalString;
                filterContext.HttpContext.Response.Cookies.Add(cookie);

            }
            else
            {
                if (filterContext.HttpContext.Request.Cookies.AllKeys.Contains("OnAuthenticateAction"))
                {
                    HttpCookie cookie = filterContext.HttpContext.Request.Cookies["OnAuthenticateAction"];
                    cookie.Expires = DateTime.Now.AddDays(-1);
                    filterContext.HttpContext.Response.Cookies.Add(cookie);
                }
            }
        }

        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {

        }

    }
  1. The second filter is applied only to the default landing page, or in other words where the identity server is redirecting after login. This second filter looks for a cookie and if it exists it calls response.Redirect on cookie value.
public class AutoRedirectFilter : ActionFilterAttribute, IAuthenticationFilter
    {

        public void OnAuthentication(AuthenticationContext filterContext)
        {
            if(filterContext.Principal.Identity.IsAuthenticated)
            {       
                if(filterContext.HttpContext.Request.Cookies.AllKeys.Contains("OnAuthenticateAction"))
                {
                    HttpCookie cookie = filterContext.HttpContext.Request.Cookies["OnAuthenticateAction"];
                    filterContext.HttpContext.Response.Redirect(cookie.Value);
                }
            }
        }

        public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext)
        {
        }

    }

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