Ověřování na základě rolí a prostředků
Naše referenční implementace je ASP.NET Core aplikace. V tomto článku se podíváme na dva obecné přístupy k autorizaci pomocí rozhraní API pro autorizaci, která ASP.NET Core.
- Autorizace na základě rolí. Autorizace akce na základě rolí přiřazených uživateli Některé akce například vyžadují roli správce.
- Autorizace na základě prostředků. Autorizace akce na základě konkrétního prostředku. Každý prostředek má například vlastníka. Vlastník může prostředek odstranit. ostatní uživatelé ne.
Typická aplikace bude využívat kombinaci obojího. Pokud například chcete prostředek odstranit, musí být uživatel vlastníkem prostředku nebo správcem.
Ověřování založené na rolích
Aplikace Tailspin Surveys definuje následující role:
- Správce. Může provádět všechny operace CRUD na jakémkoli průzkumu, který patří do tohoto tenanta.
- Tvůrce. Může vytvářet nové průzkumy.
- Čtenář. Může číst jakékoli průzkumy, které patří do tohoto tenanta.
Role se vztahují na uživatele aplikace. V aplikaci Surveys je uživatel správcem, tvůrcem nebo čtenářem.
Diskuzi o tom, jak definovat a spravovat role, najdete v tématu Aplikační role.
Bez ohledu na to, jak role spravujete, bude váš autorizační kód vypadat podobně. ASP.NET Core má abstrakci, která se nazývá zásady autorizace. Pomocí této funkce definujete zásady autorizace v kódu a pak je použijete na akce kontroleru. Zásada je oddělená od kontroleru.
Vytvoření zásad
Pokud chcete definovat zásadu, nejprve vytvořte třídu, která implementuje IAuthorizationRequirement . Nejjednodušší je odvodit z AuthorizationHandler . V Handle metodě zkontrolujte příslušné deklarace identity.
Tady je příklad z aplikace Tailspin Surveys:
public class SurveyCreatorRequirement : AuthorizationHandler<SurveyCreatorRequirement>, IAuthorizationRequirement
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, SurveyCreatorRequirement requirement)
{
if (context.User.HasClaim(ClaimTypes.Role, Roles.SurveyAdmin) ||
context.User.HasClaim(ClaimTypes.Role, Roles.SurveyCreator))
{
context.Succeed(requirement);
}
return Task.FromResult(0);
}
}
Tato třída definuje požadavek, aby uživatel vytvořil nový průzkum. Uživatel musí mít roli SurveyAdmin nebo SurveyCreator.
Ve třídě startup definujte pojmenovanou zásadu, která obsahuje jeden nebo více požadavků. Pokud existuje více požadavků, musí uživatel splňovat všechny požadavky, které musí být autorizovány. Následující kód definuje dvě zásady:
services.AddAuthorization(options =>
{
options.AddPolicy(PolicyNames.RequireSurveyCreator,
policy =>
{
policy.AddRequirements(new SurveyCreatorRequirement());
policy.RequireAuthenticatedUser(); // Adds DenyAnonymousAuthorizationRequirement
// By adding the CookieAuthenticationDefaults.AuthenticationScheme, if an authenticated
// user is not in the appropriate role, they will be redirected to a "forbidden" page.
policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
});
options.AddPolicy(PolicyNames.RequireSurveyAdmin,
policy =>
{
policy.AddRequirements(new SurveyAdminRequirement());
policy.RequireAuthenticatedUser();
policy.AddAuthenticationSchemes(CookieAuthenticationDefaults.AuthenticationScheme);
});
});
Tento kód také nastaví schéma ověřování, které informuje ASP.NET, který ověřovací middleware by se měl spustit v případě selhání autorizace. V tomto případě určíme middleware pro ověřování souborů cookie, protože middleware pro ověřování souborů cookie může uživatele přesměrovat na stránku Zakázáno. Umístění stránky Zakázáno je nastavené v možnosti middlewaru souborů cookie. Další informace najdete v AccessDeniedPath tématu Konfigurace ověřovacího middlewaru.
Autorizace akcí kontroleru
Nakonec pro autorizaci akce v kontroleru MVC nastavte zásadu v Authorize atributu :
[Authorize(Policy = PolicyNames.RequireSurveyCreator)]
public IActionResult Create()
{
var survey = new SurveyDTO();
return View(survey);
}
V dřívějších verzích ASP.NET byste nastavili vlastnost Roles u atributu :
// old way
[Authorize(Roles = "SurveyCreator")]
Tato funkce je ve ASP.NET Core podporována, ale oproti zásadám autorizace má určité nevýhody:
- Předpokládá se konkrétní typ deklarace identity. Zásady mohou kontrolovat libovolný typ deklarace identity. Role jsou jen typem deklarace identity.
- Název role je pevný do atributu . Díky zásadám je logika autorizace na jednom místě, což usnadňuje aktualizaci nebo dokonce načítání z nastavení konfigurace.
- Zásady umožňují složitější autorizační rozhodnutí (například věk >= 21), která nelze vyjádřit jednoduchým členstvím v rolích.
Autorizace na základě prostředků
K autorizaci na základě prostředků dochází vždy, když autorizace závisí na konkrétním prostředku, který bude ovlivněn operací. V aplikaci Tailspin Surveys má každý průzkum vlastníka a přispěvatele od nuly k mnoha.
- Vlastník může průzkum přečíst, aktualizovat, odstranit, publikovat a zrušit jeho publikování.
- Vlastník může k průzkumu přiřadit přispěvatele.
- Přispěvatelé mohou průzkum číst a aktualizovat.
Všimněte si, že "vlastník" a "přispěvatel" nejsou aplikační role. Ukládají se podle průzkumu v databázi aplikace. Pokud chcete zkontrolovat, jestli uživatel může například odstranit průzkum, aplikace zkontroluje, jestli je uživatel vlastníkem tohoto průzkumu.
V ASP.NET Core implementovat autorizaci na základě prostředků odvozením z AuthorizationHandler a přepsáním metody Handle.
public class SurveyAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Survey>
{
protected override void HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement operation, Survey resource)
{
}
}
Všimněte si, že pro objekty Survey je tato třída silného typu. Zaregistrujte třídu pro diodu při spuštění:
services.AddSingleton<IAuthorizationHandler>(factory =>
{
return new SurveyAuthorizationHandler();
});
K provádění kontrol autorizace použijte rozhraní IAuthorizationService, které můžete vložit do kontrolerů. Následující kód zkontroluje, jestli uživatel může přečíst průzkum:
if (await _authorizationService.AuthorizeAsync(User, survey, Operations.Read) == false)
{
return StatusCode(403);
}
Protože předáme Survey objekt , toto volání vyvolá SurveyAuthorizationHandler .
Ve vašem autorizačním kódu je vhodné agregovat všechna oprávnění na základě rolí a prostředků uživatele a pak zkontrolovat agregační sadu s požadovanou operací. Tady je příklad z aplikace Surveys. Aplikace definuje několik typů oprávnění:
- správce
- Přispěvatel
- tvůrce
- Vlastník
- Čtenář
Aplikace také definuje sadu možných operací na průzkumech:
- Vytvořit
- Číst
- Aktualizace
- Odstranit
- Publikovat
- Zrušit publikování
Následující kód vytvoří seznam oprávnění pro konkrétního uživatele a průzkum. Všimněte si, že tento kód sleduje role aplikace uživatele i pole vlastníka/přispěvatele v průzkumu.
public class SurveyAuthorizationHandler : AuthorizationHandler<OperationAuthorizationRequirement, Survey>
{
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OperationAuthorizationRequirement requirement, Survey resource)
{
var permissions = new List<UserPermissionType>();
int surveyTenantId = context.User.GetSurveyTenantIdValue();
int userId = context.User.GetSurveyUserIdValue();
string user = context.User.GetUserName();
if (resource.TenantId == surveyTenantId)
{
// Admin can do anything, as long as the resource belongs to the admin's tenant.
if (context.User.HasClaim(ClaimTypes.Role, Roles.SurveyAdmin))
{
context.Succeed(requirement);
return Task.FromResult(0);
}
if (context.User.HasClaim(ClaimTypes.Role, Roles.SurveyCreator))
{
permissions.Add(UserPermissionType.Creator);
}
else
{
permissions.Add(UserPermissionType.Reader);
}
if (resource.OwnerId == userId)
{
permissions.Add(UserPermissionType.Owner);
}
}
if (resource.Contributors != null && resource.Contributors.Any(x => x.UserId == userId))
{
permissions.Add(UserPermissionType.Contributor);
}
if (ValidateUserPermissions[requirement](permissions))
{
context.Succeed(requirement);
}
return Task.FromResult(0);
}
}
Ve vícetenantské aplikaci musíte zajistit, aby oprávnění "nevrácena" do dat jiného tenanta. V aplikaci Surveys je napříč tenanty povolené oprávnění Přispěvatel, které můžete přiřadit někomu z jiného — tenanta jako přispěvatele. Ostatní typy oprávnění jsou omezené na prostředky, které patří do tenanta tohoto uživatele. Pokud chcete tento požadavek vynutit, kód před udělením oprávnění zkontroluje ID tenanta. (Pole TenantId přiřazené při vytvoření průzkumu.)
Dalším krokem je kontrola operace (například čtení, aktualizace nebo odstranění) s oprávněními. Aplikace Surveys tento krok implementuje pomocí vyhledávací tabulky funkcí:
static readonly Dictionary<OperationAuthorizationRequirement, Func<List<UserPermissionType>, bool>> ValidateUserPermissions
= new Dictionary<OperationAuthorizationRequirement, Func<List<UserPermissionType>, bool>>
{
{ Operations.Create, x => x.Contains(UserPermissionType.Creator) },
{ Operations.Read, x => x.Contains(UserPermissionType.Creator) ||
x.Contains(UserPermissionType.Reader) ||
x.Contains(UserPermissionType.Contributor) ||
x.Contains(UserPermissionType.Owner) },
{ Operations.Update, x => x.Contains(UserPermissionType.Contributor) ||
x.Contains(UserPermissionType.Owner) },
{ Operations.Delete, x => x.Contains(UserPermissionType.Owner) },
{ Operations.Publish, x => x.Contains(UserPermissionType.Owner) },
{ Operations.UnPublish, x => x.Contains(UserPermissionType.Owner) }
};
Vzorek kódu