Zabezpečení aplikací ověřováním a autorizací

od Microsoftu

Stáhnout PDF

Toto je krok 9 bezplatného kurzu aplikace NerdDinner , který vás provede sestavením malé, ale kompletní webové aplikace pomocí ASP.NET MVC 1.

Krok 9 ukazuje, jak přidat ověřování a autorizaci k zabezpečení naší aplikace NerdDinner, aby se uživatelé museli zaregistrovat a přihlásit k webu, aby mohli vytvářet nové večeře, a pouze uživatel, který hostí večeři, ho může později upravit.

Pokud používáte ASP.NET MVC 3, doporučujeme postupovat podle kurzů Začínáme S MVC 3 nebo MVC Music Store.

NerdDinner Krok 9: Ověřování a autorizace

Právě teď naše nerdDinner aplikace dává každému, kdo navštíví stránky možnost vytvářet a upravovat podrobnosti o každé večeři. Pojďme to změnit tak, aby se uživatelé museli zaregistrovat a přihlásit se k webu, aby mohli vytvářet nové večeře, a přidat omezení, aby ho mohl později upravovat jenom uživatel, který hostí večeři.

K tomu použijeme ověřování a autorizaci k zabezpečení naší aplikace.

Principy ověřování a autorizace

Ověřování je proces identifikace a ověření identity klienta přistupujícího k aplikaci. Zjednodušeně řečeno jde o identifikaci toho, "kdo" je koncový uživatel při návštěvě webu. ASP.NET podporuje několik způsobů ověřování uživatelů prohlížeče. U internetových webových aplikací se nejčastěji používá metoda ověřování označovaná jako ověřování pomocí formulářů. Ověřování pomocí formulářů umožňuje vývojáři vytvořit přihlašovací formulář HTML v rámci své aplikace a pak ověřit uživatelské jméno a heslo, které koncový uživatel odešle, vůči databázi nebo jinému úložišti přihlašovacích údajů hesla. Pokud je kombinace uživatelského jména a hesla správná, vývojář pak může požádat ASP.NET o vydání šifrovaného souboru cookie HTTP, který identifikuje uživatele v budoucích požadavcích. Použijeme ověřování pomocí formulářů s naší aplikací NerdDinner.

Autorizace je proces určení, jestli má ověřený uživatel oprávnění k přístupu ke konkrétní adrese URL nebo prostředku nebo k provedení nějaké akce. Například v naší aplikaci NerdDinner chceme autorizovat, aby přístup k adrese /Dinners/Create URL a vytváření nových večeří měli jenom přihlášení uživatelé. Chceme také přidat autorizační logiku, aby ji mohl upravovat jenom uživatel, který hostí večeři, a odepře přístup k úpravám všem ostatním uživatelům.

Ověřování pomocí formulářů a kontrola účtů

Výchozí šablona projektu sady Visual Studio pro ASP.NET MVC automaticky povoluje ověřování pomocí formulářů při vytváření nových aplikací ASP.NET MVC. Do projektu se také automaticky přidá předem připravená implementace přihlašovací stránky účtu, což usnadňuje integraci zabezpečení do webu.

Výchozí stránka předlohy Site.master zobrazí odkaz Přihlásit se v pravém horním rohu webu, pokud uživatel, který k němu přistupuje, není ověřený:

Snímek obrazovky se stránkou Nerd Dinner Host a Dinner V pravém horním rohu je zvýrazněná položka Log On (Přihlásit se).

Kliknutím na odkaz Přihlásit se uživatel přejde na adresu URL /Account/LogOn :

Snímek obrazovky se stránkou Nerd Dinner Log On

Návštěvníci, kteří se nezaregistrovali, to mohou udělat kliknutím na odkaz "Zaregistrovat" – tím se dostanou na adresu URL /Account/Register a umožní jim zadat podrobnosti o účtu:

Snímek obrazovky se stránkou Nerd Dinner Create a New Account (Nerd Dinner Create a New Account)

Kliknutím na tlačítko Zaregistrovat se v systému členství ASP.NET vytvoří nový uživatel a ověří se na webu pomocí ověřování pomocí formulářů.

Když je uživatel přihlášený, web Site.master změní v pravém horním rohu stránky zprávu "Welcome [username]!" (Vítejte [uživatelské_jméno]!) a vykreslí odkaz "Log Off" místo "Log On" (Přihlásit se). Kliknutím na odkaz Odhlásit se uživatel odhlásí:

Snímek obrazovky se stránkou formuláře Nerd Dinner Host a Dinner V pravém horním rohu jsou zvýrazněná tlačítka Vítejte a Odhlásit se.

Výše uvedená funkce přihlášení, odhlášení a registrace je implementována v rámci třídy AccountController, která byla přidána do našeho projektu sadou Visual Studio při vytváření projektu. Uživatelské rozhraní pro AccountController je implementováno pomocí šablon zobrazení v adresáři \Views\Account:

Snímek obrazovky s navigačním stromem Nerd Dinner Je zvýrazněná tečka kontroleru účtů. Složka účtu a položky nabídky jsou také zvýrazněné.

Třída AccountController používá systém ověřování ASP.NET Forms k vydávání šifrovaných ověřovacích souborů cookie a rozhraní API členství ASP.NET k ukládání a ověřování uživatelských jmen a hesel. Rozhraní API pro členství ASP.NET je rozšiřitelné a umožňuje použití libovolného úložiště přihlašovacích údajů hesel. ASP.NET se dodává s integrovanými implementacemi poskytovatelů členství, které ukládají uživatelská jména a hesla v databázi SQL nebo ve službě Active Directory.

Poskytovatele členství, kterého má naše aplikace NerdDinner používat, můžeme nakonfigurovat tak, že otevřete soubor "web.config" v kořenovém adresáři projektu a vyhledáme <v něm oddíl členství> . Výchozí web.config přidaný při vytvoření projektu zaregistruje zprostředkovatele členství SQL a nakonfiguruje ho tak, aby k určení umístění databáze používal připojovací řetězec s názvem ApplicationServices.

Výchozí připojovací řetězec ApplicationServices (zadaný v <části connectionStrings> souboru web.config) je nakonfigurovaný tak, aby používal SQL Express. Odkazuje na databázi SQL Express s názvem ASPNETDB. MDF v adresáři App_Data aplikace. Pokud tato databáze při prvním použití rozhraní MEMBERSHIP API v rámci aplikace neexistuje, ASP.NET automaticky vytvoří databázi a zřídí v ní příslušné schéma členské databáze:

Snímek obrazovky s navigačním stromem Nerd Dinner Rozbalí se data aplikace a vybere se A S P NET D B tečka M D F.

Pokud bychom místo SQL Express chtěli použít úplnou instanci SQL Server (nebo se připojit ke vzdálené databázi), stačí aktualizovat připojovací řetězec ApplicationServices v souboru web.config a ujistit se, že se do databáze, na kterou odkazuje, přidalo příslušné schéma členství. Spuštěním nástroje "aspnet_regsql.exe" v adresáři \Windows\Microsoft.NET\Framework\v2.0.50727\ můžete přidat příslušné schéma pro členství a další ASP.NET aplikační služby do databáze.

Autorizace adresy URL /Dinners/Create POMOCÍ filtru [Authorize]

Nemuseli jsme psát žádný kód, který by umožnil implementaci zabezpečeného ověřování a správy účtů pro aplikaci NerdDinner. Uživatelé si můžou zaregistrovat nové účty v naší aplikaci a přihlásit se k webu nebo se odhlásit.

Teď můžeme do aplikace přidat autorizační logiku a pomocí stavu ověřování a uživatelského jména návštěvníků řídit, co můžou a nemůžou v rámci webu dělat. Začněme přidáním logiky autorizace do metod akcí Create naší třídy DinnersController. Konkrétně budeme vyžadovat, aby uživatelé, kteří přistupují k adrese URL /Dinners/Create , byli přihlášení. Pokud nejsou přihlášení, přesměrujeme je na přihlašovací stránku, aby se mohli přihlásit.

Implementace této logiky je poměrně snadná. Vše, co musíme udělat, je přidat atribut filtru [Authorize] do metody akce Vytvořit, například takto:

//
// GET: /Dinners/Create

[Authorize]
public ActionResult Create() {
   ...
} 

//
// POST: /Dinners/Create

[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Create(Dinner dinnerToCreate) {
   ...
}

ASP.NET MVC podporuje možnost vytvářet "filtry akcí", které se dají použít k implementaci opakovaně použitelné logiky, kterou lze deklarativně použít na metody akcí. Filtr [Authorize] je jedním z předdefinovaných filtrů akcí poskytovaných ASP.NET MVC a umožňuje vývojáři deklarativně aplikovat autorizační pravidla na metody akcí a třídy kontroleru.

Při použití bez jakýchkoli parametrů (jako je výše) filtr [Authorize] vynutí, že uživatel, který provádí požadavek metody akce, musí být přihlášený – a pokud tomu tak není, automaticky přesměruje prohlížeč na přihlašovací adresu URL. Při přesměrování se původně požadovaná adresa URL předá jako argument řetězce dotazu (například: /Account/LogOn? ReturnUrl=%2fDinners%2fCreate). AccountController pak přesměruje uživatele zpět na původně požadovanou adresu URL, jakmile se přihlásí.

Filtr [Authorize] volitelně podporuje možnost zadat vlastnost Users nebo Roles, která může vyžadovat, aby byl uživatel přihlášený a v seznamu povolených uživatelů nebo členem povolené role zabezpečení. Například následující kód umožňuje přístup k adrese URL /Dinners/Create pouze dvěma konkrétním uživatelům, "scottgu" a "billg":

[Authorize(Users="scottgu,billg")]
public ActionResult Create() {
    ...
}

Vkládání konkrétních uživatelských jmen do kódu ale bývá poměrně neudržitelné. Lepším přístupem je definovat "role" vyšší úrovně, které kód kontroluje, a pak namapovat uživatele na roli pomocí databáze nebo systému Active Directory (umožnit externí ukládání skutečného seznamu mapování uživatelů z kódu). ASP.NET zahrnuje integrované rozhraní API pro správu rolí a také předdefinovanou sadu zprostředkovatelů rolí (včetně zprostředkovatelů pro SQL a Active Directory), které vám můžou pomoct s mapováním uživatele a role. Pak bychom mohli kód aktualizovat tak, aby umožňoval přístup k adrese URL /Dinners/Create pouze uživatelům s konkrétní rolí správce:

[Authorize(Roles="admin")]
public ActionResult Create() {
   ...
}

Použití User.Identity.Name ubytování při vytváření večeří

Uživatelské jméno aktuálně přihlášeného uživatele požadavku můžeme načíst pomocí vlastnosti User.Identity.Name zveřejněné v základní třídě Controller.

Dříve, když jsme implementovali verzi HTTP-POST naší metody akce Create(), měli jsme pevně zakódovanou vlastnost "HostedBy" Dinner na statický řetězec. Teď můžeme tento kód aktualizovat tak, aby místo toho používal vlastnost User.Identity.Name, a také automaticky přidat rsvp pro hostitele, který vytváří večeři:

//
// POST: /Dinners/Create

[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Create(Dinner dinner) {

    if (ModelState.IsValid) {
    
        try {
            dinner.HostedBy = User.Identity.Name;

            RSVP rsvp = new RSVP();
            rsvp.AttendeeName = User.Identity.Name;
            dinner.RSVPs.Add(rsvp);

            dinnerRepository.Add(dinner);
            dinnerRepository.Save();

            return RedirectToAction("Details", new { id=dinner.DinnerID });
        }
        catch {
            ModelState.AddModelErrors(dinner.GetRuleViolations());
        }
    }

    return View(new DinnerFormViewModel(dinner));
}

Vzhledem k tomu, že jsme do metody Create() přidali atribut [Authorize], ASP.NET MVC zajistí, aby se metoda akce spustila pouze v případě, že uživatel, který navštíví adresu URL /Dinners/Create, je na webu přihlášený. Hodnota vlastnosti User.Identity.Name proto bude vždy obsahovat platné uživatelské jméno.

Použití User.Identity.Name ubytování při úpravách večeří

Teď přidáme autorizační logiku, která uživatele omezí, aby mohli upravovat jenom vlastnosti večeří, které sami hostují.

Abychom vám s tím pomohli, nejprve přidáme metodu pomocné rutiny IsHostedBy(username)" do objektu Dinner (v rámci částečné třídy Dinner.cs, které jsme vytvořili dříve). Tato pomocná metoda vrátí hodnotu true nebo false v závislosti na tom, jestli zadané uživatelské jméno odpovídá vlastnosti Dinner HostedBy, a zapouzdří logiku potřebnou k provedení porovnání řetězců nerozlišující malá a velká písmena:

public partial class Dinner {

    public bool IsHostedBy(string userName) {
        return HostedBy.Equals(userName, StringComparison.InvariantCultureIgnoreCase);
    }
}

Potom přidáme atribut [Authorize] do metod akce Edit() v rámci naší třídy DinnersController. Tím zajistíte, že uživatelé musí být přihlášení, aby mohli požádat o adresu URL /Dinners/Edit/[id].

Potom můžeme do metody Edit přidat kód, který pomocí pomocné metody Dinner.IsHostedBy(username) ověří, že přihlášený uživatel odpovídá hostiteli dinner. Pokud uživatel není hostitelem, zobrazíme zobrazení InvalidOwner a žádost ukončíme. Kód, který to provede, vypadá takto:

//
// GET: /Dinners/Edit/5

[Authorize]
public ActionResult Edit(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (!dinner.IsHostedBy(User.Identity.Name))
        return View("InvalidOwner");

    return View(new DinnerFormViewModel(dinner));
}

//
// POST: /Dinners/Edit/5

[AcceptVerbs(HttpVerbs.Post), Authorize]
public ActionResult Edit(int id, FormCollection collection) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (!dinner.IsHostedBy(User.Identity.Name))
        return View("InvalidOwner");

    try {
        UpdateModel(dinner);

        dinnerRepository.Save();

        return RedirectToAction("Details", new {id = dinner.DinnerID});
    }
    catch {
        ModelState.AddModelErrors(dinnerToEdit.GetRuleViolations());

        return View(new DinnerFormViewModel(dinner));
    }
}

Pak můžeme kliknout pravým tlačítkem na adresář \Views\Dinners a zvolit příkaz nabídky Přidat zobrazení> a vytvořit nové zobrazení InvalidOwner. Naplníme ho následující chybovou zprávou:

<asp:Content ID="Title" ContentPlaceHolderID="TitleContent" runat="server">
    You Don't Own This Dinner
</asp:Content>

<asp:Content ID="Main" ContentPlaceHolderID="MainContent" runat="server">

    <h2>Error Accessing Dinner</h2>

    <p>Sorry - but only the host of a Dinner can edit or delete it.</p>

</asp:Content>

A když se teď uživatel pokusí upravit večeři, kterou nevlastní, zobrazí se mu chybová zpráva:

Snímek obrazovky s chybovou zprávou na webové stránce Nerd Dinner

Stejný postup můžeme zopakovat pro metody akce Delete() v rámci kontroleru, abychom uzamknuli oprávnění k odstranění večeře a zajistili, že ho může odstranit jenom hostitel večeře.

Odkazujeme na metodu akce Upravit a Odstranit třídy DinnersController z adresy URL podrobností:

Snímek obrazovky se stránkou Nerd Dinner Tlačítka Upravit a Odstranit jsou v dolní části zakroužkovaná. Podrobnosti U R L jsou v horní části zakroužkovány.

V současné době zobrazujeme odkazy na akce Upravit a Odstranit bez ohledu na to, jestli je návštěvník adresy URL podrobností hostitelem večeře. Pojďme to změnit tak, aby se odkazy zobrazovaly jenom v případě, že hostující uživatel je vlastníkem večeře.

Metoda akce Details() v rámci třídy DinnersController načte objekt Dinner a pak ho předá jako objekt modelu do naší šablony zobrazení:

//
// GET: /Dinners/Details/5

public ActionResult Details(int id) {

    Dinner dinner = dinnerRepository.GetDinner(id);

    if (dinner == null)
        return View("NotFound");

    return View(dinner);
}

Šablonu zobrazení můžeme aktualizovat tak, aby podmíněně zobrazovala nebo skrývala odkazy Upravit a Odstranit pomocí pomocné metody Dinner.IsHostedBy(), jak je znázorněno níže:

<% if (Model.IsHostedBy(Context.User.Identity.Name)) { %>

   <%= Html.ActionLink("Edit Dinner", "Edit", new { id=Model.DinnerID }) %> |
   <%= Html.ActionLink("Delete Dinner", "Delete", new {id=Model.DinnerID}) %>    

<% } %>

Další kroky

Pojďme se teď podívat, jak můžeme ověřeným uživatelům povolit rsvp pro večeře pomocí AJAX.