簡體   English   中英

Blazor + MongoDb 標識:值不能是 null。 (參數名稱“來源”)

[英]Blazor + MongoDb Identity: Value cannot be null. (Parameter name 'source')

你可以幫幫我嗎。 我正在嘗試將 Blazor 與 MongoDb 標識一起使用,並且總是得到異常:值不能是 null。 (參數名稱'源')當我調用signInManager.SignInAsync(用戶,假);

MongoDB 服務器版本:4.2.5

ASP.Net 核心 3.1

NuGet 包:AspNetCore.Identity.Mongo:6.7.0 MongoDB.Driver:2.10.3

准備工作: 1. 創建簡單的Blazor Server項目,無需認證。 2.然后我簡單的添加AspNetCore.Identity.Mongo。

啟動.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");
        });
    }
}

應用程序用戶.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; }
}

應用程序角色.cs

public class ApplicationRole : MongoRole
{
}

注冊新用戶數據.cs

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

登錄服務.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);

我遇到了異常:值不能是 null。 (參數名稱“來源”) 那么,我錯過了什么?

注意,我對 ASP.Net Core 2.1 + Razor Pages + MongoDb Identity 使用相同的解決方案,並且效果很好。

我想我找到了問題所在。 至少對於登錄錯誤。 不知道以后會不會在其他用戶管理語句上發現另一個類似的錯誤。 但是,基本上,錯誤說明如下:

System.ArgumentNullException:值不能為 null。 (參數'源')在 System.Linq.ThrowHelper.ThrowArgumentNullException(ExceptionArgument 參數)在 System.Linq.Enumerable.Select[TSource,TResult](IEnumerable 1 source, Func AspoleId.RMongo.) `1.GetClaimsAsync(TRole 角色,CancellationToken cancelToken)

首先,我認為這與我創建的用戶沒有任何聲明有關。 因此,作為您的代碼,我在注冊方法以及管理員用戶播種上實現了它。 在對我的用戶提出索賠后,我仍然收到同樣的錯誤。 所以過了一段時間真的停下來並試圖理解錯誤信息。

如果我們從下往上閱讀,我們首先會看到 RoleStore 中的 GetClaimAsync 方法被調用。 在調用來自 System.Linq 的 Select 之后,我們有參數“source”,它是引發 nu,, 參數異常的參數。

查看這個插件的源代碼,我們可以看到 GetClaimsAsync 有這樣的語句:

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

dbRole.Claims 指的是 Roles 集合中的 Claims object。 我的收藏沒有設置索賠 object,它們是 null。

因此,在我的角色播種方法中,我在每個創建的角色中填寫了聲明 object。 之后,我能夠在沒有 ArgumentNullException 的情況下登錄。

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

現在,我想知道這些 Claims 對象是否不會再出現問題。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM