用户登录ASP.NET Core Identity期间出现空异常

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

我对 ASP.NET Core 相当陌生。我正在开发一个简单的社交媒体网络应用程序,并决定将身份添加到我现有的用户中。我在登录用户时遇到问题。登录和注册方法都会出现此问题。在

Register
方法中,用户实际上被添加到数据库中。

Database

但是当尝试使用相同的方法登录时,我得到以下信息:

ArgumentNullException: Value cannot be null. (Parameter 'value')
System.ArgumentNullException.Throw(string paramName)

System.ArgumentNullException.ThrowIfNull(object argument, string paramName)  
System.Security.Claims.Claim..ctor(string type, string value, string valueType, string issuer, string originalIssuer, ClaimsIdentity subject, string propertyKey, string propertyValue)  
System.Security.Claims.Claim..ctor(string type, string value)
Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory<TUser>.GenerateClaimsAsync(TUser user)  
Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory<TUser, TRole>.GenerateClaimsAsync(TUser user)  
Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory<TUser>.CreateAsync(TUser user)   
Microsoft.AspNetCore.Identity.SignInManager<TUser>.CreateUserPrincipalAsync(TUser user)  
Microsoft.AspNetCore.Identity.SignInManager<TUser>.SignInWithClaimsAsync(TUser user, AuthenticationProperties authenticationProperties, IEnumerable<Claim> additionalClaims)  
Microsoft.AspNetCore.Identity.SignInManager<TUser>.SignInOrTwoFactorAsync(TUser user, bool isPersistent, string loginProvider, bool bypassTwoFactor)  
Microsoft.AspNetCore.Identity.SignInManager<TUser>.PasswordSignInAsync(TUser user, string password, bool isPersistent, bool lockoutOnFailure)  
Microsoft.AspNetCore.Identity.SignInManager<TUser>.PasswordSignInAsync(string userName, string password, bool isPersistent, bool lockoutOnFailure)  
ImagiArtInfrastructure.Controllers.AccountController.Login(LoginViewModel model) in AccountController.cs

我的应用程序已经有

User
模型类,因此我将缺少的表添加到数据库中。

Database

我当前的

User
模型,继承自
IdentityUser

using Microsoft.AspNetCore.Identity;

namespace ImagiArtInfrastructure;

public partial class User : IdentityUser<int>
{
    public virtual ICollection<Comment> Comments { get; set; } = new List<Comment>();

    public virtual ICollection<Like> Likes { get; set; } = new List<Like>();
    
    public virtual ICollection<Post> Posts { get; set; } = new List<Post>();

    public virtual ICollection<UserFollower> UserFollowerFollowers { get; set; } = new List<UserFollower>();

    public virtual ICollection<UserFollower> UserFollowerUsers { get; set; } = new List<UserFollower>();
}

注册及登录方法:

[HttpPost]
public async Task<IActionResult> Register(RegisterViewModel model)
{
    if (ModelState.IsValid)
    {
        User user = new User
        {
            Email = model.Email,
            UserName = model.Email
        };

        var result = await _userManager.CreateAsync(user, model.Password);

        if (result.Succeeded)
        {
            // cookies
            // This line causes the exception
            await _signInManager.SignInAsync(user, false);
            return RedirectToAction("Index", "Home");
        }
        else
        {
            foreach (var error in result.Errors)
            {
                ModelState.AddModelError(string.Empty, error.Description);
            }
        }
    }

    return View(model);
}

[HttpGet]
public IActionResult Login(string? returnUrl = null)
{
    returnUrl ??= "/";
    return View(new LoginViewModel { ReturnUrl = returnUrl });
}

[HttpPost]
[ValidateAntiForgeryToken]
public async Task<IActionResult> Login(LoginViewModel model)
{
    if (ModelState.IsValid)
    {
        // This line causes the exception too
        var result =
        await _signInManager.PasswordSignInAsync(model.Email, model.Password, model.RememberMe, false);

        if (result.Succeeded)
        {
            if (!string.IsNullOrEmpty(model.ReturnUrl) && Url.IsLocalUrl(model.ReturnUrl))
            {
                return Redirect(model.ReturnUrl);
            }
            else
            {
                return RedirectToAction("Index", "Home");
            }
        }
        else
        {
            ModelState.AddModelError("", "Invalid login credentials");
        }
    }
    return View(model);
}

Program.cs

using ImagiArtInfrastructure;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

var builder = WebApplication.CreateBuilder(args);

// Add services to the container.
builder.Services.AddControllersWithViews();
builder.Services.AddDbContext<CloneContext>(option => option.UseSqlServer(
    builder.Configuration.GetConnectionString("DefaultConnection")
    ));

// Adding Identity
builder.Services.AddIdentity<User, IdentityRole<int>>().AddEntityFrameworkStores<CloneContext>();

var app = builder.Build();

// Configure the HTTP request pipeline.
if (!app.Environment.IsDevelopment())
{
    app.UseExceptionHandler("/Home/Error");
    // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
    app.UseHsts();
}

app.UseHttpsRedirection();
app.UseStaticFiles();

app.UseAuthentication();
app.UseRouting();
app.UseAuthorization();

app.MapControllerRoute(
    name: "default",
    pattern: "{controller=Home}/{action=Index}/{id?}");

app.Run();

数据库上下文:

using Microsoft.AspNetCore.Identity.EntityFrameworkCore;
using Microsoft.AspNetCore.Identity;
using Microsoft.EntityFrameworkCore;

namespace ImagiArtInfrastructure;

public partial class CloneContext : IdentityDbContext<User, IdentityRole<int>, int>
{
    public CloneContext()
    {
    }

    public CloneContext(DbContextOptions<CloneContext> options)
    : base(options)
    {
        Database.EnsureCreated();
    }
    public virtual DbSet<Comment> Comments { get; set; }

    public virtual DbSet<Like> Likes { get; set; }

    public virtual DbSet<Post> Posts { get; set; }

    public virtual DbSet<UserFollower> UserFollowers { get; set; }

    // Warning  CS0114  'CloneContext.Users' hides inherited member 'IdentityUserContext<User, int, IdentityUserClaim<int>, IdentityUserLogin<int>, IdentityUserToken<int>>.Users'.
    // if Users is uncommented
    //public virtual DbSet<User> Users { get; set; }

    protected override void OnConfiguring(DbContextOptionsBuilder optionsBuilder)
        => optionsBuilder.UseSqlServer("Server=DESKTOP-6SAKF27\\SQLEXPRESS; Database=Clone; Trusted_Connection=True; TrustServerCertificate=True; ");

    protected override void OnModelCreating(ModelBuilder modelBuilder)
    {
        base.OnModelCreating(modelBuilder);

        modelBuilder.Entity<Comment>(entity =>
        {
            entity.HasKey(e => e.CommentId).HasName("PK__Comments__E7957687FE981422");

            entity.Property(e => e.Caption)
                .HasMaxLength(64)
                .HasColumnName("caption");
            entity.Property(e => e.PostId).HasColumnName("post_id");
            entity.Property(e => e.UserId).HasColumnName("user_id");

            entity.HasOne(d => d.Post).WithMany(p => p.Comments)
                .HasForeignKey(d => d.PostId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("comments_post_id_foreign");

            entity.HasOne(d => d.User).WithMany(p => p.Comments)
                .HasForeignKey(d => d.UserId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_Comments_AspNetUsers");
        });

        modelBuilder.Entity<Like>(entity =>
        {
            entity.HasKey(e => e.LikeId).HasName("PK__Likes__992C79308223B6DD");

            entity.Property(e => e.PostId).HasColumnName("post_id");
            entity.Property(e => e.UserId).HasColumnName("user_id");

            entity.HasOne(d => d.Post).WithMany(p => p.Likes)
                .HasForeignKey(d => d.PostId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("likes_post_id_foreign");

            entity.HasOne(d => d.User).WithMany(p => p.Likes)
                .HasForeignKey(d => d.UserId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_Likes_AspNetUsers");
        });

        modelBuilder.Entity<Post>(entity =>
        {
            entity.HasKey(e => e.PostId).HasName("PK__Posts__3ED78766917B0BC9");

            entity.Property(e => e.Caption)
                .HasMaxLength(32)
                .HasColumnName("caption");
            entity.Property(e => e.Description)
                .HasMaxLength(64)
                .HasColumnName("description");
            entity.Property(e => e.ImageUrl)
                .HasMaxLength(50)
                .IsUnicode(false)
                .HasColumnName("image_url");
            entity.Property(e => e.UserId).HasColumnName("user_id");

            entity.HasOne(d => d.User).WithMany(p => p.Posts)
                .HasForeignKey(d => d.UserId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_Posts_AspNetUsers");
        });

        modelBuilder.Entity<UserFollower>(entity =>
        {
            entity.HasKey(e => e.UserFollowId).HasName("PK__UserFoll__15A691442B4B1096");

            entity.Property(e => e.FollowerId).HasColumnName("follower_id");
            entity.Property(e => e.UserId).HasColumnName("user_id");

            entity.HasOne(d => d.Follower).WithMany(p => p.UserFollowerFollowers)
                .HasForeignKey(d => d.FollowerId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_UserFollowers_AspNetUsers1");

            entity.HasOne(d => d.User).WithMany(p => p.UserFollowerUsers)
                .HasForeignKey(d => d.UserId)
                .OnDelete(DeleteBehavior.ClientSetNull)
                .HasConstraintName("FK_UserFollowers_AspNetUsers");
        });

        modelBuilder.Entity<User>(entity =>
        {
            entity.Property(e => e.Id).ValueGeneratedNever();
            entity.Property(e => e.Email).HasMaxLength(256);
            entity.Property(e => e.NormalizedEmail).HasMaxLength(256);
            entity.Property(e => e.NormalizedUserName).HasMaxLength(256);
            entity.Property(e => e.UserName).HasMaxLength(256);
        });

        OnModelCreatingPartial(modelBuilder);
    }

    partial void OnModelCreatingPartial(ModelBuilder modelBuilder);
}

我尝试调试以查看到底是什么原因造成的。

SignInManager class Microsoft.AspNetCore.Identity

/// <summary>
/// Creates a <see cref="ClaimsPrincipal"/> for the specified <paramref name="user"/>, as an asynchronous operation.
/// </summary>
/// <param name="user">The user to create a <see cref="ClaimsPrincipal"/> for.</param>
/// <returns>The task object representing the asynchronous operation, containing the ClaimsPrincipal for the specified user.</returns>
public virtual async Task<ClaimsPrincipal> CreateUserPrincipalAsync(TUser user) => await ClaimsFactory.CreateAsync(user); // ClaimsFactory.CreateAsync(user) causes the exception

我注意到用户参数在任何地方都正确传递,所以不知道是什么原因造成的。

asp.net-core entity-framework-core asp.net-core-mvc asp.net-core-8
1个回答
0
投票

安全地假设

Id
User
属性是主键,您将实例化新的
User
,而无需一个:

User user = new User
{
  Email = model.Email,
  UserName = model.Email
};

因为不会为该密钥自动生成任何值,并且您也没有在代码中设置值:

modelBuilder.Entity<User>(entity =>
{
  entity.Property(e => e.Id).ValueGeneratedNever();
  ...
});

删除上述配置应该可以解决问题。

更新:另外,请将您的自定义类重命名为例如

ApplicationUser
AppUser

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