如何扩展 UserManager.FindByEmail()?

问题描述 投票:0回答:1

我的登录方法如下,您会看到在使用

_userManager.FindByEmailAsync()
获取用户后,我必须再次调用我的用户,因为有几个字段
Points
Tokens
计算为
Sum()

问题 - 有什么方法可以扩展

_userManager.FindByEmailAsync()
,以便它像我在
Sum
调用中那样运行
.Select()
,这样我就不会对数据库进行冗余调用?

我尝试打电话:

var userFromRepo = await _userManager.Users.Select(p => new Core.Entities.User { Id = p.Id, Email = p.Email, UserName = p.UserName}).SingleOrDefaultAsync(p => p.Email == loginDto.Email);

并将其传递给

CheckPasswordSignInAsync()
但结果失败,因此它正在寻找除电子邮件、用户名或 ID 之外的其他内容。但什么?

如果我只是调用它来返回整个

User

var userFromRepo = await _userManager.Users.SingleOrDefaultAsync(p => p.Email == loginDto.Email);

它可以工作,但我无法运行

Sum()
调用
Point
Token

我也尝试过像这样扩展 UserManager,但没有成功。

public static User FindByEmail(this UserManager <User> input, string email) {
  return input.Users.Select(p => new User {
    Id = p.Id,
      Email = p.Email,
      UserName = p.UserName
  }).SingleOrDefault(x => x.Email == email);
}

这是我的登录方法。

[AllowAnonymous]
[HttpPost("login")]
public async Task<IActionResult> Login(LoginDto loginDto) {
  
  var userFromRepo = await _userManager.FindByEmailAsync(loginDto.Email);

  if (userFromRepo == null) return Unauthorized(new ApiResponse(401));

  if (userFromRepo.IsActive == false) return NotFound(new ApiResponse(404, "This account is no longer active."));

  var result = await _signInManager.CheckPasswordSignInAsync(userFromRepo, loginDto.Password, false);

  if (!result.Succeeded) return Unauthorized(new ApiResponse(401));

  var user = await _dbContext.Users
    .Select(p => new {
        Id = p.Id,
        Email = p.Email,
        UserName = p.UserName,
        Hosted = p.Hosted,
        Instructed = p.Instructed,
        Attended = p.Attended,
        IsBoarded = p.IsBoarded,
        IsActive = p.IsActive,
        Likers = p.LikersCount,
        Rating = p.Rating,
        YearStarted = p.YearStarted,
        YearsInstructing = p.YearsInstructing,
        YearsPracticing = System.DateTime.Now.Year - p.YearStarted,
        Certification = p.Certification.ToString(),
        CreatedDate = p.CreatedDate,
        PhotoUrl = p.IsBoarded ? p.UserPhoto : "assets/images/user.png",
        Age = p.DateOfBirth.CalculateAge(),
        DateOfBirth = p.DateOfBirth,
        ExperienceLevel = p.ExperienceLevel.GetEnumName(),
        Points = p.UserPoints.Sum(p => p.Points),
        Tokens = p.Tokens.Sum(p => p.Tokens),
        Token = _tokenService.CreateToken(userFromRepo, (from userRole in p.UserRoles join role in _dbContext.Roles on userRole.RoleId equals role.Id select role.Name).ToList()),
        IsInstructor = p.IsInstructor
    })
    .FirstOrDefaultAsync(p => p.Id == userFromRepo.Id);

  if (user == null) return NotFound(new ApiResponse(404));

  return Ok(user);
}

c# asp.net-core .net-core asp.net-identity usermanager
1个回答
-1
投票

如果要扩展

_userManager.FindByEmailAsync
方法,则需要创建一个继承
IUserEmailStore
的自定义类,因为
FindByEmailAsync
方法将调用 IUserEmailStore 的 FindByEmailAsync 方法。

_userManager
的源代码是这样的:

public virtual async Task<TUser?> FindByEmailAsync(string email)
{
    ThrowIfDisposed();
    IUserEmailStore<TUser> store = GetEmailStore();
    Microsoft.AspNetCore.Shared.ArgumentNullThrowHelper.ThrowIfNull(email, "email");
    email = NormalizeEmail(email);
    TUser val = await store.FindByEmailAsync(email, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
    if (val == null && Options.Stores.ProtectPersonalData)
    {
        ILookupProtectorKeyRing service = _services.GetService<ILookupProtectorKeyRing>();
        ILookupProtector protector = _services.GetService<ILookupProtector>();
        if (service != null && protector != null)
        {
            foreach (string allKeyId in service.GetAllKeyIds())
            {
                string normalizedEmail = protector.Protect(allKeyId, email);
                val = await store.FindByEmailAsync(normalizedEmail, CancellationToken).ConfigureAwait(continueOnCapturedContext: false);
                if (val != null)
                {
                    return val;
                }
            }
        }
    }

    return val;
}

在新实现的 IUserEmailStore 类中,您可以修改 FindByEmailAsync,如下所示:

_dbContext.Users
            .Where(u => u.Email == email)
            .Select(p => new UserDto
            {
                Id = p.Id,
                Email = p.Email,
                UserName = p.UserName,
                Hosted = p.Hosted,
                Instructed = p.Instructed,
                Attended = p.Attended,
                IsBoarded = p.IsBoarded,
                IsActive = p.IsActive,
                Likers = p.LikersCount,
                Rating = p.Rating,
                YearStarted = p.YearStarted,
                YearsInstructing = p.YearsInstructing,
                YearsPracticing = DateTime.Now.Year - p.YearStarted,
                Certification = p.Certification.ToString(),
                CreatedDate = p.CreatedDate,
                PhotoUrl = p.IsBoarded ? p.UserPhoto : "assets/images/user.png",
                Age = p.DateOfBirth.CalculateAge(),
                DateOfBirth = p.DateOfBirth,
                ExperienceLevel = p.ExperienceLevel.GetEnumName(),
                Points = p.UserPoints.Sum(up => up.Points),
                Tokens = p.Tokens.Sum(t => t.Tokens),
                Token = _tokenService.CreateToken(p, 
                    (from userRole in p.UserRoles
                     join role in _dbContext.Roles on userRole.RoleId equals role.Id
                     select role.Name).ToList()),
                IsInstructor = p.IsInstructor
            })
            .FirstOrDefaultAsync();

然后在程序.cs里面注册:

builder.Services.AddTransient<IUserEmailStore<ApplicationUser>, CustomUserEmailStore>();

更详细的使用方法,可以参考这篇文章

© www.soinside.com 2019 - 2024. All rights reserved.