از نگارش ASP.NET Core Identity 2.1 به بعد، ویژگی جدید ProtectedPersonalData در تعاریف موجودیت کاربرانسیستم مشاهده میشود:
این ویژگی در حقیقت یک نشانهگذار است. کار آن اعلام نیاز به ذخیره سازی رمزنگاری شدهی اینگونه اطلاعات در بانک اطلاعاتی، جهت محافظت از اطلاعات شخصی کاربران سیستم، در حین دسترسیهای غیرمجاز میباشد.
روش فعالسازی ذخیره سازی رمزنگاری شدهی اطلاعات شخصی کاربران
اگر برنامهی پیشین خود را به نگارشهای جدیدتر ASP.NET Core Identity ارتقاء داده باشید، احتمالا متوجه وجود یک چنین قابلیتی نشدهاید؛ چون به صورت پیشفرض غیرفعال است. برای فعالسازی آن، میتوان به صورت زیرعمل کرد:
ویژگی ProtectedPersonalData چگونه به صورت خودکار پردازش میشود؟
پیشنیاز درک نحوهی پردازش ویژگی ProtectedPersonalData، مطلب «رمزنگاری خودکار فیلدها توسط Entity Framework Core» است. در اینجا نیز دقیقا یک «تبدیلگر مقدار» برای رمزنگاری و رمزگشایی خودکار فیلدهای مزین به ProtectedPersonalData تدارک دیده شدهاست:
سپس در IdentityUserContext تعریف شدهو متد OnModelCreating آن، ابتدا بررسی میکند که آیا پیشتر ProtectPersonalData را به true تنظیم کردهاید یا خیر؟ اگر بله، تمام خواصی را که با ویژگی ProtectedPersonalDataAttribute مزین شدهاند، یافته و سپس توسط متد HasConversion به آنها تبدیلگر مقداری از نوع PersonalDataConverter را اضافه میکند:
سرویس پیشفرض IPersonalDataProtector در ASP.NET Core Identity
اگر در کدهای فوق، به جائیکه new PersonalDataConverter نوشته شده دقت کنید؛ یک سرویس از نوع IPersonalDataProtectorرا دریافت میکند که توسط آن دو متد Protect و Unprotect به کلاس خصوصی PersonalDataConverter تزریق میشوند:
پیاده سازی پیشفرض این سرویس رمزنگاری را در اینجامیتوانید مشاهده کنید.
تاثیر فعالسازی ProtectPersonalData بر روی سایر سرویسهای ASP.NET Core Identity
اگر options.Stores.ProtectPersonalData را به true تنظیم کنید، سرویس UserManager اینبار انتظار خواهد داشتکه IUserStore ای که به آن تزریق میشود، از نوع جدید IProtectedUserStore باشد؛ در غیراینصورت یک استثناء را صادر میکند:
که البته اگر از UserStore ای با امضای زیراستفاده میکنید، IProtectedUserStore را هم پیاده سازی کردهاست:
همچنین تمام متدهای سرویس UserManager که با خواص مزین شدهی به [ProtectedPersonalData] کار میکنند، جهت استفادهی از متد ProtectPersonalData به روز رسانی شدهاند:
چگونه میتوان بجای DefaultPersonalDataProtectorپیشفرض، از یک نمونهی سفارشی استفاده کرد؟
برای انجام اینکار نیاز است ILookupProtector خودتان را نوشته و به سیستم معرفی کنید. یک نمونه از پیاده سازی سفارشی آنرا در پروژهی AspNetCoreIdentityEncryptionمیتوانید مشاهده نمائید.
public class IdentityUser<TKey> where TKey : IEquatable<TKey> { [ProtectedPersonalData] public virtual string UserName { get; set; } [ProtectedPersonalData] public virtual string Email { get; set; }
روش فعالسازی ذخیره سازی رمزنگاری شدهی اطلاعات شخصی کاربران
اگر برنامهی پیشین خود را به نگارشهای جدیدتر ASP.NET Core Identity ارتقاء داده باشید، احتمالا متوجه وجود یک چنین قابلیتی نشدهاید؛ چون به صورت پیشفرض غیرفعال است. برای فعالسازی آن، میتوان به صورت زیرعمل کرد:
services.AddIdentity<IdentityUser, IdentityRole>(options => { options.Stores.ProtectPersonalData = true; // ... })
ویژگی ProtectedPersonalData چگونه به صورت خودکار پردازش میشود؟
پیشنیاز درک نحوهی پردازش ویژگی ProtectedPersonalData، مطلب «رمزنگاری خودکار فیلدها توسط Entity Framework Core» است. در اینجا نیز دقیقا یک «تبدیلگر مقدار» برای رمزنگاری و رمزگشایی خودکار فیلدهای مزین به ProtectedPersonalData تدارک دیده شدهاست:
private class PersonalDataConverter : ValueConverter<string, string> { public PersonalDataConverter(IPersonalDataProtector protector) : base(s => protector.Protect(s), s => protector.Unprotect(s), default) { } }
سپس در IdentityUserContext تعریف شدهو متد OnModelCreating آن، ابتدا بررسی میکند که آیا پیشتر ProtectPersonalData را به true تنظیم کردهاید یا خیر؟ اگر بله، تمام خواصی را که با ویژگی ProtectedPersonalDataAttribute مزین شدهاند، یافته و سپس توسط متد HasConversion به آنها تبدیلگر مقداری از نوع PersonalDataConverter را اضافه میکند:
protected override void OnModelCreating(ModelBuilder builder) { var encryptPersonalData = storeOptions?.ProtectPersonalData ?? false; builder.Entity<TUser>(b => { if (encryptPersonalData) { converter = new PersonalDataConverter(this.GetService<IPersonalDataProtector>()); var personalDataProps = typeof(TUser).GetProperties().Where( prop => Attribute.IsDefined(prop, typeof(ProtectedPersonalDataAttribute))); foreach (var p in personalDataProps) { if (p.PropertyType != typeof(string)) { throw new InvalidOperationException(Resources.CanOnlyProtectStrings); } b.Property(typeof(string), p.Name).HasConversion(converter); } } // ...
اگر در کدهای فوق، به جائیکه new PersonalDataConverter نوشته شده دقت کنید؛ یک سرویس از نوع IPersonalDataProtectorرا دریافت میکند که توسط آن دو متد Protect و Unprotect به کلاس خصوصی PersonalDataConverter تزریق میشوند:
public interface IPersonalDataProtector { string Protect(string data); string Unprotect(string data); }
تاثیر فعالسازی ProtectPersonalData بر روی سایر سرویسهای ASP.NET Core Identity
اگر options.Stores.ProtectPersonalData را به true تنظیم کنید، سرویس UserManager اینبار انتظار خواهد داشتکه IUserStore ای که به آن تزریق میشود، از نوع جدید IProtectedUserStore باشد؛ در غیراینصورت یک استثناء را صادر میکند:
if (Options.Stores.ProtectPersonalData) { if (!(Store is IProtectedUserStore<TUser>)) { throw new InvalidOperationException(Resources.StoreNotIProtectedUserStore); } if (services.GetService<ILookupProtector>() == null) { throw new InvalidOperationException(Resources.NoPersonalDataProtector); } }
public class UserStore<TUser, TRole, TContext, TKey, TUserClaim, TUserRole, TUserLogin, TUserToken, TRoleClaim> : ...
همچنین تمام متدهای سرویس UserManager که با خواص مزین شدهی به [ProtectedPersonalData] کار میکنند، جهت استفادهی از متد ProtectPersonalData به روز رسانی شدهاند:
public virtual async Task UpdateNormalizedUserNameAsync(TUser user) { var normalizedName = NormalizeName(await GetUserNameAsync(user)); normalizedName = ProtectPersonalData(normalizedName); await Store.SetNormalizedUserNameAsync(user, normalizedName, CancellationToken); }
چگونه میتوان بجای DefaultPersonalDataProtectorپیشفرض، از یک نمونهی سفارشی استفاده کرد؟
برای انجام اینکار نیاز است ILookupProtector خودتان را نوشته و به سیستم معرفی کنید. یک نمونه از پیاده سازی سفارشی آنرا در پروژهی AspNetCoreIdentityEncryptionمیتوانید مشاهده نمائید.