تست غیر مخرب

آموزش انواع تست غیر مخرب

تست غیر مخرب

آموزش انواع تست غیر مخرب

سعی می گردد یک سری از آموزش های انواع تست غیر مخرب در این وبلاگ قرار بگیرد

نویسندگان

سفارشی سازی ASP.NET Core Identity - قسمت سوم

چهارشنبه, ۴ اسفند ۱۳۹۵، ۱۲:۳۶ ب.ظ

چندی قبل مطلب «نرمال سازی اطلاعات کاربران در حین ثبت نام» را در سایت جاری مطالعه کردید. پیاده سازی یک چنین قابلیتی به صورت توکار در ASP.NET Core Identity پیش بینی شده‌است. همچنین تمام اعتبارسنج‌های نام‌های کاربران، کلمات عبور آن‌ها، ایمیل‌های آن‌ها و غیره را نیز می‌توان سفارشی سازی کرد و بجای سرویس‌های پیش‌فرض آن‌ها معرفی و جایگزین نمود.


سفارشی سازی نرمال سازها 


اگر به طراحی جداول ASP.NET Core Identity دقت کنید، تعدادی فیلد اضافی حاوی کلمه‌ی Normalized را هم مشاهده خواهید کرد. برای مثال: 




در جدول کاربران، فیلدهای Email و UserName به همراه دو فیلد اضافه‌ی NormalizedEmail و NormalizedUserName وجود دارند.

مقدار دهی و مدیریت این فیلدهای ویژه به صورت خودکار توسط کلاسی به نام UpperInvariantLookupNormalizer صورت می‌گیرد:

public class UpperInvariantLookupNormalizer : ILookupNormalizer

این کلاس اینترفیس ILookupNormalizer را پیاده سازی کرده و تنها کاری را که انجام می‌دهد، تبدیل نام کاربر، نام نقش‌ها و یا ایمیل کاربر به حالت upper case آن است. اما هدف اصلی از آن چیست؟ 

همانطور که در مطلب «نرمال سازی اطلاعات کاربران در حین ثبت نام» نیز عنوان شد، برای مثال ایمیل‌های جی‌میل را می‌توان با چندین حالت مختلف ثبت کرد و یک کاربر به این صورت می‌تواند شرط یکتا بودن آدرس ایمیل‌های تنظیم شده‌ی در کلاس IdentityServicesRegistry را دور بزند:

identityOptionsUser.RequireUniqueEmail = true;

به همین جهت برای سفارشی سازی آن کلاس CustomNormalizer با سفارشی سازی UpperInvariantLookupNormalizer پیاده سازی شده‌است.

چون تنها یک اینترفیس ILookupNormalizer وجود دارد، باید بر اساس محتوای کلیدی که به آن ارسال می‌شود:

public override string Normalize(string key)

تصمیم‌گیری کرد که آیا ایمیل است یا خیر. چون از این نرمال کننده هم برای ایمیل‌ها و هم برای نام‌ها استفاده می‌شود. سپس می‌توان منطق‌های سفارشی خود مانند حذف نقطه‌های اضافی ایمیل‌ها و یا حذف کاراکترهای اضافی اعمالی به نام‌های کاربری را اعمال کرد.

پس از تدارک کلاس CustomNormalizer، تنها کاری را که باید در جهت معرفی و جایگرینی آن انجام داد، تغییر ذیل در کلاس IdentityServicesRegistry است:

services.AddScoped<ILookupNormalizer, CustomNormalizer>();

services.AddScoped<UpperInvariantLookupNormalizer, CustomNormalizer>();

یکبار CustomNormalizer را به عنوان پیاده سازی کننده‌ی ILookupNormalizer معرفی کرده‌ایم. همچنین یکبار هم سرویس توکار UpperInvariantLookupNormalizer را به سرویس سفارشی خودمان هدایت کرده‌ایم. به این ترتیب مطمئن خواهیم شد که همواره از CustomNormalizer ما استفاده خواهد شد.

بنابراین دیگر نیازی نیست تا در حین ثبت‌نام نسبت به تمیزسازی ایمیل‌ها و یا نام‌های کاربری اقدام کنیم. سرویس ILookupNormalizer در پشت صحنه به صورت خودکار در تمام مراحل ثبت نام و به روز رسانی‌ها توسط ASP.NET Core Identity استفاده می‌شود.



سفارشی سازی UserValidator 


ASP.NET Core Identity به همراه یک سرویس توکار اعتبارسنج کاربران است که با پیاده سازی اینترفیس IUserValidator ارائه شده‌است:

public class UserValidator<TUser> : IUserValidator<TUser> where TUser : class

این سرویس پیش‌فرض و توکار، تنظیمات Options.User.RequireUniqueEmail، Options.User.AllowedUserNameCharacters و امثال آن‌را در مورد نام‌های کاربری و ایمیل‌ها بررسی می‌کند (تنظیم شده‌ی در متد setUserOptions کلاس IdentityServicesRegistry).

بنابراین اگر قصد تهیه‌ی یک IUserValidator جدید را داشته باشیم، از تمام تنظیمات و بررسی‌های پیش فرض سرویس توکار UserValidator فوق محروم می‌شویم. به همین جهت برای سفارشی سازی این سرویس، از خود کلاس UserValidator ارث بری کرده و سپس base.ValidateAsync آن‌را فراخوانی می‌کنیم. با این‌کار سبب خواهیم شد تا تمام اعتبارسنجی‌های پیش‌فرض ASP.NET Core Identity اعمال شده و پس از آن منطق‌های سفارشی اعتبارسنجی خود را که در کلاس CustomUserValidator‌ قابل مشاهده هستند، اضافه می‌کنیم.

public override async Task<IdentityResult> ValidateAsync(UserManager<User> manager, User user)

        {

            // First use the built-in validator

            var result = await base.ValidateAsync(manager, user).ConfigureAwait(false);

            var errors = result.Succeeded ? new List<IdentityError>() : result.Errors.ToList();


            // Extending the built-in validator

            validateEmail(user, errors);

            validateUserName(user, errors);


            return !errors.Any() ? IdentityResult.Success : IdentityResult.Failed(errors.ToArray());

        }

در اینجا برای مثال در متد validateEmail سفارشی تهیه شده، لیست یک سری fake email provider اضافه شده‌اند (مدخل EmailsBanList در فایل appsettings.json برنامه) تا کاربران نتوانند از آن‌ها جهت ثبت‌نام استفاده کنند و یا در متد validateUserName سفارشی، اگر نام کاربری برای مثال عددی وارد شده بود، یک new IdentityError بازگشت داده می‌شود.


پس از تدارک کلاس CustomUserValidator، تنها کاری را که باید در جهت معرفی و جایگرینی آن انجام داد، تغییر ذیل در کلاس IdentityServicesRegistry است:

services.AddScoped<IUserValidator<User>, CustomUserValidator>();

services.AddScoped<UserValidator<User>, CustomUserValidator>();

یکبار CustomUserValidator را به عنوان پیاده سازی کننده‌ی IUserValidator معرفی کرده‌ایم. همچنین یکبار هم سرویس توکار UserValidator را به سرویس سفارشی خودمان هدایت کرده‌ایم. به این ترتیب مطمئن خواهیم شد که همواره از CustomUserValidator ما استفاده خواهد شد (حتی اگر UserValidator اصلی از سیستم تزریق وابستگی‌ها درخواست شود).



سفارشی سازی PasswordValidator 


مراحل سفارشی سازی اعتبارسنج کلمات عبور نیز همانند تهیه‌ی CustomUserValidator فوق است.

ASP.NET Core Identity به همراه یک سرویس توکار اعتبارسنج کلمات عبور کاربران است که با پیاده سازی اینترفیس IPasswordValidator ارائه شده‌است:

public class PasswordValidator<TUser> : IPasswordValidator<TUser> where TUser : class

در این کلاس، از اطلاعات متد setPasswordOptions کلاس IdentityServicesRegistry

private static void setPasswordOptions(PasswordOptions identityOptionsPassword, SiteSettings siteSettings)

        {

            identityOptionsPassword.RequireDigit = siteSettings.PasswordOptions.RequireDigit;

            identityOptionsPassword.RequireLowercase = siteSettings.PasswordOptions.RequireLowercase;

            identityOptionsPassword.RequireNonAlphanumeric = siteSettings.PasswordOptions.RequireNonAlphanumeric;

            identityOptionsPassword.RequireUppercase = siteSettings.PasswordOptions.RequireUppercase;

            identityOptionsPassword.RequiredLength = siteSettings.PasswordOptions.RequiredLength;

        }

که از فایل appsettings.json و مدخل PasswordOptions آن تامین می‌شود:

"PasswordOptions": {

   "RequireDigit": false,

   "RequiredLength": 6,

   "RequireLowercase": false,

   "RequireNonAlphanumeric": false,

   "RequireUppercase": false

},

جهت اعتبارسنجی کلمات عبور وارد شده‌ی توسط کاربران در حین ثبت نام و یا به روز رسانی اطلاعات خود، استفاده می‌شود.


بنابراین در اینجا نیز ارائه‌ی یک پیاده سازی خام از IPasswordValidator سبب خواهد شد تا تمام اعتبارسنجی‌های توکار کلاس PasswordValidator اصلی را از دست بدهیم. به همین جهت کار را با ارث بری از همین کلاس توکار شروع کرده و ابتدا متد base.ValidateAsync آن‌را فراخوانی می‌کنیم تا مطمئن شویم، مدخل PasswordOptions تنظیمات یاد شده، حتما پردازش خواهند شد. سپس منطق سفارشی خود را اعمال می‌کنیم.

برای مثال در کلاس CustomPasswordValidator تهیه شده، به مدخل PasswordsBanList فایل appsettings.json مراجعه شده و کاربران را از انتخاب کلمات عبوری به شدت ساده، منع می‌کند.


پس از تدارک کلاس CustomPasswordValidator‌، تنها کاری را که باید در جهت معرفی و جایگرینی آن انجام داد، تغییر ذیل در کلاس IdentityServicesRegistry است:

services.AddScoped<IPasswordValidator<User>, CustomPasswordValidator>();

services.AddScoped<PasswordValidator<User>, CustomPasswordValidator>();

یکبار CustomPasswordValidator را به عنوان پیاده سازی کننده‌ی IPasswordValidator معرفی کرده‌ایم. همچنین یکبار هم سرویس توکار PasswordValidator را به سرویس سفارشی خودمان هدایت کرده‌ایم. به این ترتیب مطمئن خواهیم شد که همواره از CustomPasswordValidator ما استفاده خواهد شد (حتی اگر PasswordValidator اصلی از سیستم تزریق وابستگی‌ها درخواست شود).



پردازش نتایج اعتبارسنج‌ها 


این اعتبارسنج‌ها در خروجی‌های IdentityResult تمام متدهای ASP.NET Core Identity ظاهر می‌شوند. بنابراین فراخوانی ساده‌ی UpdateUserAsync اشتباه است و حتما باید خروجی آن‌را جهت پردازش IdentityResult آن بررسی کرد. به همین جهت تعدادی متد الحاقی به کلاس IdentityExtensions اضافه شده‌اند تا کارکردن با IdentityResult را ساده‌تر کنند.

public static void AddErrorsFromResult(this ModelStateDictionary modelStat, IdentityResult result)

متد AddErrorsFromResult خطاهای حاصل از عملیات ASP.NET Core Identity را به ModelState جاری اضافه می‌کند. به این ترتیب می‌توان این خطاها را به کاربر در Viewهای برنامه و در قسمت اعتبارسنجی مدل آن نمایش داد.


public static string DumpErrors(this IdentityResult result, bool useHtmlNewLine = false)

و یا متد DumpErrors تمام خطاهای موجود در IdentityResult  را تبدیل به یک رشته می‌کند. برای مثال می‌توان این رشته را در Remote validationها مورد استفاده قرار داد.

استفاده‌ی از این متدهای الحاقی را در کنترلرهای برنامه می‌توانید مشاهده کنید.



استفاده‌ی از اعتبارسنج‌ها جهت انجام Remote validation 


اگر به RegisterController دقت کنید، اکشن متدهای ValidateUsername و ValidatePassword قابل مشاهده هستند:

[AjaxOnly, HttpPost, ValidateAntiForgeryToken]

  [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]

  public async Task<IActionResult> ValidateUsername(string username, string email)


[AjaxOnly, HttpPost, ValidateAntiForgeryToken]

  [ResponseCache(Location = ResponseCacheLocation.None, NoStore = true)]

  public async Task<IActionResult> ValidatePassword(string password, string username)

این اکشن متدها توسط سرویس‌های 

IPasswordValidator<User> passwordValidator,

IUserValidator<User> userValidator,

تزریق شده‌ی به سازنده‌ی کلاس، پیاده سازی شده‌اند. در مورد تامین آن‌ها و سفارشی سازی آن‌ها نیز پیشتر بحث شد. این اینترفیس‌ها دقیقا همان وهله‌های CustomUserValidator و CustomPasswordValidator را در اختیار ما قرار می‌دهند. تنها کاری را که باید انجام دهیم، فراخوانی متد ValidateAsync آن‌ها است. این متد یک خروجی از نوع IdentityResult را دارد. به همین جهت متد DumpErrors را برای پردازش این نتیجه تدارک دیدیم.

به این ترتیب کاربران در حین ثبت نام، راهنمای بهتری را جهت انتخاب کلمات عبور و نام کاربری مشاهده خواهند کرد و این بررسی‌ها نیز Ajax ایی هستند و پیش از ارسال فرم نهایی به سرور اتفاق می‌افتند.


برای فعالسازی Remote validation، علاوه بر ثبت اسکریپت‌های Ajax ایی، خواص کلاس RegisterViewModel نیز از ویژگی Remote استفاده می‌کنند:

[Required(ErrorMessage = "(*)")]

  [Display(Name = "نام کاربری")]

  [Remote("ValidateUsername", "Register",

AdditionalFields = nameof(Email) + "," + ViewModelConstants.AntiForgeryToken, HttpMethod = "POST")]

  [RegularExpression("^[a-zA-Z_]*$", ErrorMessage = "لطفا تنها از حروف انگلیسی استفاده نمائید")]

  public string Username { get; set; }


یک نکته: برای اینکه Remote Validation را به همراه ValidateAntiForgeryToken استفاده کنیم، تنها کافی است نام فیلد مخفی آن‌را به لیست AdditionalFields به نحوی که مشاهده می‌کنید، اضافه کنیم.

dotnettips.info
  • ndt web

نظرات  (۰)

هیچ نظری هنوز ثبت نشده است

ارسال نظر

نظر دادن تنها برای اعضای بیان ممکن است.
اگر قبلا در بیان ثبت نام کرده اید لطفا ابتدا وارد شوید، در غیر این صورت می توانید ثبت نام کنید.