محتويات الدورة

ASP.NET Core / المتوسط: البيانات والهوية والعمل غير المتزامن / الدرس 10

الصلاحيات وحدود الموارد

طبّق فحوص السياسة والمورد باستخدام هوية موثوقة وحالة مورد حالية، لا بمجرد نجاح تسجيل الدخول.

وقت القراءة التقريبي: 5 دقيقةتاريخ مراجعة المحتوى
في هذه الصفحة

أهداف الدرس

  • اشرح السياسات والمتطلبات والمعالجات والقواعد الاحتياطية.
  • افحص الملكية ونطاق المستأجر قبل تنفيذ الآثار.
  • اختبر مكونات السياسة دون الادعاء باختبار تكامل المصادقة.

تعبّر السياسة عن السلطة المطلوبة

يقيم التحقق من الصلاحيات ما إذا كان يحق لفاعل أمني إجراء عملية على مورد. قد تشترط السياسة هوية ثبتت مصادقتها، أو ادعاءات أو أدوارا، أو متطلبات مخصصة. يلزم عادة استيفاء جميع متطلبات السياسة الواحدة، بينما قد تدعم عدة معالجات متطلبا واحدا وفقا لقواعد الإطار. تستحق آلية الفشل الصريح وخيارات تنفيذ المعالجات مراجعة، بدلا من افتراض التوقف المبكر عند أول نتيجة.

للسياسات المسماة والافتراضية والاحتياطية أدوار اختيار مختلفة. قد تحمي السياسة الاحتياطية نقاط النهاية الخالية من بيانات الصلاحية الوصفية عندما تعمل برمجية الصلاحيات الوسيطة، لكنها لا تحمي تلقائيا محتوى ثابتا قُدّم قبلها. تمثل AllowAnonymous استثناء صريحا يحتاج إلى مراجعة. وثّق السطح العام المقصود واختبره.

قيّم سياسة مسماة بادعاءات اصطناعية

يستخدم البرنامج الكامل الأول خدمة الصلاحيات الفعلية مع سياسة محلية وفاعلين مختلقين. يؤكد أن تجهيز القارئ يستوفي شرطي الهوية المصادق عليها والنطاق، بينما لا يستوفيهما التجهيز الفارغ. لا يتحقق من اعتمادات، ولا يحول النتيجة إلى استجابة HTTP من نوع challenge أو forbid؛ فهذان سلوكا تكامل منفصلان.

يجب أن تأتي قيمة النطاق أو الدور من مسار هوية موثوق. لا تمنح السلطة لأن مسارا أو استعلاما أو ترويسة مخصصة تحتوي كلمة مطابقة. قد يؤثر ربط نوع الادعاء وقيمته في نتيجة السياسة؛ لذا اجعل إعداد جهة الإصدار والمعالج متوافقا مع السياسة، واختبر الحالات الموجبة والسالبة معا.

csharp تقييم خدمة سياسات فعلية في الذاكرة
using System;
using System.Security.Claims;
using Microsoft.AspNetCore.Authorization;
using Microsoft.Extensions.DependencyInjection;

var services = new ServiceCollection();
services.AddLogging();
services.AddAuthorization(options => options.AddPolicy("ReadReports", policy => policy.RequireAuthenticatedUser().RequireClaim("scope", "reports.read")));
using var provider = services.BuildServiceProvider();
var authorization = provider.GetRequiredService<IAuthorizationService>();
var reader = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim("scope", "reports.read") }, "synthetic"));
var empty = new ClaimsPrincipal(new ClaimsIdentity());
bool allowed = (await authorization.AuthorizeAsync(reader, null, "ReadReports")).Succeeded;
bool denied = (await authorization.AuthorizeAsync(empty, null, "ReadReports")).Succeeded;
Console.WriteLine($"reader={allowed} empty={denied}");
الناتج المتوقع
reader=True empty=False

لا يستوفي المتطلبين إلا القارئ الاصطناعي؛ ولا يشارك رمز أو خط برمجيات وسيطة يعمل داخل مضيف.

المصادقة لا تثبت الملكية

يحدد معرف المسار موردا مطلوبا، لا حق الوصول إليه. حمّل البيانات فقط ضمن تصميم محدود ومصرح للوصول إليها، ثم افرض قواعد المالك والمستأجر والحالة الخاصة بالعملية قبل عرض البيانات أو تعديلها. لا يمنح ادعاء واسع مثل reports.read بالضرورة كل تقرير. ولا تثق بمعرف مستأجر لمجرد أن العميل قدمه.

يمكن للصلاحيات القائمة على المورد استخدام IAuthorizationService مع المورد الفعلي ومعالجات مخصصة. اجعل السياسة وقيود المجال متسقة مع الحالة المحفوظة الحالية. إذا أمكن تغير الحالة بين الفحص والتحديث، فقد يلزم تصميم للتزامن أو المعاملات؛ ففحص منطقي مبكر لا يوفر ضمانا ذريّا عاما للسماح بالكتابة.

اختبر معالج المورد باستخدام مورد صريح

ينفذ البرنامج الثاني مباشرة معالجا يفحص المالك والمستأجر معا. ويقارن عن قصد حالة مسموحة بأخرى ذات مستأجر خاطئ. يتحقق ذلك من قاعدة معالج واحد، لا من رسم السياسات كاملا، أو عزل قاعدة البيانات، أو البرمجيات الوسيطة لنقطة النهاية. على التطبيق الكامل تحديد سياسة الإفصاح عند رفض الوصول أو عدم العثور، واختبارها باتساق.

أبق رسائل الرفض والسجلات مفيدة دون كشف بيانات مستأجر آخر. دقق تغييرات السياسات والاستثناءات المجهولة الهوية. قد يفوت اختبار يقتصر على مسار المدير حالة المستخدم العادي أو العبور بين المستأجرين التي يُنتهك عندها الحد الفعلي.

csharp اختبار المالك والمستأجر مباشرة
using System;
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Authorization;

var user = new ClaimsPrincipal(new ClaimsIdentity(new[] { new Claim(ClaimTypes.NameIdentifier, "u1"), new Claim("tenant", "t1") }, "synthetic"));
var requirement = new OwnerRequirement();
var allowed = new AuthorizationHandlerContext(new[] { requirement }, user, new Report("u1", "t1"));
var wrongTenant = new AuthorizationHandlerContext(new[] { requirement }, user, new Report("u1", "t2"));
var handler = new OwnerHandler();
await handler.HandleAsync(allowed);
await handler.HandleAsync(wrongTenant);
Console.WriteLine($"owner={allowed.HasSucceeded} wrongTenant={wrongTenant.HasSucceeded}");

internal sealed class OwnerRequirement : IAuthorizationRequirement { }
internal sealed record Report(string Owner, string Tenant);
internal sealed class OwnerHandler : AuthorizationHandler<OwnerRequirement, Report>
{
    protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, OwnerRequirement requirement, Report resource)
    {
        if (context.User.FindFirst(ClaimTypes.NameIdentifier)?.Value == resource.Owner && context.User.FindFirst("tenant")?.Value == resource.Tenant)
            context.Succeed(requirement);
        return Task.CompletedTask;
    }
}
الناتج المتوقع
owner=True wrongTenant=False

يمر المورد الاصطناعي ذو المالك والمستأجر المطابقين، ولا يمر المورد ذو المستأجر المختلف.

تحقق من السياسة عند حد العملية العام

اختبر المستدعي المجهول، ومن ثبتت هويته لكنه يفتقد السلطة، والمستخدم العادي المسموح، واختلاف المالك، واختلاف المستأجر، وتغير المورد. أدرج اختيار السياسة وترتيب البرمجيات الوسيطة ضمن تغطية تكامل معزولة. لا يثبت اختبار المعالج المباشر أن نقطة النهاية تتطلب السياسة، أو أن السياسة الاحتياطية قد اختيرت، أو أن challenge وforbid تحولا إلى الاستجابات الصحيحة.

أبق التحقق من الصلاحيات قريبا بما يكفي من الأثر حتى تظل افتراضاته صالحة. لا تخزّن قرارا حساسا مؤقتا دون مدة حياة واضحة للهوية والمورد والإصدار. يجب ألا تتجاوز الخدمات القابلة لإعادة الاستخدام الفحوص خفية لأن المتوقع أن يجريها متحكم؛ بل حدد نقاط الدخول الموثوقة في التطبيق وافرض عقدها.

الأخطاء الشائعة وإصلاحها

يُوثق بمعامل مسار بوصفه مصدرا لسلطة المستأجر.

لماذا يحدث؟
يحل مدخل العميل محل علاقة موثوقة بين الهوية والمورد.
كيف تصلحه؟
اشتق نطاق المستأجر من تصميم صلاحيات متحقق منه.
كيف تتجنب تكراره؟
اختبر الوصول العابر بين المستأجرين صراحة.

يُعد نجاح اختبار المعالج دليلا على حماية نقطة النهاية.

لماذا يحدث؟
لم يُختبر ربط نقطة النهاية بالسياسة والبرمجيات الوسيطة.
كيف تصلحه؟
تحقق من متطلب السياسة العام باختبار تكامل.
كيف تتجنب تكراره؟
اختبر المسارات المجهولة والمسارات التي تفتقد السياسة.

يجيز قرار قديم مخزن مؤقتا حالة مورد تغيرت.

لماذا يحدث؟
تتجاوز مدة حياة القرار صلاحية افتراضاته.
كيف تصلحه؟
استخدم تخزينا مؤقتا محدودا ومدركا للإصدار، أو أعد التقييم قبل الأثر.
كيف تتجنب تكراره؟
راجع إبطال القرارات عند تغير الهوية أو المورد.

اختبر فهمك

1. يحمل مستخدم reports.read ويطلب تقرير مستأجر آخر. لماذا قد لا تكفي سياسة قائمة على الادعاء وحده؟

اعرض الحل المشروح

قد يجيز الادعاء فئة من العمليات دون تحديد موارد المستأجر المسموح بها. افرض نطاق المالك والمستأجر الموثوق مقابل المورد الفعلي وحد الوصول إلى البيانات. اختبر حالة العبور بين المستأجرين دون كشف التقرير. ادعاء القراءة العام ليس منحة شاملة لكل كائن، ويجب أن تكون سياسة حالة HTTP والإفصاح متسقة.

2. لماذا يلزم أحيانا النظر إلى الصلاحيات مع التزامن التفاؤلي؟

اعرض الحل المشروح

قد يتغير مالك المورد أو حالة سير عمله بعد الفحص وقبل التحديث. يستطيع رمز إصدار أو تزامن، أو تصميم معاملات، اكتشاف الكتابات المتقادمة أو تقييدها وفقا لدلالات الموفّر. تظل الصلاحيات هي التي تثبت النية المسموح بها، بينما يحمي التزامن افتراض الحالة. اختبر الاثنين، ولا تدّع أن نتيجة سياسة مبكرة واحدة تجعل عملية قاعدة بيانات لاحقة ذرية.

أهم ما تعلمته

  • الهوية الموثوقة ضرورية، لكنها لا تكفي للوصول إلى المورد.
  • يحتاج اختيار السياسة وقواعد المورد كليهما إلى اختبارات سلبية.
  • يجب أن تلائم مدة حياة القرار الحالة والأثر اللذين يجيزهما.

المراجع الرسمية