91

Я создаю веб-сайт с несколькими арендаторами, на котором размещаются страницы для клиентов. Первый сегмент URL будет строка, которая идентифицирует клиента, определенный в Global.asax с использованием следующей схемы URL-маршрутизации:Как перенаправить на динамический URL входа в ASP.NET MVC

"{client}/{controller}/{action}/{id}" 

Это прекрасно работает с URL-адреса, такие как/Foo/Home/Index.

Однако при использовании атрибута [Авторизовать] я хочу перенаправить на страницу входа, которая также использует ту же схему сопоставления. Таким образом, если клиент является foo, страница входа в систему будет/foo/Account/Login вместо фиксированной пересылки/Account/Login, определенной в web.config.

MVC использует HttpUnauthorizedResult для возврата неавторизованного статуса 401, который, как я полагаю, вызывает перенаправление ASP.NET на страницу, определенную в web.config.

Так кто-нибудь знает, как переопределить поведение перенаправления входа в ASP.NET? Или было бы лучше перенаправить в MVC путем создания настраиваемого атрибута авторизации?

EDIT - Ответ: после некоторого копания в источник .Net, я решил, что атрибут пользовательской аутентификации является лучшим решением:

public class ClientAuthorizeAttribute: AuthorizeAttribute 
{ 
    public override void OnAuthorization(AuthorizationContext filterContext) 
    { 
     base.OnAuthorization(filterContext); 

     if (filterContext.Cancel && filterContext.Result is HttpUnauthorizedResult) 
     { 
      filterContext.Result = new RedirectToRouteResult(
       new RouteValueDictionary 
       { 
        { "client", filterContext.RouteData.Values[ "client" ] }, 
        { "controller", "Account" }, 
        { "action", "Login" }, 
        { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
       }); 
     } 
    } 
} 
+2

делает почти ту же самую вещь с маршрутизацией, так что мне нужно это! Благодаря! – 2008-12-27 21:20:41

+0

Спасибо, я пытался выяснить, как сделать что-то подобное. – Chance 2010-02-03 02:34:06

+0

это дало мне идею для собственной реализации, спасибо большое! – 2010-10-31 16:47:08

ответ

30

Я думаю, что главная проблема в том, что если вы собираетесь для контрейлеризации на встроенном классе ASP.NET FormsAuthentication (и нет никакой веской причины, по которой вы не должны этого делать), что-то в конце дня собирается позвонить FormsAuthentication.RedirectToLoginPage(), который будет рассматривать один сконфигурированный URL. Там только один URL-адрес для входа, и именно так они его разработали.

Моим ударом (возможно, реализацией Rube Goldberg) было бы перенаправление на одну страницу входа в корневой каталог, общий для всех клиентов, например/account/login. На этой странице входа ничего не будет видно; он проверяет либо параметр ReturnUrl, либо какое-то значение, которое у меня есть в сеансе, или файл cookie, который идентифицирует клиента, и использует это для немедленного перенаправления 302 на конкретную страницу/клиент/учетную запись/логин. Это дополнительный перенаправление, но, вероятно, не заметно, и он позволяет использовать встроенные механизмы перенаправления.

Другой вариант - создать свой собственный пользовательский атрибут, как описано и избегать всего, что вызывает метод RedirectToLoginPage() класса FormsAuthentication, поскольку вы замените его собственной логикой перенаправления. (Вы можете создать свой собственный класс, похожий.) Поскольку это статический класс, я не знаю какого-либо механизма, с помощью которого вы могли бы просто ввести свой собственный альтернативный интерфейс и волшебным образом работать с существующим атрибутом [Авторизовать], который удары, но people have done similar things before.

Надеюсь, что это поможет!

40

В RTM-версии ASP.NET MVC отсутствует свойство Cancel. Этот код работает с ASP.NET MVC RTM:

using System; 
using System.Web; 
using System.Web.Mvc; 
using System.Web.Mvc.Resources; 

namespace ePegasus.Web.ActionFilters 
{ 
    public class CustomAuthorize : AuthorizeAttribute 
    { 
     public override void OnAuthorization(AuthorizationContext filterContext) 
     { 
      base.OnAuthorization(filterContext); 
      if (filterContext.Result is HttpUnauthorizedResult) 
      { 
       filterContext.Result = new RedirectToRouteResult(
        new System.Web.Routing.RouteValueDictionary 
         { 
           { "langCode", filterContext.RouteData.Values[ "langCode" ] }, 
           { "controller", "Account" }, 
           { "action", "Login" }, 
           { "ReturnUrl", filterContext.HttpContext.Request.RawUrl } 
         }); 
      } 
     } 
    } 
} 

Edit: Вы можете отключить loginUrl для проверки подлинности форм по умолчанию в web.config - в случае, если кто-то забывает вас есть пользовательский атрибут и использует встроенный атрибут [Авторизовать] по ошибке.

Изменить значение в сети.конфигурации:

<forms loginUrl="~/Account/ERROR" timeout="2880" /> 

Затем сделайте метод действия «ERROR», который регистрирует ошибку и перенаправляет пользователя к наиболее общей странице входа у вас есть.

2

Мое решение этой проблемы был обычай ActionResult класс:

sealed public class RequiresLoginResult : ActionResult 
    { 
     override public void ExecuteResult (ControllerContext context) 
     { 
      var response = context.HttpContext.Response; 

      var url = FormsAuthentication.LoginUrl; 
      if (!string.IsNullOrWhiteSpace (url)) 
       url += "?returnUrl=" + HttpUtility.UrlEncode (ReturnUrl); 

      response.Clear(); 
      response.StatusCode = 302; 
      response.RedirectLocation = url; 
     } 

     public RequiresLoginResult (string returnUrl = null) 
     { 
      ReturnUrl = returnUrl; 
     } 

     string ReturnUrl { get; set; } 
    } 
Смежные вопросы