نظرات مطالب
سفارشی سازی ASP.NET Core Identity - قسمت پنجم - سیاست‌های دسترسی پویا
ربطی به هم ندارند. دو فناوری مستقل هستند. هرچند می‌توان در IDP از Identity core برای مدیریت کاربران هم استفاده کرد. اطلاعات بیشتر
البته بدون مرور کامل سری «امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x»  قادر به درک مستندات رسمی آن و مطلب فوق نخواهید شد.
نظرات مطالب
اعمال تزریق وابستگی‌ها به مثال رسمی ASP.NET Identity
- UpdateSecurityStamp دقیقا همین کار را انجام می‌دهد. اجبار به اعتبارسنجی مجدد کوکی و در صورت نیاز، لاگین مجدد، پس از تغییر قسمت‌های مهم اکانت شخص.
- روش دیگر آ‌ن‌را برای NET Core. در اینجا توضیح دادم: «سفارشی سازی ASP.NET Core Identity - قسمت چهارم - User Claims» . قسمت «چگونه پس از ویرایش اطلاعات کاربر، اطلاعات کوکی او را نیز به روز کنیم؟ » 
اشتراک‌ها
نحوه‌ی آفلاین کردن یک سایت ASP.NET 5 برای تعمیرات

ASP.NET 2.0 introduced a concept of application offline. This mean that when there is App_Offline.htm file in the root of a web application directory then ASP.NET will shut-down the application, unload the application domain from the server, and stop processing any new incoming requests for that application. In ASP.NET 5, there is an open-issue for supporting this feature. 

نحوه‌ی آفلاین کردن یک سایت ASP.NET 5 برای تعمیرات
مطالب
شروع به کار با DNTFrameworkCore - قسمت 1 - معرفی و نحوه استفاده از آن

پروژه DNTFrameworkCore  که قصد پشتیبانی از آن را دارم، یک زیرساخت سبک وزن و توسعه پذیر با پشتیبانی از طراحی چند مستاجری، با تمرکز بر کاهش زمان و افزایش کیفیت توسعه سیستم‌های تحت وب مبتنی بر ASP.NET Core، توسعه داده شده است. 


اهدافی که این زیرساخت دنبال می‌کند

  • ارائه ساختارهای مشترک بین پروژه‌های مختلف از جمله Cross-Cutting Concern‌ها و ...
  • دنبال کردن اصل DRY به منظور متمرکز شدن صرف برروی منطق تجاری سیستم نه انجام و حل یکسری مسائل تکراری
  • کاهش زمان توسعه و اختصاص زمان بیشتر برای نوشتن آزمون‌های واحد منطق تجاری
  • کاهش باگ و جلوگیری از پخش شدن باگ‌های پیاده سازی در سراسر سیستم
  • کاهش زمان آموزش نیروهای جدید برای ملحق شدن به تیم تولید شما با حداقل دانش طراحی و برنامه نویسی شیء گرا
  • ارائه راهکاری یکپارچه برای توسعه پذیر بودن منطق تجاری پیاده سازی شده از طریق در معرض دید قرار دادن یکسری «Extensibility Point» با استفاده از رویکرد Event-Driven


امکانات این زیرساخت در زمان نگارش مطلب جاری


نحوه استفاده از بسته‌های نیوگت مرتبط

PM> Install-Package DNTFrameworkCore -Version 1.0.0
 services.AddDNTFramework()
     .AddDataAnnotationValidation()
     .AddModelValidation()
     .AddValidationOptions(options =>
     {
         /*options.IgnoredTypes.Add(typeof());*/
     })
     .AddMemoryCache()
     .AddAuditingOptions(options =>
     {
         // options.Enabled = true;
         // options.EnabledForAnonymousUsers = false;
         // options.IgnoredTypes.Add(typeof());
         // options.Selectors.Add(new NamedTypeSelector("SelectorName", type => type == typeof()));
     }).AddTransactionOptions(options =>
     {
         // options.Timeout=TimeSpan.FromMinutes(3);
         //options.IsolationLevel=IsolationLevel.ReadCommitted;
     });

متدهای الحاقی بالا برای ثبت سرویس‌ها و تنظیمات مرتبط با مکانیزم‌های اعتبارسنجی خودکار، مدیریت تراکنش‌ها، لاگ آماری، Eventing و سایر امکانات ذکر شده، در IoC Container  توکار ASP.NET Core استفاده خواهند شد.

PM> Install-Package DNTFrameworkCore.EntityFramework -Version 1.0.0
services.AddDNTUnitOfWork<ProjectDbContext>();

‎بسته نیوگت بالا شامل پیاده سازی مبتنی بر EF Core برای واسط‌های تعریف شده در بسته نیوگت DNTFrameworkCore، می‌باشد؛ از جمله آن می‌توان به CrudService پایه اشاره کرد.  متد الحاقی AddDNTUnitOfWork برای ثبت و معرفی واسط‌های IUnitOfWork و ITransactionProvider به عنوان مهیا کننده تراکنش به همراه پیاده سازهای آنها و همچنین ثبت یک سری Hook تعریف شده برای ردیابی تغییرات، در سیستم تزریق وابستگی، استفاده خواهد شد.

همچنین با نصب بسته بالا، امکان استفاده از مهیا کننده Logging با امکان ذخیره سازی در بانک اطلاعاتی را خواهید داشت:

 public static IWebHostBuilder CreateWebHostBuilder(string[] args) =>
            WebHost.CreateDefaultBuilder(args)
                .UseDefaultServiceProvider((context, options) =>
                {
                    options.ValidateScopes = context.HostingEnvironment.IsDevelopment();
                })
                .ConfigureLogging((hostingContext, logging) =>
                {
                    logging.AddConfiguration(hostingContext.Configuration.GetSection("Logging"));
                    logging.AddConsole();
                    logging.AddDebug();
                    logging.AddEntityFramework<ProjectDbContext>(options => options.MinLevel = LogLevel.Warning);
                })
                .UseStartup<Startup>();

متد جنریک الحاقی AddEntityFramework برای ثبت مهیا کننده مذکور استفاده می‌شود. 

PM> Install-Package DNTFrameworkCore.Web -Version 1.0.0

بسته نیوگت بالا شامل یکسری سرویس برای اعمال دسترسی‌های پویا، CrudController مبتنی بر ASP.NET Core Web API، فیلتر مدیریت سراسری خطاهای برنامه و سایر امکاناتی که در ادامه مقالات با جزئیات بیشتری بررسی خواهیم کرد، می‌باشد. برای ثبت سرویس‌های تعریف شده می‌توانید از متد الحاقی AddDNTCommonWeb و به منظور تغییر محل ذخیره سازی کلیدهای موقت رمزنگاری مرتبط با Data Protection API و انتقال آنها به بانک اطلاعاتی، استفاده کنید. 

services.AddDNTCommonWeb()
    .AddDNTDataProtection();

نکته: برای انتقال کلیدهای موقت رمزنگاری به بانک اطلاعاتی، نیاز است تا از متد الحاقی زیر که در بسته نیوگت DNTFrameworkCore.EntityFramework موجود می‌باشد، به شکل زیر استفاده کنید:

services.AddDNTProtectionRepository<ProjectDbContext>();

‎‎

اگر نیاز به شماره گذاری خودکار دارید، بسته زیر را نیز می‌بایست نصب کنید:
PM> Install-Package DNTFrameworkCore.EntityFramework.SqlServer -Version 1.0.0

بسته بالا از امکانات مخصوص SqlServer برای اعمال قفل منطقی برای مدیریت مباحث همزمانی استفاده می‌کند؛ همچنین PreUpdateHook مرتبط با تولید خودکار کد منحصر به فرد، در این کتابخانه پیاده سازی شده است. به شکل زیر می‌توانید سرویس‌های مرتبط با آن را به سیستم تزریق وابستگی‌های معرفی کنید:

services.AddDNTNumbering(options =>
{
    options.NumberedEntityMap[typeof(Task)] = new NumberedEntityOption
    {
        Start = 100,
        Prefix = "Task-",
        IncrementBy = 5
    };
});

‎‎به عنوان مثال برای شماره گذاری موجودیت Task، لازم است تنظیمات مرتبط آن را به شکل بالا به سیستم شماره گذاری معرفی کنید.

اگر قصد استفاده از کتابخانه FluentValidation را داشته باشید، می‌بایست بسته زیر را نیز نصب کنید:

PM> Install-Package DNTFrameworkCore.FluentValidation -Version 1.0.0  

برای ثبت و معرفی Adapter مرتبط، به سیستم اعتبارسنجی خودکار معرفی شده، لازم است از طریق متد الحاقی AddFluentModelValidation به شکل زیر اقدام کنید:

 services.AddDNTFramework()
     .AddDataAnnotationValidation()
     .AddModelValidation()
     .AddFluentModelValidation()
     .AddValidationOptions(options =>
     {
         /*options.IgnoredTypes.Add(typeof());*/
     })
     .AddMemoryCache()
     .AddAuditingOptions(options =>
     {
         // options.Enabled = true;
         // options.EnabledForAnonymousUsers = false;
         // options.IgnoredTypes.Add(typeof());
         // options.Selectors.Add(new NamedTypeSelector("SelectorName", type => type == typeof()));
     }).AddTransactionOptions(options =>
     {
         // options.Timeout=TimeSpan.FromMinutes(3);
         //options.IsolationLevel=IsolationLevel.ReadCommitted;
     });

‎‎

برای شروع پروژه جدید، نصب این بسته‌ها کفایت می‌کند. اگر نیاز به طراحی MultiTenancy دارید، بسته زیر را برای شناسایی Tenant جاری و از این قبیل کارها نیز می‌بایست نصب کنید:

PM> Install-Package DNTFrameworkCore.Web.MultiTenancy -Version 1.0.0
برای ثبت و معرفی ITenantResolver شخصی سازی شده خود، می‌توانید از متد الحاقی زیر استفاده کنید:
services.AddMultiTenancy<TenantResolver>();
همچنین نیاز است با استفاده از متد الحاقی زیر، Middleware تعریف شده در کتابخانه را به «HTTP Request Pipeline» سیستم معرفی کرده و ثبت کنید:
app.UseMultiTenancy();
نکته: بسته نیوگت DNTFrameworkCore.Web.MultitTenancy به منظور مهیا کردن طول عمر Tenant-Singleton، وابستگی به کتابخانه StructureMap نیز دارد. البته این بسته نیاز به بهبود هم دارد که در ادامه اعمال خواهد شد. همچنین امضای متدهای الحاقی بالا، در انتشارهای بعدی به AddDNTMultiTenancy و UseDNTMultiTenancy تغییر خواهند کرد.
در نهایت به منظور تزئین خودکار و پویای سرویس‌های برنامه برای اعمال یکسری Cross-Cutting Concern معرفی شده در بالا، از جمله اعتبارسنجی ورودی‌ها، مدیریت تراکنش‌ها و ... می‌توانید پس از ثبت و معرفی سرویس‌های خود به سیستم تزریق وابستگی توکار، با استفاده از Interceptor‌های پیاده سازی شده در زیرساخت، به شکل زیر اقدام کنید:
services.Scan(scan => scan
    .FromCallingAssembly()
    .AddClasses(classes => classes.AssignableTo<ISingletonDependency>())
    .AsMatchingInterface()
    .WithSingletonLifetime()
    .AddClasses(classes => classes.AssignableTo<IScopedDependency>())
    .AsMatchingInterface()
    .WithScopedLifetime()
    .AddClasses(classes => classes.AssignableTo<ITransientDependency>())
    .AsMatchingInterface()
    .WithTransientLifetime()
    .AddClasses(classes => classes.AssignableTo(typeof(IDomainEventHandler<>)))
    .AsImplementedInterfaces()
    .WithTransientLifetime());

foreach (var descriptor in services.Where(s => typeof(IApplicationService).IsAssignableFrom(s.ServiceType))
    .ToList())
{
    services.Decorate(descriptor.ServiceType, (target, serviceProvider) =>
        ProxyGenerator.CreateInterfaceProxyWithTargetInterface(
            descriptor.ServiceType,
            target, serviceProvider.GetRequiredService<ValidationInterceptor>(),
            (IInterceptor) serviceProvider.GetRequiredService<TransactionInterceptor>()));
}
به عنوان مثال در اینجا از ValidationInterceptor و TransactionInterceptor استفاده شده است.

پروژه نمونه‌ای هم برای نمایش امکانات زیرساخت را از اینجا می توانید دریافت کنید.
آزمون‌های واحد مرتبط با قسمت هایی از این زیرساخت را نیز می‌توانید در اینجا مشاهده کنید.
نظرات مطالب
سفارشی سازی ASP.NET Core Identity - قسمت اول - موجودیت‌های پایه و DbContext برنامه
فلسفه‌ی وجودی «اعتبارسنجی مبتنی بر کوکی‌ها در ASP.NET Core 2.0 » و همچنین «اعتبارسنجی مبتنی بر JWT در ASP.NET Core 2.0 » فراهم آوردن زیر ساختی برای طراحی یک سیستم مستقل اعتبارسنجی، شبیه به ASP.NET Core Identity هست. چون سیستم Identity به صورت پیش‌فرض از همین زیرساخت مبتنی بر کوکی‌ها استفاده می‌کند. برای مثال اگر می‌خواهید با JWT کار کنید و مدیریت کاربران را توسط Idnetity انجام دهید، اینکار برای مثال توسط متد signInManager.PasswordSignInAsync آن قابل انجام نیست؛ چون پس از پایان کار لاگین، یک کوکی را تنظیم می‌کند و نه یک توکن‌را.
نظرات مطالب
امن سازی برنامه‌های ASP.NET Core توسط IdentityServer 4x - قسمت ششم - کار با User Claims
همه نکات رو بررسی کردم. البته موضوع اینکه من اومدم IdentityServer رو در کنار Asp.net Identity استفاده کردم و دیتای user  رو از جدول مربوطه میخونم و عملیات لاگین رو هم به شکل زیر انجام دادم . 
  if (ModelState.IsValid)
        {
            // find user by username
            var user = await _signInManager.UserManager.FindByNameAsync(Input.Username);

            // validate username/password using ASP.NET Identity
            if (user != null && (await _signInManager.CheckPasswordSignInAsync(user, Input.Password, true)) == SignInResult.Success)
            {
                await _events.RaiseAsync(new UserLoginSuccessEvent(user.UserName, user.Id, user.UserName, clientId: context?.Client.ClientId));

                // only set explicit expiration here if user chooses "remember me". 
                // otherwise we rely upon expiration configured in cookie middleware.
                AuthenticationProperties props = null;
                if (LoginOptions.AllowRememberLogin && Input.RememberLogin)
                {
                    props = new AuthenticationProperties
                    {
                        IsPersistent = true,
                        ExpiresUtc = DateTimeOffset.UtcNow.Add(LoginOptions.RememberMeLoginDuration)
                    };
                };

                // issue authentication cookie with subject ID and username
                var isuser = new IdentityServerUser(user.Id)
                {
                    DisplayName = user.UserName
                };

                await HttpContext.SignInAsync(isuser, props);

                if (context != null)
                {
                    if (context.IsNativeClient())
                    {
                        // The client is native, so this change in how to
                        // return the response is for better UX for the end user.
                        return this.LoadingPage(Input.ReturnUrl);
                    }

                    // we can trust model.ReturnUrl since GetAuthorizationContextAsync returned non-null
                    return Redirect(Input.ReturnUrl);
                }

                // request for a local page
                if (Url.IsLocalUrl(Input.ReturnUrl))
                {
                    return Redirect(Input.ReturnUrl);
                }
                else if (string.IsNullOrEmpty(Input.ReturnUrl))
                {
                    return Redirect("~/");
                }
                else
                {
                    // user might have clicked on a malicious link - should be logged
                    throw new Exception("invalid return URL");
                }
            }

            await _events.RaiseAsync(new UserLoginFailureEvent(Input.Username, "invalid credentials", clientId: context?.Client.ClientId));
            ModelState.AddModelError(string.Empty, LoginOptions.InvalidCredentialsErrorMessage);
        }
ممکنه به خاطر این مورد باشه که sub رو تو claim ندارم.؟
مگر غیر اینکه با تعریف new IdentityResources.OpenId در IdentityResources و تنظیم AllowScope کلاینت به IdentityServerConstants.StandardScopes.OpenId خود IdentityServer الزاما SubjectId رو در claim به ما برگردونه؟