Реализуйте методы get / set для пользовательского свойства Identity User - PullRequest
0 голосов
/ 20 февраля 2020

Я использую Identity и расширил базовый IdentityUser тремя пользовательскими свойствами. Использование .netCore 3.1.1 и удостоверения 4

namespace FleetLogix.Intranet.Identity
{
    // Add profile data for application users by adding properties to the ApplicationUser class
    public class ApplicationUser : IdentityUser<int>
    {
        [MaxLength(50)]
        [PersonalData]
        public string FirstName { get; set; }

        [MaxLength(50)]
        [PersonalData]
        public string LastName { get; set; }

        [MaxLength(5)]
        public string OrgCode { get; set; }

        public ApplicationUser() : base()
        {

        }


    }
}

Они были успешно созданы в таблице [AspNetUsers]. Было создано 4 начальных пользователя со всеми дополнительными свойствами.

Я также создал несколько расширений, которые позволяют мне получать значения этих свойств. FirstName -> GivenName, LastName -> Surname и OrgCode - это CustomClaimTypes.OrgCode

namespace FleetLogix.Intranet.Identity
{
    /// <summary>
    /// Extends the <see cref="System.Security.Principal.IIdentity" /> object to add accessors for our custom properties.
    /// </summary>
    public static class IdentityExtensions
    {
        /// <summary>
        /// Gets the value of the custom user property FirstName
        /// </summary>
        /// <example>
        /// User.Identity.GetFirstName()
        /// </example>
        /// <param name="identity">Usually the Identity of the current logged in User</param>
        /// <returns><see langword="string"/> containing value of LastName or an empty string</returns>
        public static string GetFirstName(this IIdentity identity)
        {
            ClaimsIdentity claimsIdentity = identity as ClaimsIdentity;
            Claim claim = claimsIdentity?.FindFirst(ClaimTypes.GivenName);

            return claim?.Value ?? string.Empty;
        }

        /// <summary>
        /// Gets the value of the custom user property LastName
        /// </summary>
        /// <example>
        /// User.Identity.GetLastName()
        /// </example>
        /// <param name="identity">Usually the Identity of the current logged in User</param>
        /// <returns><see langword="string"/> containing value of LastName or an empty string</returns>
        public static string GetLastName(this IIdentity identity)
        {
            ClaimsIdentity claimsIdentity = identity as ClaimsIdentity;
            Claim claim = claimsIdentity?.FindFirst(ClaimTypes.Surname);

            return claim?.Value ?? string.Empty;
        }


        /// <summary>
        /// Gets the value of the custom user property OrgCode
        /// </summary>
        /// <example>
        /// User.Identity.GetOrgCode()
        /// </example>
        /// <param name="identity">Usually the Identity of the current logged in User</param>
        /// <returns><see langword="string"/> containing value of OrgCode or an empty string</returns>
        public static string GetOrgCode(this IIdentity identity)
        {
            ClaimsIdentity claimsIdentity = identity as ClaimsIdentity;
            Claim claim = claimsIdentity?.FindFirst(CustomClaimTypes.OrgCode);

            return claim?.Value ?? string.Empty;
        }
    }
}

Я настраиваю новый сайт и хочу изменить _LoginPartial.cshtml. Я хочу заменить отображение зарегистрированного имени пользователя (адрес электронной почты) на имя пользователя FirstName

@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
    <a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @UserManager.GetUserName(User)!</a> 
    </li>
   ...
}

на это

@if (SignInManager.IsSignedIn(User))
{
    <li class="nav-item">
    <a id="manage" class="nav-link text-dark" asp-area="Identity" asp-page="/Account/Manage/Index" title="Manage">Hello @User.Identity.GetFirstName()!</a> 
    </li>
   ...
}

, однако это приводит к пустому тексту. Почему этот пробел?

При переходе на страницу Account/Manage/Index мне представляется форма для изменения данных пользователя. Я изменил InputModel, чтобы включить два пользовательских свойства (FirstName, LastName). Задача LoadAsync была изменена для загрузки значений (с использованием методов расширения) и добавления их в `InputModel

private async Task LoadAsync(ApplicationUser user)
{

    var userName = await _userManager.GetUserNameAsync(user);
    var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
    var firstName =  user.FirstName;
    var lastName = user.LastName;
    var orgCode = user.OrgCode;


    Username = userName;

    OrgCode = orgCode;

    Input = new InputModel
    {
        PhoneNumber = phoneNumber,
        FirstName = firstName,
        LastName = lastName

    };
}

Screenshot of User Modify page

Почему пользовательские свойства видны на этой странице, а не на предыдущей?

Далее в Account/Manage/Index указан метод обновления OnPostAsync()

public async Task<IActionResult> OnPostAsync()
{
   var user = await _userManager.GetUserAsync(User);
   if (user == null)
   {
       return NotFound($"Unable to load user with ID '{_userManager.GetUserId(User)}'.");
   }

   if (!ModelState.IsValid)
   {
       await LoadAsync(user);
       return Page();
   }

   var phoneNumber = await _userManager.GetPhoneNumberAsync(user);
   if (Input.PhoneNumber != phoneNumber)
   {
       var setPhoneResult = await _userManager.SetPhoneNumberAsync(user, Input.PhoneNumber);
       if (!setPhoneResult.Succeeded)
       {
           var userId = await _userManager.GetUserIdAsync(user);
           throw new InvalidOperationException($"Unexpected error occurred setting phone number for user with ID '{userId}'.");
       }
   }

   var firstName = user.FirstName; //.GetPhoneNumberAsync(user);
   if (Input.FirstName != firstName)
   {
       //var setFirstNameResult = await _userManager.SetFirstNameAsync(user, Input.FirstName);
       user.FirstName = Input.FirstName;
       //if (!setFirstNameResult.Succeeded)
       //{
       //    var userId = await _userManager.GetUserIdAsync(user);
       //    throw new InvalidOperationException($"Unexpected error occurred setting First Name for user with ID '{userId}'.");
       //}
   }


   var lastName = user.LastName;
   if (Input.LastName != lastName)
   {
       //var setLastNameResult = await _userManager.SetLastNameAsync(user, Input.LastName);
       user.LastName = Input.LastName;
       //if (!setLastNameResult.Succeeded)
       //{
       //    var userId = await _userManager.GetUserIdAsync(user);
       //    throw new InvalidOperationException($"Unexpected error occurred setting Last Name for user with ID '{userId}'.");
       //}
   }

   await _signInManager.RefreshSignInAsync(user);
   StatusMessage = "Your profile has been updated";
   return RedirectToPage();
}

Без методов Set как SetPhoneNumberAsync() Я пытался использовать свойство setter. Это не сработало. Как обновить значения пользовательских свойств Identity User?

Я просто хочу иметь возможность использовать пользовательские свойства пользователя. Мне нужно, чтобы свойство FirstName & OrgCode было доступно, как только они войдут в систему, что в настоящее время не так. Текущие методы расширения не всегда работают.

Кроме того, мне нужно иметь возможность редактировать эти свойства в случае, если они являются ошибками или изменились требования.

1 Ответ

0 голосов
/ 20 февраля 2020

Вам необходимо создать область идентификатора, просто создайте свою идентификацию и добавьте область действия

services.AddScoped<IUserIdentity, UserIdentity>();

Вам необходимо реализовать middleware для сопоставления всех ваших свойств в идентификаторе. Добавить в стартап:

app.UseMiddleware<UserIdentityAccessor>();

Реализация:

    public class UserIdentityAccessor
    {
        private readonly RequestDelegate _next;

        public UserIdentityAccessor(RequestDelegate next)
        {
            _next = next;
        }

        public async Task InvokeAsync(HttpContext context, IUserIdentity userIdentity)
        {
            var user = (ClaimsIdentity) context.User.Identity;

            if (user.IsAuthenticated)
            {
                var first = user.FindFirst(ClaimsName.FirstName).Value; \\ get info from claims
                userIdentity.FirstName = first;                         \\ and add to identity
            }
            else
            {
                userIdentity.FirstName = null;
            }

            await _next(context);
        }
    }

И теперь вы можете получить личность где угодно

...