نظرات مطالب
از سرگیری مجدد، لغو درخواست و سعی مجدد دریافت فایل‌های حجیم توسط HttpClient
یک نکته‌ی تکمیلی: پشتیبانی توکار ASP.NET Core 2.0 از Range headers

فرض کنید برای آزمایش قسمت «از سرگیری مجدد» دریافت یک فایل حجیم مطلب جاری، یک چنین کدی را در یک برنامه‌ی ASP.NET Core 2.0 تهیه کرده‌اید:
    public class HomeController : Controller
    {
        public IActionResult GetFile()
        {
            return PhysicalFile(@"C:\path\file.pdf", "application/pdf");
        }
در مورد PhysicalFile در مطلب «تغییرات متدهای بازگشت فایل‌ها به سمت کلاینت در ASP.NET Core» بیشتر بحث شده‌است.
اجرای این کد به همراه هدر مخصوص «Accept-Ranges: bytes » که در مطلب جاری در مورد آن بحث شد نیز هست:


یعنی دریافت فایل‌ها در ASP.NET Core 2.0 به صورت توکار از ویژگی «از سرگیری مجدد» پشتیبانی می‌کند. قابلیتی که در نگارش‌های پیشین ASP.NET (تمام نگارش‌های آن‌)، به صورت پیش‌فرض و توکار وجود نداشت و برای پیاده سازی آن می‌بایستی مقدار زیادی کد نوشته می‌شد.
در اینجا return File، FileStreamResult و VirtualFileResult نیز از ویژگی partial range requests پشتیبانی می‌کنند. همچنین حتی اگر از static files middleware آن نیز استفاده کنید، یک چنین قابلیتی را پیاده سازی کرده‌است.
به علاوه تمام متدهای بازگشت فایل، پارامتر enableRangeProcessing را نیز به همراه دارند:
var result = new FileStreamResult(readStream, contentType)
{
                LastModified = lastModified,
                EntityTag = entityTag,
                EnableRangeProcessing = true,
};

 return PhysicalFile(path, "text/plain", "downloadName.txt", lastModified, entityTag, true);

 return File(data, "text/plain", "downloadName.txt", lastModified: null, entityTag: entityTag,
    enableRangeProcessing: true);
اشتراک‌ها
StringSimilarity.NET؛ کتابخانه‌ی الگوریتم‌هایی برای یافتن رشته‌های مشابه

A library implementing different string similarity and distance measures. A dozen of algorithms (including Levenshtein edit distance and sibblings, Jaro-Winkler, Longest Common Subsequence, cosine similarity etc.) are currently implemented. Check the summary table below for the complete list... 

StringSimilarity.NET؛ کتابخانه‌ی الگوریتم‌هایی برای یافتن رشته‌های مشابه
اشتراک‌ها
سری مقدماتی NET Core.

Day 1 - Installing and Running .NET Core on a Windows Box
Day 2 - Taking a Look at the Visual Studio Templates for .NET Core
Day 3 - Running a .NET Core app on a Mac
Day 4 - Creating a NuGet Package from .NET Core app
Day 5 - Creating a Test Project from .NET Core
Day 6 - Migrating an existing .NET Core to csproj
Day 7 - Creating an ASP.NET Core Web Application 

سری مقدماتی NET Core.
اشتراک‌ها
اعتبارسنجی کاربران بدون هاردکد کردن نقشها

You already know how role-based authorization works in ASP.NET Core.

[Authorize(Roles = "Administrator")]
public class AdministrationController : Controller
{
}

But what if you don't want hardcode roles on the Authorize attribute or create roles later and specify in which controller and action it has access without touching source code?

DynamicAuthorization helps you authorize users without hardcoding role(s) on the Authorize attribute with minimum effort. DynamicAuthorization is built at the top of ASP.NET Core Identity and use identity mechanism for managing roles and authorizing users. 

اعتبارسنجی کاربران بدون هاردکد کردن نقشها
اشتراک‌ها
روش صحیح استفاده از ASP.NET Identity، بدون وابستگی Domain و سایر لایه ها به آن

The Problem

What they neglect to say is all that testability and persistence ignorance flies right out the window when you create a new ASP.NET Web Application using the MVC template and "Individual User Accounts" authentication. What you get is a single-layered application, tightly coupled to Entity Framework, that:

  • Ignores the patterns that facilitate testing, including: the repository pattern, unit of work pattern, and dependency injection;

  • Forces you to implement their IUser interface in your application’s User entity, thereby coupling it to ASP.NET Identity;

  • Eliminates any clear separation between your entities, persistence concerns, and business logic. Persistence ignorance? Forget about it.

Thankfully, due to the extensibility designed into ASP.NET Identity, it is possible to ditch the reference to the Microsoft.AspNet.Identity.EntityFramework assembly and write a custom implementation that can address these and other architectural issues. Just be forewarned: it is not a trivial undertaking, and you’ll have to put up with some code smell that is baked into the Microsoft.AspNet.Identity.Core assembly. 

روش صحیح استفاده از ASP.NET Identity، بدون وابستگی Domain و سایر لایه ها به آن
مطالب
اعمال کنترل دسترسی پویا در پروژه‌های ASP.NET Core با استفاده از AuthorizationPolicyProvider سفارشی

در مطلب «سفارشی سازی ASP.NET Core Identity - قسمت پنجم - سیاست‌های دسترسی پویا» به طور مفصل به قضیه کنترل دسترسی پویا در ASP.NET Core Identity پرداخته شده‌است؛ در این مطلب روش دیگری را بررسی خواهیم کرد.

مشخص می‌باشد که بدون وابستگی به روش خاصی، خیلی ساده می‌توان به شکل زیر عمل کرد:

services.AddAuthorization(options =>
{
    options.AddPolicy("View Projects", 
        policy => policy.RequireClaim(CustomClaimTypes.Permission, "projects.view"));
});
با یک ClaimType مشخص برای دسترسی‌ها، یک سیاست جدید را تعریف کرده و برای استفاده از آن نیز همانند قبل به شکل زیر می‌توان عمل کرد:
[Authorize("View Projects")]
public IActionResult Index(int siteId)
{
    return View();
}
روشی یکپارچه و بدون نیاز به کوچکترین سفارشی سازی؛ ولی در مقیاس بزرگ تعریف سیاست‌ها برای تک تک دسترسی‌های مورد نیاز، قطعا آزار دهنده خواهد بود. خبر خوب اینکه زیرساخت احراز هویت و کنترل دسترسی در ASP.NET Core مکانیزمی برای خودکار کردن فرآیند تعریف options.AddPolicy‌ها در کلاس آغازین برنامه، ارائه داده‌است که دقیقا یکی از موارد استفاده‌ی آن، راه حلی می‌باشد برای همین مشکلی که مطرح شد.
Using a large range of policies (for different room numbers or ages, for example), so it doesn’t make sense to add each individual authorization policy with an AuthorizationOptions.AddPolicy call. 


کار با پیاده سازی واسط IAuthorizationPolicyProvider شروع می‌شود؛ یا شاید ارث بری از DefaultAuthorizationPolicyProvider رجیستر شده‌ی در سیستم DI و توسعه آن هم کافی باشد.

public class AuthorizationPolicyProvider : DefaultAuthorizationPolicyProvider
{
    public AuthorizationPolicyProvider(IOptions<AuthorizationOptions> options)
        : base(options)
    {
    }

    public override Task<AuthorizationPolicy> GetPolicyAsync(string policyName)
    {
        if (!policyName.StartsWith(PermissionAuthorizeAttribute.PolicyPrefix, StringComparison.OrdinalIgnoreCase))
        {
            return base.GetPolicyAsync(policyName);
        }

        var permissionNames = policyName.Substring(PermissionAuthorizeAttribute.PolicyPrefix.Length).Split(',');

        var policy = new AuthorizationPolicyBuilder()
            .RequireClaim(CustomClaimTypes.Permission, permissionNames)
            .Build();

        return Task.FromResult(policy);
    }
}

متد GetPolicyAsync موظف به یافتن و بازگشت یک Policy ثبت شده می‌باشد؛ با این حال می‌توان با بازنویسی آن و با استفاده از وهله‌ای از AuthorizationPolicyBuilder، فرآیند تعریف سیاست درخواست شده را که احتمالا در تنظیمات آغازین پروژه تعریف نشده و پیشوند مدنظر را نیز دارد، خوکار کرد. در اینجا امکان ترکیب کردن چندین دسترسی را هم خواهیم داشت که برای این منظور می‌توان دسترسی‌های مختلف را به صورت comma separated به سیستم معرفی کرد. 

نکته‌ی مهم در تکه کد بالا مربوط است به PolicyPrefix که با استفاده از آن مشخص کرده‌ایم که برای هر سیاست درخواستی، این فرآیند را طی نکند و موجب اختلال در سیستم نشود. 


پس از پیاده سازی واسط مطرح شده، لازم است این پیاده سازی جدید را به سیستم DI هم معرفی کنید:

services.AddSingleton<IAuthorizationPolicyProvider, AuthorizationPolicyProvider>();


خوب، تا اینجا فرآیند تعریف سیاست‌ها به صورت خودکار انجام شد. در ادامه نیاز است با تعریف یک فیلتر Authorization، بتوان لیست دسترسی‌های مورد نظر برای اکشنی خاص را نیز مشخص کرد تا در متد GetPolicyAsync فوق، کار ثبت خودکار سیاست دسترسی متناظر با آن‌را توسط فراخوانی متد policyBuilder.RequireClaim، انجام دهد تا دیگر نیازی به تعریف دستی و جداگانه‌ی آن، در کلاس آغازین برنامه نباشد. برای این منظور به شکل زیر عمل خواهیم کرد:

    public class PermissionAuthorizeAttribute : AuthorizeAttribute
    {
        internal const string PolicyPrefix = "PERMISSION:";

        /// <summary>
        /// Creates a new instance of <see cref="AuthorizeAttribute"/> class.
        /// </summary>
        /// <param name="permissions">A list of permissions to authorize</param>
        public PermissionAuthorizeAttribute(params string[] permissions)
        {
            Policy = $"{PolicyPrefix}{string.Join(",", permissions)}";
        }
    }

همانطور که مشخص می‌باشد، رشته PERMISSION به عنوان پیشوند رشته تولیدی از لیست اسامی دسترسی‌ها، استفاده شده‌است و در پراپرتی Policy قرار داده شده‌است. این بار برای کنترل دسترسی می‌توان به شکل زیر عمل کرد:

[PermissionAuthorize(PermissionNames.Projects_View)]
public IActionResult Get(FilteredQueryModel query)
{
   //...
}
[PermissionAuthorize(PermissionNames.Projects_Create)]
public IActionResult Post(ProjectModel model)
{
   //...
}

برای مثال در اولین فراخوانی فیلتر PermissionAuthorize فوق، مقدار ثابت PermissionNames.Projects_View به عنوان یک Policy جدید به متد GetPolicyAsync کلاس AuthorizationPolicyProvider سفارشی ما ارسال می‌شود. چون دارای پیشوند «:PERMISSION» است، مورد پردازش قرار گرفته و توسط متد policyBuilder.RequireClaim به صورت خودکار به سیستم معرفی و ثبت خواهد شد.


همچنین راه حل مطرح شده برای مدیریت دسترسی‌های پویا، در gist به اشتراک گذاشته شده «موجودیت‌های مرتبط با مدیریت دسترسی‌های پویا» را نیز مد نظر قرار دهید.