CodeShot

AuthenticationHandler در مقابل AuthorizationHandler

AuthenticationHandler در ASP.NET Core مسئول تشخیص "کاربر کیست" است — اعتبارسنجی توکن/کوکی و ساخت ClaimsPrincipal از هویت درخواست؛ AuthorizationHandler مسئول تصمیم‌گیری "آیا این کاربر مجاز است" است — بررسی خط‌مشی‌ها (Policy) و claim ها پس از احراز هویت برای اجازه یا رد دسترسی به یک منبع خاص.

ویژگیAuthenticationHandlerAuthorizationHandler
سوالی که پاسخ می‌دهدکاربر کیست؟آیا کاربر مجاز است؟
زمان اجرا در pipelineقبل (احراز هویت)بعد از احراز هویت
خروجیClaimsPrincipalنتیجه Succeed/Fail برای یک Requirement
مثال کاربرد سفارشیاحراز هویت با API Keyبررسی مالکیت منبع

کِی از AuthenticationHandler استفاده کنیم؟

وقتی می‌خواهید یک مکانیزم سفارشی برای شناسایی کاربر پیاده کنید (مثلاً یک روش احراز هویت غیراستاندارد بر پایه هدر API Key)، یک AuthenticationHandler سفارشی بنویسید که از AuthenticationHandler ارث‌بری می‌کند.

کِی از AuthorizationHandler استفاده کنیم؟

وقتی منطق مجوزدهی شما فراتر از نقش‌های ساده است (مثلاً "فقط مالک منبع یا ادمین اجازه ویرایش دارد")، یک AuthorizationHandler سفارشی برای یک Requirement خاص بنویسید و آن را به Policy اضافه کنید.

مثال AuthenticationHandler

public class ApiKeyAuthenticationHandler : AuthenticationHandler<ApiKeyOptions>
{
    protected override Task<AuthenticateResult> HandleAuthenticateAsync()
    {
        if (!Request.Headers.TryGetValue("X-Api-Key", out var key))
            return Task.FromResult(AuthenticateResult.Fail("Missing API Key"));
        var identity = new ClaimsIdentity("ApiKey");
        return Task.FromResult(AuthenticateResult.Success(
            new AuthenticationTicket(new ClaimsPrincipal(identity), Scheme.Name)));
    }
}

مثال AuthorizationHandler

public class OwnerRequirementHandler : AuthorizationHandler<OwnerRequirement, Order>
{
    protected override Task HandleRequirementAsync(
        AuthorizationHandlerContext context, OwnerRequirement req, Order order)
    {
        if (order.OwnerId == context.User.GetUserId())
            context.Succeed(req);
        return Task.CompletedTask;
    }
}

اشتباه رایج

نوشتن منطق مجوزدهی پیچیده (مثل بررسی مالکیت منبع) داخل خود AuthenticationHandler، در حالی که این مسئولیت باید کاملاً جدا و در یک AuthorizationHandler انجام شود — ترکیب این دو مسئولیت، کد را غیرقابل‌تست و شکننده می‌کند.

جمع‌بندی

"این کاربر کیست؟" → AuthenticationHandler؛ "آیا این کاربر اجازه دارد؟" → AuthorizationHandler — همیشه این دو مسئولیت را جدا نگه دارید.