سفارشی سازی ASP.NET Core Identity - قسمت چهارم - User Claims
اندازه‌ی قلم متن
تخمین مدت زمان مطالعه‌ی مطلب: هفت دقیقه

از نگارش‌های پیشین ASP.NET، هنوز هم اطلاعات شیء User مانند User.Identity.Name در ASP.NET Core نیز در دسترس هستند. به این ترتیب زمانیکه کاربری به سیستم وارد شد، دیگر نیازی نیست تا جهت یافتن Name او، از بانک اطلاعاتی کوئری گرفت. خاصیت Name یاد شده به صورت خودکار از کوکی رمزنگاری شده‌ی او دریافت شده و در اختیار برنامه قرار می‌گیرد. این Name در ASP.NET Core Identity، اصطلاحا یک User Claim پیش‌فرض نام دارد و به صورت خودکار ایجاد و مقدار دهی می‌شود. اکنون این سؤال مطرح می‌شود که آیا می‌توان خاصیت دیگری را به شیء User.Identity اضافه کرد؟


جدول AppUserClaims


جدول AppUserClaims، جزو جداول اصلی ASP.NET Core Identity است و هدف آن ذخیره‌ی اطلاعات ویژه‌ی کاربران و بازیابی ساده‌تر آن‌ها از طریق کوکی‌های آن‌ها است (همانند User.Identity.Name). زمانیکه کاربری به سیستم وارد می‌شود، بر اساس UserId او، تمام رکوردهای User Claims متعلق به او از این جدول واکشی شده و به صورت خودکار به کوکی او اضافه می‌شوند.

در پروژه‌ی DNT Identity از این جدول استفاده نمی‌شود. چون اطلاعات User Claims مورد نیاز آن، هم اکنون در جدول AppUsers موجود هستند. به همین جهت افزودن این نوع User Claimها به جدول AppUserClaims، به ازای هر کاربر، کاری بیهوده است. سناریویی که استفاده‌ی از این جدول را با مفهوم می‌کند، ذخیره سازی تنظیمات ویژه‌ی هرکاربر است (خارج از فیلدهای جدول کاربران). برای مثال اگر سایتی را چندزبانه طراحی کردید، می‌توانید یک User Claim سفارشی جدید را برای این منظور ایجاد و زبان انتخابی کاربر را به عنوان یک رکورد جدید مخصوص آن در این جدول ویژه ثبت کنید. مزیت آن این است که واکشی و افزوده شدن اطلاعات آن به کوکی شخص، به صورت خودکار توسط فریم ورک صورت گرفته و در حین مرور صفحات توسط کاربر، دیگر نیازی نیست تا اطلاعات زبان انتخابی او را از بانک اطلاعاتی واکشی کرد.
بنابراین برای ذخیره سازی تنظیمات با کارآیی بالای ویژه‌ی هرکاربر، جدول جدیدی را ایجاد نکنید. جدول User Claim برای همین منظور درنظر گرفته شده‌است و پردازش اطلاعات آن توسط فریم ورک صورت می‌گیرد.


ASP.NET Core Identity چگونه اطلاعات جدول AppUserClaims را پردازش می‌کند؟

ASP.NET Identity Core در حین لاگین کاربر به سیستم، از سرویس SignInManager خودش استفاده می‌کند که با نحوه‌ی سفارشی سازی آن پیشتر در قسمت دوم این سری آشنا شدیم. سرویس SignInManager پس از لاگین شخص، از یک سرویس توکار دیگر این فریم ورک به نام UserClaimsPrincipalFactory جهت واکشی اطلاعات User Claims و همچنین Role Claims و افزودن آن‌ها به کوکی رمزنگاری شده‌ی شخص، استفاده می‌کند.
بنابراین اگر قصد افزودن User Claim سفارشی دیگری را داشته باشیم، می‌توان همین سرویس توکار UserClaimsPrincipalFactory را سفارشی سازی کرد (بجای اینکه الزاما رکوردی را به جدول AppUserClaims اضافه کنیم).

اطلاعات جالبی را هم می‌توان از پیاده سازی متد CreateAsync آن استخراج کرد:
  public virtual async Task<ClaimsPrincipal> CreateAsync(TUser user)
1) userId شخص پس از لاگین از طریق User Claims ایی با نوع Options.ClaimsIdentity.UserIdClaimType به کوکی او اضافه می‌شود.
2) userName شخص پس از لاگین از طریق User Claims ایی با نوع Options.ClaimsIdentity.UserNameClaimType به کوکی او اضافه می‌شود.
3) security stamp او (آخرین بار تغییر اطلاعات اکانت کاربر) نیز یک Claim پیش‌فرض است.
4) اگر نقش‌هایی به کاربر انتساب داده شده باشند، تمام این نقش‌ها واکشی شده و به عنوان یک Claim جدید به کوکی او اضافه می‌شوند.
5) اگر یک نقش منتسب به کاربر دارای Role Claim باشد، این موارد نیز واکشی شده و به کوکی او به عنوان یک Claim جدید اضافه می‌شوند. در ASP.NET Identity Core نقش‌ها نیز می‌توانند Claim داشته باشند (امکان پیاده سازی سطوح دسترسی پویا).

بنابراین حداقل مدیریت Claims این 5 مورد خودکار است و اگر برای مثال نیاز به Id کاربر لاگین شده را داشتید، نیازی نیست تا آن‌را از بانک اطلاعاتی واکشی کنید. چون این اطلاعات هم اکنون در کوکی او موجود هستند.


سفارشی سازی کلاس UserClaimsPrincipalFactory جهت افزودن User Claims سفارشی

تا اینجا دریافتیم که کلاس UserClaimsPrincipalFactory کار مدیریت Claims پیش‌فرض این فریم ورک را برعهده دارد. در ادامه از این کلاس ارث بری کرده و متد CreateAsync آن‌را جهت افزودن Claims سفارشی خود بازنویسی می‌کنیم. این پیاده سازی سفارشی را در کلاس ApplicationClaimsPrincipalFactory می‌توانید مشاهده کنید:
        public override async Task<ClaimsPrincipal> CreateAsync(User user)
        {
            var principal = await base.CreateAsync(user).ConfigureAwait(false); 
            addCustomClaims(user, principal);
            return principal;
        }

        private static void addCustomClaims(User user, IPrincipal principal)
        {
            ((ClaimsIdentity) principal.Identity).AddClaims(new[]
            {
                new Claim(ClaimTypes.NameIdentifier, user.Id.ToString(), ClaimValueTypes.Integer),
                new Claim(ClaimTypes.GivenName, user.FirstName ?? string.Empty),
                new Claim(ClaimTypes.Surname, user.LastName ?? string.Empty),
                new Claim(PhotoFileName, user.PhotoFileName ?? string.Empty, ClaimValueTypes.String),
            });
        }
در حین بازنویسی متد CreateAsync، ابتدا base.CreateAsync را فراخوانی کرده‌ایم، تا اخلالی در عملکرد این فریم ورک رخ ندهد و هنوز هم همان مواردی که در قسمت قبل توضیح داده شد، به صورت پیش فرض به کوکی شخص اضافه شوند. سپس در متد addCustomClaims، تعدادی Claim سفارشی خاص خودمان را اضافه کرده‌ایم.
برای مثال نام، نام خانوادگی و نام تصویر شخص به صورت Claimهایی جدید به کوکی او اضافه می‌شوند. در این حالت دیگر نیازی نیست تا به ازای هر کاربر، جدول AppUserClaims را ویرایش کرد و اطلاعات جدیدی را افزود و یا تغییر داد. همینقدر که کاربر به سیستم لاگین کند، شیء User او به متد Create کلاس UserClaimsPrincipalFactory ارسال می‌شود. به این ترتیب می‌توان به تمام خواص این کاربر دسترسی یافت و در صورت نیاز آن‌ها را به صورت Claimهایی به کوکی او افزود.

پس از تدارک کلاس ApplicationClaimsPrincipalFactory‌، تنها کاری را که باید در جهت معرفی و جایگرینی آن انجام داد، تغییر ذیل در کلاس IdentityServicesRegistry است:
services.AddScoped<IUserClaimsPrincipalFactory<User>, ApplicationClaimsPrincipalFactory>();
services.AddScoped<UserClaimsPrincipalFactory<User, Role>, ApplicationClaimsPrincipalFactory>();
یکبار ApplicationClaimsPrincipalFactory را به عنوان پیاده سازی کننده‌ی IUserClaimsPrincipalFactory معرفی کرده‌ایم. همچنین یکبار هم سرویس توکار UserClaimsPrincipalFactory را به سرویس سفارشی خودمان هدایت کرده‌ایم. به این ترتیب مطمئن خواهیم شد که همواره از ApplicationClaimsPrincipalFactory ما استفاده خواهد شد (حتی اگر UserClaimsPrincipalFactory اصلی از سیستم تزریق وابستگی‌ها درخواست شود).
 

چگونه به اطلاعات User Claims در سرویس‌های برنامه دسترسی پیدا کنیم؟

برای دسترسی به اطلاعات User Claims نیاز به دسترسی به HttpContext جاری را داریم. در این مورد و تزریق سرویس IHttpContextAccessor جهت تامین آن، در مطلب «بررسی روش دسترسی به HttpContext در ASP.NET Core» پیشتر بحث شده‌است.
به علاوه در کلاس IdentityServicesRegistry، تزریق وابستگی‌های سفارشی‌تری نیز صورت گرفته‌است:
services.AddScoped<IPrincipal>(provider =>
    provider.GetService<IHttpContextAccessor>()?.HttpContext?.User ?? ClaimsPrincipal.Current);
در اینجا اگر نیاز به اطلاعات Claims شیء User را داشتید، می‌توانید اینترفیس IPrincipal را هم بجای IHttpContextAccessor، به سازنده‌ی کلاس مدنظر خود تزریق کنید.


چگونه اطلاعات User Claims سفارشی را دریافت کنیم؟

برای کار ساده‌تر با Claims یک کلاس کمکی به نام IdentityExtensions به پروژه اضافه شده‌است و متدهایی مانند دو متد ذیل را می‌توانید در آن مشاهده کنید:
        public static string FindFirstValue(this ClaimsIdentity identity, string claimType)
        {
            return identity?.FindFirst(claimType)?.Value;
        }

        public static string GetUserClaimValue(this IIdentity identity, string claimType)
        {
            var identity1 = identity as ClaimsIdentity;
            return identity1?.FindFirstValue(claimType);
        }
در اینجا نحوه‌ی استخراج اطلاعات را از شیء User و یا User.Identity مشاهده می‌کنید. تنها کافی است claimType ایی را درخواست کرده و سپس مقدار آن‌را از کوکی شخص به نحو فوق واکشی کنیم.
برای نمونه متد GetUserDisplayName این کلاس کمکی، از همان Claims سفارشی که در کلاس ApplicationClaimsPrincipalFactory تعریف کردیم، اطلاعات خود را استخراج می‌کند و اگر در View ایی خواستید این اطلاعات را نمایش دهید، می‌توانید بنویسید:
 @User.Identity.GetUserDisplayName()


چگونه پس از ویرایش اطلاعات کاربر، اطلاعات کوکی او را نیز به روز کنیم؟

در پروژه قسمتی وجود دارد جهت ویرایش اطلاعات کاربران (UserProfileController). اگر کاربری برای مثال نام و نام خانوادگی خود را ویرایش کرد، می‌خواهیم بلافاصله متد GetUserDisplayName اطلاعات صحیح و به روزی را از کوکی او دریافت کند. برای اینکار یا می‌توان او را وادار به لاگین مجدد کرد (تا پروسه‌ی رسیدن به متد CreateAsync کلاس ApplicationClaimsPrincipalFactory طی شود) و یا روش بهتری نیز وجود دارد:
 // reflect the changes, in the current user's Identity cookie
await _signInManager.RefreshSignInAsync(user).ConfigureAwait(false);
در اینجا تنها کافی است متد RefreshSignInAsync را مجددا بر اساس اطلاعات ویرایش شده‌ی کاربر، فراخوانی کنیم تا کوکی او را بلافاصله به روز کند و این روش نیازی به اجبار به لاگین مجدد کاربر را ندارد.


کدهای کامل این سری را در مخزن کد DNT Identity می‌توانید ملاحظه کنید.
  • #
    ‫۶ سال و ۱۰ ماه قبل، شنبه ۴ آذر ۱۳۹۶، ساعت ۱۴:۳۷
    با سلام
    در عملیات برگشت درگاه پرداخت در صورت وجود [Athorize] مقادیر برگشتی null است. و  در صورت عدم استفاده از [Athorize]  اطلاعات UserClaim کاربر null است. 
      [Authorize]
     public async Task<IActionResult> CallBackResult(long token, string status, string orderId, string terminalNo, string rrn)
      {
              
       var userId = User.Identity.GetId();
            
       //موفقیت بودن عملیات پرداخت
       if (status == "0" && token > 0)
        {
    
        }
    }


    • #
      ‫۶ سال و ۹ ماه قبل، یکشنبه ۵ آذر ۱۳۹۶، ساعت ۱۳:۴۱
      مفهومی در ASP.NET Core Identity وجود دارد به نام AutomaticAuthenticate و AutomaticChallenge که سبب می‌شوند کاربر با وارد کردن آدرس سایت، به صورت خودکار اعتبارسنجی شود (اگر پیشتر کوکی لاگین او وجود داشته باشد). این موارد برای فعالسازی به تنظیمات ذیل نیاز دارند:
      در متد ConfigureServices:
      services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme);
      و همچنین در متد Configure:
      app.UseAuthentication();
      البته اگر از سیستم Identity استفاده می‌کنید، مورد اول به صورت خودکار با فراخوانی متد AddIdentity تنظیم شده‌است. فقط مورد دوم را هم باید اضافه کنید.

      زمانی متد CallBackResult فراخوانی می‌شود و از فیلتر Authorize رد خواهید شد که کار اعتبارسنجی کاربر با موفقیت صورت گرفته باشد (همان
      AutomaticAuthenticate و AutomaticChallenge فوق). بنابراین اگر تنظیمات اولیه‌ی Identity شما به درستی انجام شده باشد، صرفا مشکل مسیریابی را دارید که مقادیر را نال دریافت می‌کنید.
  • #
    ‫۶ سال و ۴ ماه قبل، چهارشنبه ۱۲ اردیبهشت ۱۳۹۷، ساعت ۰۷:۱۵
    با سلام؛ من از روش فوق برای «اعتبارسنجی مبتنی بر کوکی‌ها در ASP.NET Core 2.0 بدون استفاده از سیستم Identity»استفاده کردم. زمانیکه از کد زیر  استفاده میکنم، مقدارنال رو بر میگرداند. آیا تنظیمات خاصی رو از قلم انداختم. با تشکر
    var userId = user.Identity.GetUserFirstName();
    • #
      ‫۶ سال و ۴ ماه قبل، چهارشنبه ۱۲ اردیبهشت ۱۳۹۷، ساعت ۱۲:۱۸
      در پروژه DNTIdentity یک claim سفارشی برای ClaimTypes.GivenName ایجاد شده‌است (^ و ^). شبیه به همان claim سفارشی را در پروژه‌های دیگر هم باید ایجاد کنید تا متد GetUserFirstName کار کند.
      • #
        ‫۶ سال و ۴ ماه قبل، پنجشنبه ۱۳ اردیبهشت ۱۳۹۷، ساعت ۰۰:۰۸
        تشکر؛ مشکلم حل شد. فقط من در لایه سرویس کد زیر رو استفاده میکنم، user رو نمیشناسه. تو کدهایی که استفاده شد، کتابخانه خاصی جا افتاده؟ شما هم تو لایه وب استفاده کردید. سپاس 
         user.Identity.GetUserFirstName();  
  • #
    ‫۶ سال و ۳ ماه قبل، شنبه ۱۹ خرداد ۱۳۹۷، ساعت ۱۴:۳۲
    با سلام 
    یک سوال
    1. چگونگی استفاده از jwt بجای Cookie در این پروژه  ؟
    • به عبارتی اعتبار سنجی مبتنی بر jwt با استفاده از سیستم asp.net core identity 2.0
  • #
    ‫۵ سال و ۱۱ ماه قبل، سه‌شنبه ۲۴ مهر ۱۳۹۷، ساعت ۱۵:۵۴
    در سناریویی که برای سفارشی سازی Identity داریم باید Claims و Logins و ... رو از User جدا کنیم؛ به این که هر کاربر در نرم افزارهای مختلف دارای Claims متفاوتی است. با Ignore کردن UserId در Claims و ... و تعریف یک کلید جدید باز هم رابطه‌ی بین User و Claims ایجاد می‌شود!
    چگونه باید از ایجاد این ارتباط جلوگیری کرد؟
    تشکر 
    • #
      ‫۵ سال و ۱۱ ماه قبل، سه‌شنبه ۲۴ مهر ۱۳۹۷، ساعت ۱۶:۴۰
      در Context برنامه، یک چنین تعریفی وجود دارد:
          public class ApplicationDbContext :
              IdentityDbContext<User, Role, int, UserClaim, UserRole, UserLogin, RoleClaim, UserToken>,
              IUnitOfWork
          {
              protected override void OnModelCreating(ModelBuilder builder)
              {
                  // it should be placed here, otherwise it will rewrite the following settings!
                  base.OnModelCreating(builder);
      فراخوانی base.OnModelCreating به معنای اعمال تنظیمات پیش‌فرض خود کتابخانه‌ی پایه‌ی Identity است که باید مدنظر باشند.
  • #
    ‫۵ سال و ۱۱ ماه قبل، شنبه ۲۸ مهر ۱۳۹۷، ساعت ۱۸:۰۹
    سلام؛ اگر ممکنه کدهای این متد رو که در ApplicationroleMananger نوشتید رو یه توضیح مختصر در موردشون بدید.
    • #
      ‫۵ سال و ۱۱ ماه قبل، شنبه ۲۸ مهر ۱۳۹۷، ساعت ۱۸:۲۵
      تعدادی رکورد RoleClaim در بانک اطلاعاتی موجود هستند. لیست جدیدی از طرف کاربر ارسال شده‌است. بررسی می‌شود که از این لیست کاربر، چه تعدادی در لیست موجود در بانک اطلاعاتی، وجود ندارند؛ بنابراین باید به صورت رکورد جدید ثبت شوند. سپس بررسی می‌شود از این لیست کاربر، چه تعداد رکورد بانک اطلاعاتی موجود، دیگر انتخاب نشده‌اند و باید حذف شوند.
  • #
    ‫۵ سال و ۹ ماه قبل، جمعه ۲۳ آذر ۱۳۹۷، ساعت ۱۶:۳۵
    آیا وقتی از identity استفاده میکنیم نیازی هست که از JWT برای تولید توکن و پر کردن claim استفاده کنیم ؟ اگر با identity چنین امکانی وجود داره ممنون میشم در موردش توضیحی بدید . 
  • #
    ‫۵ سال و ۶ ماه قبل، شنبه ۱۱ اسفند ۱۳۹۷، ساعت ۱۶:۰۱
    باسلام؛ برای گرفتن لیست Claim‌ها می‌توانیم از this.User.Identity.GetUserClaims استفاده کنیم. اگر بخواهیم لیست Role‌های یک کاربر را بگیریم باید چکار کنیم؟
    • #
      ‫۵ سال و ۶ ماه قبل، شنبه ۱۱ اسفند ۱۳۹۷، ساعت ۱۶:۵۶
      Roleها هم در این سیستم یک User-Claim از نوع ClaimTypes.Role هستند:
      var roles = ((ClaimsIdentity)User.Identity).Claims
                      .Where(c => c.Type == ClaimTypes.Role)
                      .Select(c => c.Value);
  • #
    ‫۵ سال و ۵ ماه قبل، جمعه ۳۰ فروردین ۱۳۹۸، ساعت ۱۹:۳۹
    برای ثبت نام کاربر جدید، خطایی با عنوان "لطفا تنها از حروف انگلیسی استفاده نمائید" صادر میشه، برای حل این خطا کد زیر رو اضافه کردم:
    private static void setUserOptions(UserOptions identityOptionsUser)
            {
                identityOptionsUser.AllowedUserNameCharacters =
                    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+/ ";
                identityOptionsUser.RequireUniqueEmail = true;
            }

    آیا تنظیم خاصی رو از قلم انداختم؟
  • #
    ‫۵ سال و ۴ ماه قبل، چهارشنبه ۱۱ اردیبهشت ۱۳۹۸، ساعت ۱۸:۱۵
    سلام؛ در صورتی که سطح کاربری ما به صورت زیر باشد باید به چه نحوی از Claim استفاده کنیم:
    ادمین سیستم >> ادمین 1 (دسترسی به اطلاعات و زیر مجموعه‌های خود) >> کاربر ارشد (دسترسی به اطلاعات (دیتا)ی ادمین خود و کاربر‌های عادی) >> کاربر عادی (دسترسی فقط به اطلاعات خودش)
    >> ادمین 2 (دسترسی به اطلاعات و زیر مجموعه‌های خود) >> کاربر ارشد (دسترسی به اطلاعات (دیتا)ی ادمین خود و کاربر‌های عادی) >> کاربر عادی (دسترسی فقط به اطلاعات خودش)
    و اینکه آیا به ازای هر ادمین در جدول اطلاعات باید Id ادمین ذخیره گردد یا کاربر؟ 
    • #
      ‫۵ سال و ۴ ماه قبل، چهارشنبه ۱۱ اردیبهشت ۱۳۹۸، ساعت ۱۸:۲۸
      - جائیکه قرار است Roles یا Claims با هم «And» شوند از روش متداول استفاده کنید:
      options.AddPolicy("ElevatedRights", 
         policyBuilder => policyBuilder.RequireRole("Administrator", "PowerUser", "BackupAdministrator"));
      حتی ذکر زنجیروار این‌ها هم یعنی «And»:
      policyBuilder => policyBuilder
          .RequireClaim("VIPNumber")
          .RequireClaim("EmployeeNumber")
          .RequireRole("CEO"));
      - جائیکه قرار است «Or» شوند یا از RequireAssertion هنگام تعریف یک Policy جدید استفاده کنید:
      services.AddAuthorization(options =>
      {
          options.AddPolicy(
              "CanAccessVIPArea",
              policyBuilder => policyBuilder.RequireAssertion(
                  context => context.User.HasClaim(claim => 
                                 claim.Type == "VIPNumber" 
                                 || claim.Type == "EmployeeNumber")
                              || context.User.IsInRole("CEO"))
              );
      });
      - و یا برای حالت‌های پیچیده‌تر، AuthorizationHandler ای را که در قسمت بعدی توضیح داده شده، پیاده سازی کنید.
  • #
    ‫۵ سال و ۱ ماه قبل، شنبه ۵ مرداد ۱۳۹۸، ساعت ۱۹:۰۱
    با سلام. چطور می‌تونم این کد رو طوری تغییر بدم تا پس از اولین بار که claim‌ها رو ایجاد کردیم، سیستم فقط از claim‌ها نقش‌ها بخونه و هیچ کوئری به دیتابیس زده نشه؟ الان به ازای هر نقش کاربر، ما یک سلکت به دیتابیس داریم و این رو بنده می‌خوام فقط و فقط از claim‌ها بخونم.
    • #
      ‫۵ سال و ۱ ماه قبل، شنبه ۵ مرداد ۱۳۹۸، ساعت ۲۰:۱۶
      - این سیستم مدنظر شما نیست؟ اشکالی ندارد! از صفر خودتان آن‌را بنویسید و تنظیم کنید: «اعتبارسنجی مبتنی بر کوکی‌ها در ASP.NET Core 2.0 بدون استفاده از سیستم Identity»
      - در Identity به ازای هر نقش کاربر، یک select به بانک اطلاعاتی وجود ندارد. دقیقا پس از لاگین، اطلاعات User Claims در کوکی شخص به صورت رمزنگاری شده، کش می‌شوند و در دفعات بعدی/درخواست‌های بعدی، از این کوکی خوانده خواهند شد. اما در پروژه‌ی DNT Identity به ازای هر درخواست، طوری تنظیم شده تا وضعیت اعتبار کاربر، بررسی شود و اینکار توسط تنظیم enableImmediateLogout و ValidationInterval = TimeSpan.Zero آن انجام می‌شود. چرا؟ چون اگر در سمت سرور، کاربری را غیرفعال کردید، آیا باید تا زمان منقضی شدن اعتبار کوکی آن، بتواند از سایت استفاده کند؟ بله. این مورد هزینه‌ی اعتبارسنجی User Claims و در نتیجه، کوئری گرفتن از بانک اطلاعاتی را به ازای هر درخواست، به همراه دارد؛ ولی ضروری است. یعنی این سیستم صرفا هر کوکی را که شامل یکسری User Claims باشد، معتبر نمی‌داند.
  • #
    ‫۴ سال و ۳ ماه قبل، دوشنبه ۵ خرداد ۱۳۹۹، ساعت ۰۵:۵۹
    با سلام؛ چرا در متد addCustomClaims  دوباره userId به Claim‌ها اضافه شده؟
    • #
      ‫۴ سال و ۳ ماه قبل، دوشنبه ۵ خرداد ۱۳۹۹، ساعت ۰۶:۱۶
      مثال هست.
  • #
    ‫۱ سال و ۹ ماه قبل، جمعه ۲۷ آبان ۱۴۰۱، ساعت ۱۲:۵۳
    با سلام؛ یه پروژه انجام میدم بر اساس DNT Identity مشکلی که دارد زمان طولانی build پروژه است. هر بار که build میکنم حدود 2 الی 3 دقیقه طول میکشد تا عملیات build انجام شود که اذیت کننده است. آیا روشی برای کاهش زمان build پروژه وجود دارد؟
    • #
      ‫۱ سال و ۹ ماه قبل، جمعه ۲۷ آبان ۱۴۰۱، ساعت ۲۲:۳۹
      - فعال شدن آنالایزرها را بر اساس debug و یا release تنظیم کنید. وجود آن‌ها build را کند می‌کنند.
      - ارتقاء سخت افزاری را هم فراموش نکنید. اگر 3 دقیقه طول می‌کشد، یعنی نیاز به یک سیستم بهتر هست و ... در سایت دیوار موارد دست دوم خوبی را با 4 میلیون تومان می‌توانید پیدا کنید که نمونه‌ی نو آن‌ها شاید بالای 20 میلیون تومن قیمت داشته باشند.
  • #
    ‫۱ سال و ۷ ماه قبل، سه‌شنبه ۱۳ دی ۱۴۰۱، ساعت ۱۴:۵۵
    سلام و خسته نباشید
    آیا راهی هست که کاربر ادمین بتواند logoff را برای سایر کاربران انجام دهد بطوریکه که کاربر مربوطه را مجبور به لاگین مجدد نماید