Як переспрямувати на URL-адресу динамічного входу в ASP.NET MVC


96

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

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

Це чудово працює з такими URL-адресами, як / foo / Home / Index.

Однак, використовуючи атрибут [Authorize], я хочу перенаправити на сторінку входу, яка також використовує ту саму схему відображення. Отже, якщо клієнт є foo, сторінкою входу буде / foo / Account / Login замість фіксованого / Account / Login перенаправлення, визначеного в web.config.

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

Тож хтось знає, як замінити поведінку перенаправлення входу ASP.NET? Або було б краще перенаправити в MVC, створивши власний атрибут авторизації?

РЕДАГУВАТИ - Відповідь: після деякого копання у джерелі .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
роблячи майже те саме, що стосується маршрутизації, тому мені це було потрібно! Дякую!
Тревор де Куккук,

Дякую, я намагався зрозуміти, як зробити щось подібне.
Шанс

це дало мені ідею для власної реалізації, велике спасибі!
Олександр Белецький

3
обов’язково встановіть area = null (або до правильної області), якщо використовуєте MVC 2 і вище - інакше він успадковується від сторінки, яку ви намагалися відвідати
Simon_Weaver

Будь-який спосіб зробити це без MVC?
DARKGuy

Відповіді:


30

Я думаю, що головна проблема полягає в тому, що якщо ви збираєтеся підключатись до вбудованого класу ASP.NET FormsAuthentication (і немає вагомих причин, чому ви цього не повинні робити), наприкінці дня буде дзвонити щось, FormsAuthentication.RedirectToLoginPage()що відбувається щоб переглянути одну налаштовану URL-адресу. Існує лише одна URL-адреса для входу, і саме так вони її розробили.

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

Інший варіант - створити власний власний атрибут, коли ви описуєте, і уникати будь-чого, що викликає RedirectToLoginPage()метод у FormsAuthenticationкласі, оскільки ви заміните його власною логікою перенаправлення. (Ви можете створити власний подібний клас.) Оскільки це статичний клас, я не знаю жодного механізму, за допомогою якого ви могли б просто вводити свій власний альтернативний інтерфейс і магічно працювати з існуючим атрибутом [Authorize], який удари, але люди робили подібні речі і раніше .

Сподіваюся, що це допомагає!


це, мабуть, найбезпечніший підхід. створення власного атрибута [MyAuthorize] небезпечно. якщо ваша збірка не підтверджує, що люди не використовують вбудований атрибут [Authorize], ви ризикуєте, щоб люди (або ви самі) забули та використали неправильний
Simon_Weaver

У деяких випадках може бути корисно перевизначити Application_AuthenticateRequest(див. Мою відповідь нижче).
turdus-merula

41

У 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 }
                        });
            }
        }
    }
}

Редагувати: можливо, ви захочете відключити автентифікацію форм за замовчуванням loginUrl у web.config - на випадок, якщо хтось забуде, що у вас є власний атрибут, і помилково використовує вбудований атрибут [Authorize].

Змініть значення в web.config:

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

Потім зробіть метод дії "ПОМИЛКА", який реєструє помилку та перенаправляє користувача на найбільш загальну сторінку входу у вас.


2
не забудьте додати {area, null} до словника (або як би там не називали вашу область), якщо ви використовуєте MVC 2 і вище - інакше він успадковується від сторінки, яку ви намагалися відвідати
Simon_Weaver

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; }
    }

0

Тим НЕ менше, якщо один вирішує використовувати вбудований в ASP.NET FormsAuthentication, можна overide Application_AuthenticateRequestв Global.asax.csнаступним чином :

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    string url = Request.RawUrl;

    if (url.Contains(("Account/Login"))
    {
        return;
    }

    if (Context.User == null)
    {
        // Your custom tenant-aware logic
        if (url.StartsWith("/foo"))
        {
            // Your custom login page.
            Response.Redirect("/foo/Account/Login");
            Response.End();
            return;
        }
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.