c# - Blazor + MongoDb 身份 : Value cannot be null.(参

你能帮帮我吗?我正在尝试将 Blazor 与 MongoDb Identity 一起使用,并且总是出现异常:值不能为空。 (参数名称“来源”)当我调用 signInManager.SignInAsync(user, false);

MongoDB 服务器版本:4.2.5

ASP.Net Core 3.1

NuGet 包: AspNetCore.Identity.Mongo:6.7.0 MongoDB.驱动程序:2.10.3

准备步骤: 1. 创建简单的 Blazor Server 项目,无需身份验证。 2. 然后我简单地添加 AspNetCore.Identity.Mongo。

Startup.cs

public class Startup
{
    public Startup(IConfiguration configuration)
    {
        Configuration = configuration;
    }

    public IConfiguration Configuration { get; }

    // This method gets called by the runtime. Use this method to add services to the container.
    // For more information on how to configure your application, visit https://go.microsoft.com/fwlink/?LinkID=398940
    public void ConfigureServices(IServiceCollection services)
    {
        services.Configure<CookiePolicyOptions>(options =>
        {
            // This lambda determines whether user consent for non-essential cookies is needed for a given request.
            options.CheckConsentNeeded = context => true;
            options.MinimumSameSitePolicy = SameSiteMode.None;
        });

        services.Configure<BookstoreDatabaseSettings>(Configuration.GetSection(nameof(BookstoreDatabaseSettings)));
        services.AddSingleton<IBookstoreDatabaseSettings>(sp =>
             sp.GetRequiredService<IOptions<BookstoreDatabaseSettings>>().Value);

        services
            .AddIdentityMongoDbProvider<ApplicationUser, ApplicationRole>(identityOptions =>
            {
                identityOptions.Password.RequiredLength = 1;
                identityOptions.Password.RequireLowercase = false;
                identityOptions.Password.RequireUppercase = false;
                identityOptions.Password.RequireNonAlphanumeric = false;
                identityOptions.Password.RequireDigit = false;
            }, mongoIdentityOptions =>
            {
                mongoIdentityOptions.ConnectionString = Configuration.GetConnectionString("MongoDbDatabase");
            })
            .AddDefaultTokenProviders();

        services.AddAuthentication(options =>
        {
            options.DefaultScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        });

        services.AddRazorPages();
        services.AddServerSideBlazor();
        services.AddSingleton<WeatherForecastService>();

        services.AddScoped<BookService>();
        services.AddTransient<LoginService>();
    }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/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.UseCookiePolicy();

        app.UseRouting();

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

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapBlazorHub();
            endpoints.MapFallbackToPage("/_Host");
        });
    }
}

ApplicationUser.cs

public class ApplicationUser : MongoUser
{
    public string Name { get; set; }
    public string LastName { get; set; }
    public string Gender { get; set; }
    public DateTime? Birthdate { get; set; }
    public string Country { get; set; }
    public string State { get; set; }
    public string City { get; set; }
}

ApplicationRole.cs

public class ApplicationRole : MongoRole
{
}

RegisterNewUserData.cs

public class RegisterUserData
{
    public string UserName { get; set; }
    public string Gender { get; set; }
    public string Password { get; set; }
    public string ConfirmedPassword { get; set; }
}

LoginService.cs

public class LoginService
{
    private readonly UserManager<ApplicationUser> _userManager;
    private readonly SignInManager<ApplicationUser> _signInManager;
    private readonly IConfiguration _configuration;
    private readonly RoleManager<ApplicationRole> _roleManager;

    public LoginService(UserManager<ApplicationUser> userManager,
                                 SignInManager<ApplicationUser> signInManager,
                                 IConfiguration configuration,
                                 RoleManager<ApplicationRole> roleManager)
    {
        _userManager = userManager;
        _signInManager = signInManager;
        _configuration = configuration;
        _roleManager = roleManager;
    }

    public async Task<bool> LogIn(LoginUserData loginUser)
    {
        ApplicationUser user = await _userManager.FindByNameAsync(loginUser.UserName);

        if (user != null)
        {
            try
            {  
                var result2 = await _signInManager.PasswordSignInAsync(user.Email, loginUser.Password, loginUser.RememberMe, lockoutOnFailure: true);
                if (result2.Succeeded)
                {
                    return true;
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine(ex.Message);
                throw;
            }
        }
        return false;
    }

    public async Task<bool> RegisterNewUser(RegisterUserData regUser)
    {
        string roleName = "Member";
        var user = new ApplicationUser
        {
            Name = regUser.UserName,
            UserName = regUser.UserName,
            Email = regUser.UserName,
            Gender = regUser.Gender,
            LastName = "",
            Country = "",
            State = "",
            City = ""
        };

        bool isRoleExists = await _roleManager.RoleExistsAsync(roleName);
        if (isRoleExists == false)
        {
            var role = new ApplicationRole();
            role.Name = roleName;
            await _roleManager.CreateAsync(role);
        }

        var result = await _userManager.CreateAsync(user, regUser.Password);
        if (result.Succeeded)
        {
            await _userManager.AddToRoleAsync(user, roleName);

            var claims = new List<Claim>
            {
                new Claim("user", user.UserName),
                new Claim("role", roleName)
            };
            result = await _userManager.AddClaimsAsync(user, claims);

            if (result.Succeeded)
            {
                try
                {
                    await _signInManager.SignInAsync(user, false);
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                    throw;
                }                    
                return true;
            }
        }
        return false;
    }
}

在注册过程中,成功创建并添加了用户、角色和声明。这是来自 MongoDb 的数据:

{
  "_id": {
    "$oid": "5e9df2819fecf83484901211"
  },
  "UserName": "M1@g.com",
  "NormalizedUserName": "M1@G.COM",
  "Email": "M1@g.com",
  "NormalizedEmail": "M1@G.COM",
  "EmailConfirmed": false,
  "PasswordHash": "AQAAAAEAACcQAAAAEGdbk1EC4niPacknWuMDpbc+YRZP5CmvH0IaUIslo5/vcHplpJO/iWBU/6opCYsErQ==",
  "SecurityStamp": "BOYJUYQFPMLMHJ6NFBHG64K4SC7WEF5W",
  "ConcurrencyStamp": "e9133395-1eed-4757-91a5-a5fc1d699f5d",
  "PhoneNumber": null,
  "PhoneNumberConfirmed": false,
  "TwoFactorEnabled": false,
  "LockoutEnd": null,
  "LockoutEnabled": true,
  "AccessFailedCount": 0,
  "AuthenticatorKey": null,
  "Roles": [
    "5e9df27c9fecf83484901210"
  ],
  "Claims": [
    {
      "_id": 0,
      "UserId": null,
      "ClaimType": "user",
      "ClaimValue": "M1@g.com"
    },
    {
      "_id": 0,
      "UserId": null,
      "ClaimType": "role",
      "ClaimValue": "Member"
    }
  ],
  "Logins": [],
  "Tokens": [],
  "RecoveryCodes": [],
  "Name": "M1@g.com",
  "LastName": "",
  "Gender": "Male",
  "Birthdate": null,
  "Country": "",
  "State": "",
  "City": ""
}

但是当进程调用时:

_signInManager.SignInAsync(user, false);

或:

await _signInManager.PasswordSignInAsync(user.Email, loginUser.Password, loginUser.RememberMe, lockoutOnFailure: true);

我遇到异常:值不能为空。 (参数名称“来源”)。 那么,我错过了什么?

请注意,我使用与 ASP.Net Core 2.1 + Razor Pages + MongoDb Identity 相同的解决方案,效果很好。

最佳答案

我想我找到了问题所在。至少对于登录错误。不知道以后在其他用户管理语句上会不会再发现类似的错误。 但是,基本上,错误说明如下:

System.ArgumentNullException:值不能为空。 (参数“来源”) 在 System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument 参数) 在 System.Linq.Enumerable.Select[TSource,TResult](IEnumerable1 源,Func2 选择器) 在 AspNetCore.Identity.Mongo.Stores.RoleStore`1.GetClaimsAsync(TRole 角色,CancellationToken cancellationToken)

起初我认为这与我创建的用户没有任何声明有关。因此,作为您在此处的代码,我在注册方法和管理员用户播种中实现了它。在对我的用户提出 claim 后,我仍然收到同样的错误。所以一段时间后 a 真的停下来并试图理解错误消息。

如果我们从下往上阅读它,我们首先会看到调用了 RoleStore 中的 GetClaimAsync 方法。在调用 Select from System.Linq 之后,我们有参数“source”,它会引发 nu,, 参数异常。

查看此插件的源代码,我们可以看到 GetClaimsAsync 有这样的语句:

return dbRole.Claims.Select(e => new Claim(e.ClaimType, e.ClaimValue)).ToList();

dbRole.Claims 引用 Roles 集合中的 Claims 对象。我的收藏没有设置 Claims 对象,它们为空。

因此,在我的 Roles 播种方法中,我在每个创建的角色中填充了 Claims 对象。之后,我能够在没有 ArgumentNullException 的情况下登录。

await roleManager.CreateAsync(new MongoRole
                        {
                            Name = role,
                            Claims = new List<IdentityRoleClaim<string>> {
                                new IdentityRoleClaim<string> {
                                    ClaimType = "role",
                                    ClaimValue = role
                                }
                            }
                        });

现在,我想知道我们是否不会再遇到这些 Claims 对象的问题。

关于c# - Blazor + MongoDb 身份 : Value cannot be null.(参数名称 'source'),我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61331181/

相关文章:

reactjs - 为什么 react-router 在调度时自动返回到以前的路由

windows - 在 Visual Studio Code 中更改工作区目录

wordpress - 全局禁用 WP Gutenberg 预发布检查

reactjs - 构建后 Admob 不会在真实设备上展示广告。 Expo React-nativ

azure - 如何在ARM模板中添加多个访问策略

dataframe - 在 DataFrame 上描述 vs printSchema 方法

flutter - 复选框不会更改值

spring-boot - 使用 Spring jpa 查询在字符串列表的列中搜索字符串

tensorflow - 如何将 Tensorflow model.json 转换为 model.p

python - Pandas - 函数 get_dummies() 中参数 dummy_na 的好