یک نکتهی تکمیلی: کار با Policyها در برنامههای Blazor WASM
در این مطلب، روشی را برای برقراری دسترسی نقش Admin، به تمام قسمتهای محافظت شدهی برنامه، با معرفی نقش آن به یک ویژگی Authorize سفارشی شده، مشاهده کردید. هرچند این روش کار میکند، اما روش جدیدتر برقراری یک چنین دسترسیهای ترکیبی در برنامههای ASP.NET Core و سایر فناوریهای مشتق شدهی از آن، کار با Policyها است که برای نمونه در مثال فوق، به صورت زیر قابل پیاده سازی است:
الف) تعریف Policyهای مشترک بین برنامههای Web API و WASM
Policyهای تعریف شده، باید قابلیت اعمال به اکشن متدهای کنترلرها و همچنین کامپوننتهای WASM را داشته باشند. به همین جهت آنها را در پروژهی اشتراکی BlazorServer.Common که در هر دو پروژه استفاده میشود، قرار میدهیم:
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization; // dotnet add package Microsoft.AspNetCore.Authorization
namespace BlazorServer.Common
{
public static class PolicyTypes
{
public const string RequireAdmin = nameof(RequireAdmin);
public const string RequireCustomer = nameof(RequireCustomer);
public const string RequireEmployee = nameof(RequireEmployee);
public const string RequireEmployeeOrCustomer = nameof(RequireEmployeeOrCustomer);
public static AuthorizationOptions AddAppPolicies(this AuthorizationOptions options)
{
options.AddPolicy(RequireAdmin, policy => policy.RequireRole(ConstantRoles.Admin));
options.AddPolicy(RequireCustomer, policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(claim => claim.Type == ClaimTypes.Role
&& (claim.Value == ConstantRoles.Admin || claim.Value == ConstantRoles.Customer))
));
options.AddPolicy(RequireEmployee, policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(claim => claim.Type == ClaimTypes.Role
&& (claim.Value == ConstantRoles.Admin || claim.Value == ConstantRoles.Employee))
));
options.AddPolicy(RequireEmployeeOrCustomer, policy =>
policy.RequireAssertion(context =>
context.User.HasClaim(claim => claim.Type == ClaimTypes.Role
&& (claim.Value == ConstantRoles.Admin ||
claim.Value == ConstantRoles.Employee ||
claim.Value == ConstantRoles.Customer))
));
return options;
}
}
}
در اینجا یکسری Policy جدید را مشاهده میکنید که در آنها همواره نقش Admin حضور دارد و همچین روش or آنها را توسط policy.RequireAssertion مشاهده میکنید. این تعاریف، نیاز به نصب بستهی Microsoft.AspNetCore.Authorization را نیز دارند. با کمک Policyها میتوان ترکیبهای پیچیدهای از دسترسیهای موردنیاز را ساخت؛ بدون اینکه نیاز باشد مدام AuthorizeAttribute سفارشی را طراحی کرد.
ب) افزودن Policyهای تعریف شده به پروژههای Web API و WASM
پس از تعریف Policyهای مورد نیاز، اکنون نوبت به افزودن آنها به برنامههای Web API:
namespace BlazorWasm.WebApi
{
public class Startup
{
// ...
public void ConfigureServices(IServiceCollection services)
{
// ...
services.AddAuthorization(options => options.AddAppPolicies());
// ...
و همچنین WASM است:
namespace BlazorWasm.Client
{
public class Program
{
public static async Task Main(string[] args)
{
// ...
builder.Services.AddAuthorizationCore(options => options.AddAppPolicies());
// ...
}
}
}
به این ترتیب Policyهای یکدستی را بین برنامههای کلاینت و سرور، به اشتراک گذاشتهایم.
ج) استفاده از Policyهای تعریف شده در برنامهی WASM
اکنون که برنامه قابلیت کار با Policyها را پیدا کرده، میتوان فیلتر Roles سفارشی را حذف و با فیلتر Authorize پالیسی دار جایگزین کرد:
@page "/hotel-room-details/{Id:int}"
// ...
@*
@attribute [Roles(ConstantRoles.Customer, ConstantRoles.Employee)]
*@
@attribute [Authorize(Policy = PolicyTypes.RequireEmployeeOrCustomer)]
حتی میتوان از پالیسیها در حین تعریف AuthorizeViewها نیز استفاده کرد:
<AuthorizeView Policy="@PolicyTypes.RequireEmployeeOrCustomer">
<p>You can only see this if you're an admin or an employee or a customer.</p>
</AuthorizeView>