Sdílet prostřednictvím


Zabezpečení: Ověřování a autorizace ve webových formulářích ASP.NET a Blazor

Tip

Tento obsah je výňatek z eBooku pro Blazor vývojáře webových formulářů ASP NET pro Azure, který je k dispozici na webu .NET Docs nebo jako bezplatný soubor PDF ke stažení, který si můžete přečíst offline.

Blazor-for-ASP-NET-Web-Forms-Developers eBook cover thumbnail.

Migrace z aplikace webových formulářů ASP.NET na Blazor téměř jistě bude vyžadovat aktualizaci způsobu provádění ověřování a autorizace za předpokladu, že aplikace měla nakonfigurované ověřování. V této kapitole se dozvíte, jak migrovat z modelu univerzálního zprostředkovatele ASP.NET Webových formulářů (pro členství, role a profily uživatelů) a jak pracovat s ASP.NET základní identitou z Blazor aplikací. I když tato kapitola popisuje základní kroky a důležité informace, podrobné kroky a skripty najdete v referenční dokumentaci.

ASP.NET univerzálních poskytovatelů

Od ASP.NET 2.0 podporuje platforma webových formulářů ASP.NET model poskytovatele pro řadu funkcí, včetně členství. Poskytovatel univerzálního členství společně s volitelným zprostředkovatelem rolí se běžně nasazuje s aplikacemi ASP.NET Webových formulářů. Nabízí robustní a bezpečný způsob správy ověřování a autorizace, který dnes funguje dobře. Nejnovější nabídka těchto univerzálních poskytovatelů je k dispozici jako balíček NuGet, Microsoft.AspNet.Providers.

Univerzální poskytovatelé pracují se schématem databáze SQL, který obsahuje tabulky jako aspnet_Applications, aspnet_Membership, aspnet_Rolesa aspnet_Users. Při konfiguraci spuštěním příkazu aspnet_regsql.exe nainstalují poskytovatelé tabulky a uložené procedury, které poskytují všechny potřebné dotazy a příkazy pro práci s podkladovými daty. Schéma databáze a tyto uložené procedury nejsou kompatibilní s novějšími systémy identit ASP.NET Identity a ASP.NET Core Identity, takže stávající data musí být migrována do nového systému. Obrázek 1 ukazuje ukázkové schéma tabulky nakonfigurované pro univerzální poskytovatele.

Schéma univerzálních poskytovatelů

Univerzální poskytovatel zpracovává uživatele, členství, role a profily. Uživatelům se přiřazují globálně jedinečné identifikátory a základní informace, jako je userId, userName atd. jsou uložené v aspnet_Users tabulce. Ověřovací informace, jako je heslo, formát hesla, sůl hesla, čítače uzamčení a podrobnosti atd. jsou uložené v aspnet_Membership tabulce. Role se skládají jednoduše z názvů a jedinečných identifikátorů, které jsou přiřazeny uživatelům prostřednictvím aspnet_UsersInRoles tabulky přidružení a poskytují relaci M:N.

Pokud váš stávající systém kromě členství používá role, budete muset migrovat uživatelské účty, přidružená hesla, role a členství rolí do ASP.NET základní identity. Pravděpodobně budete také muset aktualizovat kód, ve kterém aktuálně provádíte kontroly rolí pomocí příkazů if, aby místo toho využívaly deklarativní filtry, atributy a/nebo pomocné rutiny značek. Na konci této kapitoly se podrobněji podíváme na aspekty migrace.

Konfigurace autorizace ve webových formulářích

Pokud chcete nakonfigurovat autorizovaný přístup k určitým stránkám v aplikaci ASP.NET Web Forms, obvykle určíte, že některé stránky nebo složky jsou pro anonymní uživatele nepřístupné. Tato konfigurace se provádí v souboru web.config:

<?xml version="1.0"?>
<configuration>
    <system.web>
      <authentication mode="Forms">
        <forms defaultUrl="~/home.aspx" loginUrl="~/login.aspx"
          slidingExpiration="true" timeout="2880"></forms>
      </authentication>

      <authorization>
        <deny users="?" />
      </authorization>
    </system.web>
</configuration>

Oddíl authentication konfigurace nastaví ověřování pomocí formulářů pro aplikaci. Oddíl authorization slouží k zakázání anonymních uživatelů pro celou aplikaci. Podrobnější autorizační pravidla však můžete poskytnout na základě jednotlivých umístění a také použít kontroly autorizace na základě role.

<location path="login.aspx">
  <system.web>
    <authorization>
      <allow users="*" />
    </authorization>
  </system.web>
</location>

Výše uvedená konfigurace v kombinaci s první konfigurací by anonymním uživatelům umožňovala přístup k přihlašovací stránce a přepisovala omezení celého webu na neověřené uživatele.

<location path="/admin">
  <system.web>
    <authorization>
      <allow roles="Administrators" />
      <deny users="*" />
    </authorization>
  </system.web>
</location>

Výše uvedená konfigurace v kombinaci s ostatními omezuje přístup ke /admin složce a všem prostředkům v ní na členy role Administrators. Toto omezení lze použít také umístěním samostatného web.config souboru do kořenové složky /admin .

Autorizační kód ve webových formulářích

Kromě konfigurace přístupu pomocí web.configkódu programu můžete také nakonfigurovat přístup a chování v aplikaci Webové formuláře. Můžete například omezit možnost provádět určité operace nebo zobrazit určitá data na základě role uživatele.

Tento kód lze použít jak v logice kódu, tak i na samotné stránce:

<% if (HttpContext.Current.User.IsInRole("Administrators")) { %>
  <a href="/admin">Go To Admin</a>
<% } %>

Kromě kontroly členství v rolích uživatelů můžete také určit, jestli jsou ověřeny (často se to ale používá lépe pomocí výše popsané konfigurace založené na poloze). Níže je příklad tohoto přístupu.

protected void Page_Load(object sender, EventArgs e)
{
    if (!User.Identity.IsAuthenticated)
    {
        FormsAuthentication.RedirectToLoginPage();
    }
    if (!Roles.IsUserInRole(User.Identity.Name, "Administrators"))
    {
        MessageLabel.Text = "Only administrators can view this.";
        SecretPanel.Visible = false;
    }
}

Ve výše uvedeném kódu se řízení přístupu na základě role (RBAC) používá k určení, jestli jsou určité prvky stránky, například a SecretPanel, viditelné na základě role aktuálního uživatele.

Obvykle ASP.NET aplikace Webových formulářů konfigurují zabezpečení v web.config souboru a pak na stránkách a souvisejících .aspx.cs souborech kódu přidávají další kontroly.aspx. Většina aplikací využívá poskytovatele univerzálního členství, často s dalším poskytovatelem rolí.

základní identita ASP.NET

I když se stále pracuje s ověřováním a autorizací, ASP.NET Core Identity používá v porovnání s univerzálními poskytovateli jinou sadu abstrakcí a předpokladů. Nový model identity například podporuje ověřování třetích stran, což uživatelům umožňuje ověřování pomocí účtu sociálních médií nebo jiného důvěryhodného zprostředkovatele ověřování. ASP.NET Core Identity podporuje uživatelské rozhraní pro běžně potřebné stránky, jako je přihlášení, odhlášení a registrace. Využívá EF Core pro přístup k datům a používá migrace EF Core k vygenerování potřebného schématu potřebného k podpoře datového modelu. Tento úvod do identity v ASP.NET Core poskytuje dobrý přehled toho, co je součástí ASP.NET Core Identity a jak s ní začít pracovat. Pokud jste ještě ve své aplikaci a její databázi nenastavili ASP.NET Core Identity, pomůže vám to začít.

Role, deklarace identity a zásady

Koncept rolí podporují univerzální zprostředkovatelé i ASP.NET Core Identity. Můžete vytvářet role pro uživatele a přiřazovat uživatele k rolím. Uživatelé můžou patřit do libovolného počtu rolí a v rámci implementace autorizace můžete ověřit členství v rolích.

Kromě rolí podporuje identita ASP.NET Core koncepty deklarací identity a zásad. Zatímco role by měla konkrétně odpovídat sadě prostředků, ke kterým by měl mít uživatel v této roli přístup, deklarace identity je jednoduše součástí identity uživatele. Deklarace identity je dvojice hodnot názvu, která představuje, co předmět je, ne to, co předmět může dělat.

Je možné přímo zkontrolovat deklarace identity uživatele a určit na základě těchto hodnot, zda má být uživateli udělen přístup k prostředku. Tyto kontroly jsou však často opakované a rozptýlené v celém systému. Lepším přístupem je definovat zásadu.

Zásady autorizace se skládají z jednoho nebo více požadavků. Zásady se registrují jako součást konfigurace autorizační služby v ConfigureServices metodě Startup.cs. Například následující fragment kódu konfiguruje zásadu s názvem "CanadiansOnly", která má požadavek, aby uživatel získal deklaraci země s hodnotou "Kanada".

services.AddAuthorization(options =>
{
    options.AddPolicy("CanadiansOnly", policy => policy.RequireClaim(ClaimTypes.Country, "Canada"));
});

Další informace o vytváření vlastních zásad najdete v dokumentaci.

Bez ohledu na to, jestli používáte zásady nebo role, můžete určit, že konkrétní stránka ve vaší Blazor aplikaci vyžaduje tuto roli nebo zásadu s atributem použitou [Authorize] se direktivou @attribute .

Vyžadování role:

@attribute [Authorize(Roles ="administrators")]

Vyžadování zásady:

@attribute [Authorize(Policy ="CanadiansOnly")]

Pokud potřebujete přístup ke stavu ověřování, rolím nebo deklaracím identity uživatele v kódu, existují dva primární způsoby, jak tuto funkci dosáhnout. Prvním je přijmout stav ověřování jako kaskádový parametr. Druhým je přístup ke stavu pomocí vloženého AuthenticationStateProvidersouboru . Podrobnosti o každém z těchto přístupů jsou popsány v Blazor dokumentaci zabezpečení.

Následující kód ukazuje, jak získat AuthenticationState kaskádový parametr:

[CascadingParameter]
private Task<AuthenticationState> authenticationStateTask { get; set; }

S tímto parametrem můžete uživatele získat pomocí tohoto kódu:

var authState = await authenticationStateTask;
var user = authState.User;

Následující kód ukazuje, jak vložit AuthenticationStateProvider:

@using Microsoft.AspNetCore.Components.Authorization
@inject AuthenticationStateProvider AuthenticationStateProvider

S poskytovatelem můžete získat přístup k uživateli pomocí následujícího kódu:

AuthenticationState authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
ClaimsPrincipal user = authState.User;

if (user.Identity.IsAuthenticated)
{
  // work with user.Claims and/or user.Roles
}

Poznámka: Součást AuthorizeView , která je popsána dále v této kapitole, poskytuje deklarativní způsob, jak řídit, co uživatel vidí na stránce nebo komponentě.

Pokud chcete pracovat s uživateli a deklaracemi identity (v Blazor serverových aplikacích), možná budete muset vložit UserManager<T> (použít pro výchozí nastavení IdentityUser ), které můžete použít k vytvoření výčtu a úpravě deklarací identity pro uživatele. Nejprve zadejte typ a přiřaďte ho k vlastnosti:

@inject UserManager<IdentityUser> MyUserManager

Pak ho použijte k práci s deklaracemi identity uživatele. Následující ukázka ukazuje, jak přidat a zachovat deklaraci identity u uživatele:

private async Task AddCountryClaim()
{
    var authState = await AuthenticationStateProvider.GetAuthenticationStateAsync();
    var user = authState.User;
    var identityUser = await MyUserManager.FindByNameAsync(user.Identity.Name);

    if (!user.HasClaim(c => c.Type == ClaimTypes.Country))
    {
        // stores the claim in the cookie
        ClaimsIdentity id = new ClaimsIdentity();
        id.AddClaim(new Claim(ClaimTypes.Country, "Canada"));
        user.AddIdentity(id);

        // save the claim in the database
        await MyUserManager.AddClaimAsync(identityUser, new Claim(ClaimTypes.Country, "Canada"));
    }
}

Pokud potřebujete pracovat s rolemi, postupujte podle stejného přístupu. Možná budete muset vložit (použít IdentityRole výchozí typ) k výpisu RoleManager<T> a správě samotných rolí.

Poznámka: V Blazor projektech WebAssembly budete muset k provedení těchto operací poskytnout rozhraní API serveru (místo použití UserManager<T> nebo RoleManager<T> přímo). Blazor Klientská aplikace WebAssembly by spravovala deklarace identity nebo role zabezpečeným voláním koncových bodů rozhraní API vystavených pro tento účel.

Průvodce migrací

Migrace z webových formulářů ASP.NET a univerzálních poskytovatelů na ASP.NET Základní identita vyžaduje několik kroků:

  1. Vytvoření schématu databáze ASP.NET Core Identity v cílové databázi
  2. Migrace dat ze schématu univerzálního zprostředkovatele na schéma základní identity ASP.NET
  3. Migrace konfigurace z middlewaru web.config a služeb, obvykle v Program.cs (nebo Startup třídě)
  4. Aktualizujte jednotlivé stránky pomocí ovládacích prvků a podmíněných prvků, aby používaly pomocné rutiny značek a nová rozhraní API identit.

Každý z těchto kroků je podrobně popsaný v následujících částech.

Vytvoření schématu základní identity ASP.NET

Existuje několik způsobů, jak vytvořit potřebnou strukturu tabulky použitou pro ASP.NET základní identitu. Nejjednodušší je vytvořit novou webovou aplikaci ASP.NET Core. Zvolte webovou aplikaci a potom změňte typ ověřování tak, aby používal jednotlivé účty.

nový projekt s jednotlivými účty

Z příkazového řádku můžete provést totéž spuštěním dotnet new webapp -au Individualpříkazu . Po vytvoření aplikace ji spusťte a zaregistrujte na webu. Měla by se aktivovat stránka podobná té, která je znázorněná níže:

Stránka použít migrace

Klikněte na tlačítko Použít migrace a měli byste vytvořit potřebné databázové tabulky. Kromě toho by se soubory migrace měly zobrazit v projektu, jak je znázorněno níže:

soubory migrace

Migraci můžete spustit sami bez spuštění webové aplikace pomocí tohoto nástroje příkazového řádku:

dotnet ef database update

Pokud byste raději spustili skript pro použití nového schématu pro existující databázi, můžete tyto migrace skriptovat z příkazového řádku. Spuštěním tohoto příkazu vygenerujte skript:

dotnet ef migrations script -o auth.sql

Výše uvedený příkaz vytvoří ve výstupním souboru auth.sqlskript SQL, který pak můžete spustit pro libovolnou databázi, kterou chcete. Pokud máte potíže se spouštěním dotnet ef příkazů, ujistěte se, že máte v systému nainstalované nástroje EF Core.

V případě, že máte ve zdrojových tabulkách další sloupce, budete muset identifikovat nejlepší umístění pro tyto sloupce v novém schématu. Obecně platí, že sloupce nalezené v aspnet_Membership tabulce by se měly mapovat na AspNetUsers tabulku. Sloupce by aspnet_Roles měly být namapovány na AspNetRoles. Všechny další sloupce v aspnet_UsersInRoles tabulce by se do AspNetUserRoles tabulky přidaly.

Je také vhodné zvážit vložení dalších sloupců do samostatných tabulek. Aby budoucí migrace nemusely brát v úvahu taková přizpůsobení výchozího schématu identit.

Migrace dat z univerzálních zprostředkovatelů do ASP.NET základní identity

Jakmile budete mít zavedené schéma cílové tabulky, dalším krokem je migrace záznamů uživatelů a rolí do nového schématu. Tady najdete úplný seznam rozdílů ve schématu, včetně sloupců mapovaných na nové sloupce.

Pokud chcete migrovat uživatele z členství do nových tabulek identit, měli byste postupovat podle kroků popsaných v dokumentaci. Po provedení těchto kroků a zadaného skriptu budou muset uživatelé při příštím přihlášení změnit heslo.

Je možné migrovat uživatelská hesla, ale proces je mnohem více zapojen. Vyžadování, aby uživatelé v rámci procesu migrace aktualizovali svá hesla a podporovali je, aby používali nová, jedinečná hesla, pravděpodobně zlepší celkové zabezpečení aplikace.

Migrace nastavení zabezpečení z web.config na spuštění aplikace

Jak je uvedeno výše, ASP.NET členství a zprostředkovatelé rolí se konfigurují v souboru aplikace web.config . Vzhledem k tomu, že aplikace ASP.NET Core nejsou svázané se službou IIS a pro konfiguraci používají samostatný systém, musí být tato nastavení nakonfigurovaná jinde. Ve většině případů se ASP.NET základní identita konfiguruje v souboru Program.cs . Otevřete webový projekt, který byl vytvořen dříve (pro vygenerování schématu tabulky identit) a zkontrolujte jeho Program.cs (nebo Startup.cs).

Tento kód přidává podporu pro EF Core a identitu:

// Add services to the container.
var connectionString = builder.Configuration.GetConnectionString("DefaultConnection");
builder.Services.AddDbContext<ApplicationDbContext>(options =>
    options.UseSqlServer(connectionString));
builder.Services.AddDatabaseDeveloperPageExceptionFilter();
builder.Services.AddDefaultIdentity<IdentityUser>(options =>
    options.SignIn.RequireConfirmedAccount = true)
    .AddEntityFrameworkStores<ApplicationDbContext>();

Metoda AddDefaultIdentity rozšíření se používá ke konfiguraci identity tak, aby používala IdentityUser výchozí ApplicationDbContext a typ architektury. Pokud používáte vlastní IdentityUser, nezapomeňte sem zadat jeho typ. Pokud tyto rozšiřující metody nefungují ve vaší aplikaci, zkontrolujte, zda máte odpovídající using direktivy a že máte potřebné odkazy na balíčky NuGet. Projekt by například měl obsahovat odkazy na určitou verzi Microsoft.AspNetCore.Identity.EntityFrameworkCore balíčků a Microsoft.AspNetCore.Identity.UI balíčků.

Také v Program.cs byste měli vidět potřebný middleware nakonfigurovaný pro lokalitu. UseAuthentication Konkrétně a UseAuthorization mělo by být nastaveno a ve správném umístění.

// Configure the HTTP request pipeline.
if (app.Environment.IsDevelopment())
{
    app.UseMigrationsEndPoint();
}
else
{
    app.UseExceptionHandler("/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();

app.UseStaticFiles();

app.UseRouting();

app.UseAuthentication();
app.UseAuthorization();

//app.MapControllers();
app.MapBlazorHub();
app.MapFallbackToPage("/_Host");

ASP.NET Identita nekonfiguruje anonymní přístup ani přístup na základě role k umístěním z Program.cs. Do filtrů v ASP.NET Core budete muset migrovat konfigurační data specifická pro konkrétní umístění. Poznamenejte si, které složky a stránky budou tyto aktualizace vyžadovat. Tyto změny provedete v další části.

Aktualizace jednotlivých stránek tak, aby používaly abstrakce základní identity ASP.NET

Pokud byste měli web.config v aplikaci webové formuláře ASP.NET nastavení odepřít přístup k určitým stránkám nebo složkám anonymním uživatelům, mohli byste tyto změny migrovat přidáním atributu [Authorize] na tyto stránky:

@attribute [Authorize]

Pokud jste dále odepřeli přístup s výjimkou těch uživatelů, kteří patří k určité roli, měli byste toto chování také migrovat přidáním atributu určujícího roli:

@attribute [Authorize(Roles ="administrators")]

Atribut [Authorize] funguje pouze na @page součástech, které jsou dosaženy Blazor přes směrovač. Atribut nefunguje s podřízenými komponentami, které by místo toho měly používat AuthorizeView.

Pokud máte logiku v kódu stránky pro určení, zda se má určitý uživatel zobrazit nějaký kód, můžete ho nahradit komponentou AuthorizeView . Komponenta AuthorizeView selektivně zobrazuje uživatelské rozhraní v závislosti na tom, jestli má uživatel oprávnění k jeho zobrazení. Také zveřejňuje proměnnou context , která se dá použít pro přístup k informacím o uživateli.

<AuthorizeView>
    <Authorized>
        <h1>Hello, @context.User.Identity.Name!</h1>
        <p>You can only see this content if you are authenticated.</p>
    </Authorized>
    <NotAuthorized>
        <h1>Authentication Failure!</h1>
        <p>You are not signed in.</p>
    </NotAuthorized>
</AuthorizeView>

Ke stavu ověřování v rámci procedurální logiky můžete přistupovat tak, že k uživateli přistupujete z Task<AuthenticationState nakonfigurovaného atributu [CascadingParameter] . Tato konfigurace vám umožní přístup k uživateli, který vám umožní určit, jestli je ověřený a jestli patří do určité role. Pokud potřebujete vyhodnotit zásadu procedurálně, můžete do ní vložit instanci IAuthorizationService a volat metodu AuthorizeAsync . Následující ukázkový kód ukazuje, jak získat informace o uživateli a povolit autorizovanému uživateli provádět úlohu omezenou zásadou content-editor .

@using Microsoft.AspNetCore.Authorization
@inject IAuthorizationService AuthorizationService

<button @onclick="@DoSomething">Do something important</button>

@code {
    [CascadingParameter]
    private Task<AuthenticationState> authenticationStateTask { get; set; }

    private async Task DoSomething()
    {
        var user = (await authenticationStateTask).User;

        if (user.Identity.IsAuthenticated)
        {
            // Perform an action only available to authenticated (signed-in) users.
        }

        if (user.IsInRole("admin"))
        {
            // Perform an action only available to users in the 'admin' role.
        }

        if ((await AuthorizationService.AuthorizeAsync(user, "content-editor"))
            .Succeeded)
        {
            // Perform an action only available to users satisfying the
            // 'content-editor' policy.
        }
    }
}

První AuthenticationState musí být nastavena jako kaskádová hodnota, aby bylo možné ji svázat s kaskádovým parametrem, jako je tento. To se obvykle provádí pomocí CascadingAuthenticationState komponenty. Tato konfigurace se obvykle provádí v App.razor:

<CascadingAuthenticationState>
    <Router AppAssembly="@typeof(Program).Assembly">
        <Found Context="routeData">
            <AuthorizeRouteView RouteData="@routeData"
                DefaultLayout="@typeof(MainLayout)" />
        </Found>
        <NotFound>
            <LayoutView Layout="@typeof(MainLayout)">
                <p>Sorry, there's nothing at this address.</p>
            </LayoutView>
        </NotFound>
    </Router>
</CascadingAuthenticationState>

Shrnutí

Blazor používá stejný model zabezpečení jako ASP.NET Core, což je ASP.NET identita Core. Migrace z univerzálních zprostředkovatelů na ASP.NET Základní identita je poměrně jednoduchá, za předpokladu, že se na původní schéma dat použilo příliš mnoho přizpůsobení. Po migraci dat je dobře zdokumentovaná práce s ověřováním a autorizací v Blazor aplikacích s konfigurovatelnou i programovou podporou pro většinu požadavků na zabezpečení.

Reference