Forms authentication + ASP.NET MVC absolute Return

2019-01-21 12:28发布

问题:

I have a central authentication application on server a. Server b has one or more applications on the same domain that need to authenticate from server a. It's easy enough to set it up so that the server b apps redirect out to server a. What's not so easy is getting the ReturnURL to be absolute.

Here's the wrinkle. Consuming app on server b has two controllers, one public and one secured. If the [authorize] decoration is placed on an action in the public (which is the default controller), I get the proper absolute URL. However, if its in it's own controller I get a relative URL.

I can intercept the on pre-request event in the consuming applications, but I need some parts of the site to be public, not the whole smash.

Ideas?

回答1:

The way the standard AuthorizeAttribute works is by setting the response status code to 401 if the request is not authenticated. This kicks in the default authentication module's standard response to an unauthorized request. I assume that you're using forms-based authentication, which would build the return url based on the url in the request. In this case, probably a relative URL.

One thing you could do is instead of relying on the built-in behavior, you could implement a SSOAuthorizeAttribute which extends the AuthorizeAttribute class and overrides OnAuthorization. You could then extract the loginUrl from the forms element in the web configuration and build your own RedirectResult and pull the returnUrl from the HttpContext.Request.Url.AbsoluteUri property in the AuthorizationContext parameter.

 public class SSOAuthorizeAttribute : AuthorizeAttribute
 {
      public override void OnAuthorization( 
                          AuthorizationContext filterContext )
      {
          if (filterContext == null)
          {
              throw new ArgumentNullException( "filterContext" );
          }

          if (!filterContext.HttpContext.User.Identity.IsAuthenticated)
          {
              // get from cached variable from web configuration
              string loginUrl = ... 
              if (filterContext.HttpContext.Request != null)
              {
                  loginUrl += "?ReturnUrl=" + filterContext.HttpContext
                                                           .Request
                                                           .Url
                                                           .AbsoluteUri;
              }

              filterContext.Result = new RedirectResult( loginUrl );
          }
      }
 }


回答2:

Assuming forms authentication, in the server B apps web.config, set the loginUrl attribute on the forms tag to a Controller Action method that tacks on the absolute url before redirecting to server A.

Config on server B

<authentication mode="Forms">
  <forms loginUrl="/Account/LoginRedirect" />
</authentication>

The action method would look like

 public RedirectResult LoginRedirect(string returnUrl)
    {
       var requestUrl = HttpContext.Current.Request.Url;
       return LoginUrlOnServerA + 
              "?returnUrl=" +          
              HttpUtility.UrlEncode(string.Format("http://{0}:{1}{2}",
                requestUrl.Host,
                requestUrl.Port,
                HttpUtility.UrlDecode(returnUrl)));
     }


回答3:

as https://stackoverflow.com/a/583608/80589 but shorter:

public RedirectResult LogOn(string returnUrl)
{
  var r = new Uri(Request.Url, returnUrl).ToString();
  return Redirect("https://logonserver.com/?return_url=" + Url.Encode(r));
}