Jak możemy ustawić autoryzację dla całego obszaru w ASP.NET MVC?

Mam obszar administratora i chcę, aby tylko administratorzy weszli w ten obszar. Rozważałem dodanie autoryzowanego atrybutu do każdego kontrolera w obszarze administracyjnym. Czy nie ma eleganckiego rozwiązania, czy tej funkcji nie ma w samym frameworku?

Edytuj: Przepraszam, powinienem był wcześniej o tym wspomnieć. Używam niestandardowego AuthorizedAttribute wywodzącego się z AuthorizeAttribute.

Author: Jon Seigel, 2010-02-23

6 answers

Www.zabezpieczenia oparte na konfiguracji powinny prawie nigdy być używane w aplikacji MVC. Powodem tego jest to, że wiele adresów URL może potencjalnie trafić w kontroler i umieścić te kontrole w sieci.config Pamiętaj-Kontrolery nie są powiązane z obszarami, trasy są powiązane z obszarami. Fabryka kontrolerów MVC będzie z przyjemnością obsługiwać Kontrolery z folderu obszary / dla żądań innych niż obszary, jeśli nie będzie konfliktu.

Na przykład, używając domyślna struktura projektu, dodając obszar administracyjny z kontrolerem AdminDefaultController, możesz nacisnąć ten kontroler przez /Admin/AdminDefault /Index i/AdminDefault / Index.

Jedynym obsługiwanym rozwiązaniem jest umieszczenie atrybutu na klasie bazowej kontrolera i upewnienie się, że każdy kontroler w obszarze podklasa tę klasę bazową.

 51
Author: Levi,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-23 17:47:27

Właśnie badałem ten sam problem. Ponieważ zabezpieczenie kontrolerów w oparciu o obszary nie jest możliwe , przychodzi na myśl prostsza opcja.

Utwórz definicję kontrolera bazowego dla każdego obszaru, który nadpisuje kontroler i dodaj do tego wymagane zabezpieczenia. Następnie musisz tylko upewnić się, że każdy kontroler w obszarze nadpisuje AreaController zamiast kontrolera. Na przykład:

/// <summary>
/// Base controller for all Admin area
/// </summary>
[Authorize(Roles = "Admin")]
public abstract class AdminController : Controller { }

Nadal wymaga, aby każdy kontroler w obszarze administracyjnym był pobierany z ta baza,

public class HomeController : AdminController
{
    // .. actions
}

Ale przynajmniej masz jeden punkt, w którym definiujesz bezpieczeństwo obszaru.

 44
Author: Quango,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2013-01-25 08:34:01

Jeśli cały Twój kod administracyjny znajduje się w jednym kontrolerze, dodaj Authorize do całej klasy.

[Authorize]
public class AdminController : Controller
{
     .......
}
 13
Author: John,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-23 15:17:12

Dopiero zacząłem... ale jak na razie to działa całkiem dobrze dla mnie.

Tworzę własną klasę AuthorizeAttribute i dodaję ją do funkcji RegisterGlobalFilters.

W Customautorizeattribute sprawdzam różne warunki w zależności od obszaru, w którym się znajduje.

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new CustomAuthorizeAttribute());
        filters.Add(new HandleErrorAttribute());
    }
}

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var routeData = httpContext.Request.RequestContext.RouteData;
        var controller = routeData.GetRequiredString("controller");
        var action = routeData.GetRequiredString("action");
        var area = routeData.DataTokens["area"];
        var user = httpContext.User;
        if (area != null && area.ToString() == "Customer")
        {
            if (!user.Identity.IsAuthenticated)
                return false;
        }
        else if (area != null && area.ToString() == "Admin")
        {
            if (!user.Identity.IsAuthenticated)
                return false;
            if (!user.IsInRole("Admin"))
                return false;
        }
        return true;
    }
}
 13
Author: Brian Rice,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2015-09-11 01:16:40

Aktualnie akceptowana odpowiedź nie jest najbezpieczniejszym rozwiązaniem, ponieważ wymaga od programisty zawsze pamiętania o dziedziczeniu nowej klasy bazowej dla nowych kontrolerów lub akcji ("Czarna lista"; pozwalająca użytkownikom na dostęp do wszystkiego, chyba że akcja jest ręcznie ograniczona). Powoduje to szczególnie problemy, gdy nowi programiści, nie znający Twoich rytuałów, są wprowadzani do projektu. Łatwo jest zapomnieć o dziedziczeniu odpowiedniej klasy kontrolera, jeśli jest to zrobione w ten sposób, zwłaszcza po oderwaniu wzroku od projektu na tygodnie, miesiące lub lata. Jeśli programista zapomni dziedziczyć, nie jest oczywiste, że w projekcie występuje luka w zabezpieczeniach.

Bezpieczniejszym rozwiązaniem tego problemu jest odmowa dostępu do wszystkich żądań , a następnie udekorowanie każdej akcji rolami, które mają dostęp do akcji ("biała lista"; zapobieganie dostępowi do wszystkich użytkowników, chyba że jest to dozwolone ręcznie). Teraz, jeśli programista zapomni o białej liście WŁAŚCIWEGO autoryzacja, użytkownicy dadzą Ci znać i jest to tak proste, jak przeglądanie innych kontrolerów w celu przypomnienia o tym, jak dać odpowiedni dostęp. Jednak przynajmniej nie ma większych luk w zabezpieczeniach.

W App_Start/FilterConfig.plik cs, zmodyfikuj klasę FilterConfig:

public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        ...

        //Deny access to all controllers and actions so that only logged in Administrators can access them by default
        filters.Add(new System.Web.Mvc.AuthorizeAttribute() { Roles = "Administrator" });
    }

To sprawia, że wszystkie działania są niedostępne, chyba że użytkownik jest zalogowany jako Administrator. Następnie dla każdej akcji, do której chcesz mieć dostęp inny upoważniony użytkownik, po prostu udekoruj ją [OverrideAuthorization] i [Authorize].

W logice biznesowej pozwala to na używanie atrybutu Authorize na wiele sposobów bez konieczności martwienia się o nieautoryzowany dostęp użytkowników do jakichkolwiek funkcji. Poniżej kilka przykładów.

Przykład 1 -Tylko zalogowani użytkownicy administratora i dyspozytora będą mieli dostęp do metod Get i Post Index().

public class MarkupCalculatorController : Controller //Just continue using the default Controller class.
{
    // GET: MarkupCalculator
    [OverrideAuthorization]
    [Authorize(Roles = "Administrator,Dispatcher")]
    public ActionResult Index()
    {
        //Business logic here.

        return View(...);
    }

    // POST: DeliveryFeeCalculator
    [HttpPost]
    [ValidateAntiForgeryToken]
    [OverrideAuthorization]
    [Authorize(Roles = "Administrator,Dispatcher")]
    public ActionResult Index([Bind(Include = "Price,MarkedupPrice")] MarkupCalculatorVM markupCalculatorVM)
    {
        //Business logic here.

        return View(...);
    }
}

Przykład 2 - tylko uwierzytelnieni użytkownicy będą mogli uzyskać dostęp do kontrolera domowego Index() metoda.

public class HomeController : Controller
{
    [OverrideAuthorization]
    [Authorize] //Allow all authorized (logged in) users to use this action
    public ActionResult Index()
    {
        return View();
    }

}

Przykład 3 -nieautoryzowani użytkownicy (np. anonimowi) mogą mieć dostęp do metod za pomocą atrybutu [AllowAnonymous]. To również automatycznie nadpisuje filtr globalny bez potrzeby atrybutu [OverrideAuthorization].

    // GET: /Account/Login
    [AllowAnonymous]
    public ActionResult Login(string returnUrl)
    {
        ViewBag.ReturnUrl = returnUrl;
        return View();
    }

    //
    // POST: /Account/Login
    [HttpPost]
    [AllowAnonymous]
    [ValidateAntiForgeryToken]
    public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
    {
        ...
    }

Przykład 4 - Tylko administratorzy będą mieli dostęp do metod, które nie posiadają atrybutu [Authorize].

public class LocationsController : Controller
{

    // GET: Locations
    public ActionResult Index()
    {
        //Business logic here.
        return View(...);
    }
}

Kilka uwag.

Musisz użyć atrybutu [OverrideAuthorization], jeśli chcesz ograniczyć dostęp do konkretnego działania do konkretnych ról. W przeciwnym razie, właściwości atrybutu [Authorize] zostaną zignorowane i tylko domyślna rola (Administrator w moim przykładzie) będzie dozwolona, nawet jeśli określisz inne role (np. Dyspozytor, itd.) ze względu na filtr globalny. Nieautoryzowani użytkownicy zostaną przekierowani na ekran logowania.

Użycie atrybutu [OverrideAuthorization] powoduje, że akcja ignoruje ustawiony filtr globalny. Dlatego musisz ponownie zastosować atrybut [Authorize] za każdym razem, gdy używasz obejdź, aby akcja pozostała bezpieczna.

W odniesieniu do całych obszarów i kontrolerów

Aby ograniczyć obszary, jak prosisz, umieść atrybuty [OverrideAuthorization] i [Authorize] na kontrolerze zamiast poszczególnych akcji.

 2
Author: aiwyn,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-11-09 17:57:06

.. bardzo brutalnie, wierzę, że chcesz czegoś takiego?

Szybkie i brudne zarządzanie rolami

[Authorize(Roles = "Admins")]
public ActionResult Register()
{
  ViewData["roleName"] = new SelectList(Roles.GetAllRoles(), "roleName");
  ViewData["PasswordLength"] = MembershipService.MinPasswordLength;
  return View();
}
 -5
Author: Ric Tokyo,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2010-02-23 15:10:47