✨ ایجاد Clean APIها با استفاده از Extension Methodها در ASP.NET Core
کار با Authorization Policyهای خام درست است ولی معمولاً کد را طولانی و پیچیده میکند.
برای بهبود تجربهٔ توسعهدهنده، میتوانیم از Extension Methodها استفاده کنیم تا کد خواناتر و تمیزتر شود. 🧩
🧠 ایجاد Extension Method برای مجوزها
public static class PermissionExtensions
{
public static void RequirePermission(
this AuthorizationPolicyBuilder builder,
params string[] allowedPermissions)
{
builder.AddRequirements(new PermissionAuthorizationRequirement(allowedPermissions));
}
}
🔹 با این متد، میتوانید بهصورت مستقیم و تمیز در Policyها از ()RequirePermission استفاده کنید.
⚡️ استفاده در Minimal APIها
public static class Permissions
{
public const string UsersRead = "users:read";
public const string UsersUpdate = "users:update";
public const string UsersDelete = "users:delete";
}
app.MapGet("me", async (ApplicationDbContext dbContext, ClaimsPrincipal User) =>
{
var user = await dbContext.Users
.AsNoTracking()
.Where(u => u.Id == int.Parse(User.FindFirstValue(JwtRegisteredClaimNames.Sub)!))
.Select(u => new UserDto
{
u.Id,
u.Email,
u.FirstName,
u.LastName
})
.SingleOrDefaultAsync();
return Results.Ok(user);
})
.RequireAuthorization(policy => policy.RequirePermission(Permissions.UsersRead));
💡 حالا endpointها تمیز، خوانا و کاملاً منطبق با الگوی Clean Architecture هستند.
🧩 استفاده در MVC Controllerها
برای MVC Controllerها میتوانیم Attribute اختصاصی بسازیم تا کار با مجوزها سادهتر شود:
[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)]
public class RequirePermissionAttribute(params string[] permissions) : AuthorizeAttribute
{
public RequirePermissionAttribute(params string[] permissions)
: base(policy: string.Join(",", permissions))
{
}
}
🔧 سپس Policyها را در DI Container ثبت میکنیم:
builder.Services.AddAuthorizationBuilder()
.AddPolicy("users:read", policy => policy.RequirePermission(Permissions.UsersRead))
.AddPolicy("users:update", policy => policy.RequirePermission(Permissions.UsersUpdate));
📦 حالا استفاده از آن در Controller بسیار تمیز و ساده است:
[RequirePermission(Permissions.UsersUpdate)]
public async Task<IActionResult> UpdateUser(int id, UpdateUserRequest request)
{
// Your logic here
}
🚀 Extension Points برای محیط Production
پیادهسازی بالا کاملاً کاربردی است، اما میتوان آن را در محیطهای Production گسترش داد.
دو نقطهٔ کلیدی برای توسعه وجود دارد:
🧱 Type-Safe Permissions با استفاده از Enum
بهجای استفاده از رشتههای جادویی (Magic Strings)، میتوان از Enumها استفاده کرد تا از بررسی در زمان کامپایل (Compile-Time Safety) بهره ببریم:
public enum Permission
{
UsersRead,
UsersUpdate,
UsersDelete,
OrdersCreate,
ReportsExport
}
سپس هنگام صدور JWT Token یا بررسی مجوز،
باید Enum را به string تبدیل کنید و هنگام خواندن Claims مجدداً آن را به Enum برگردانید. 🔁
این کار باعث میشود اشتباهات تایپی و ناسازگاریهای احتمالی حذف شوند،
و سیستم امنتر، خواناتر و مقیاسپذیرتر شود. 💪