Аутентификация форм + ASP.NET MVC абсолютный ReturnURL

У меня есть центральное приложение аутентификации на сервере a. Сервер b имеет одно или несколько приложений в том же домене, которые должны пройти аутентификацию с сервера a. Достаточно легко настроить его так, чтобы сервер b apps перенаправлялся на сервер a. Что не так просто, чтобы получить ReturnURL, чтобы быть абсолютным.

Вот морщина. Употребление приложения на сервере b имеет два контроллера, один открытый и один защищенный. Если [authorize] украшение помещается в действие публично (которое является контроллером по умолчанию), я получаю правильный абсолютный URL. Однако, если в нем есть собственный контроллер, я получаю относительный URL.

Я могу перехватить событие pre-request в приложениях-потребителях, но мне нужно, чтобы некоторые части сайта были общедоступными, а не весь разлом.

Идеи?

Ответ 1

Как работает стандартный AuthorizeAttribute, устанавливается код состояния ответа на 401, если запрос не аутентифицирован. Это приводит к стандартным ответам модуля аутентификации по умолчанию на несанкционированный запрос. Я предполагаю, что вы используете аутентификацию на основе форм, которая будет строить возвращаемый url на основе URL-адреса в запросе. В этом случае, вероятно, относительный URL.

Одна вещь, которую вы можете сделать, - вместо того, чтобы полагаться на встроенное поведение, вы можете реализовать SSOAuthorizeAttribute, который расширяет класс AuthorizeAttribute и переопределяет OnAuthorization. Затем вы можете извлечь loginUrl из элемента forms в веб-конфигурации и создать собственный RedirectResult и вытащить returnUrl из свойства HttpContext.Request.Url.AbsoluteUri в параметре AuthorizationContext.

 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

Предполагая, что для проверки подлинности форм в приложении сервера Web.config сервера B установите атрибут loginUrl в теге формы методу действия контроллера, который привязывается к абсолютному URL-адресу перед перенаправлением на сервер А.

Конфигурация на сервере B

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

Метод действия будет выглядеть как

 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

как fooobar.com/info/460228/..., но короче:

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