identitysever和AspNetUsers

时间:2018-10-08 22:24:14

标签: c# asp.net-core identityserver4 asp.net-core-identity

我在哪里设置了

services.AddIdentity<AppUser, AppRole>() 
    .AddEntityFrameworkStores<ApplicationDbContext>() 
    .AddUserManager<userManage>()
    .AddDefaultTokenProviders();

使用AppUserAppRole的地方,但是似乎因此失败。我不断得到

  

ArgumentNullException:值不能为null。参数名称:System.Security.Claims.Claim..ctor

处声明的类型

之后

  

Microsoft.AspNetCore.Identity.IdentityUserClaim1.ToClaim()

整个日志位于底部

在引入IdentityUserIdentityRole的扩展名之前,一切都在工作

对于IDS4设置,我有:

        services.AddIdentityServer(options => {
                options.UserInteraction.LoginUrl = "/Account/Login";
            })
           .AddSigningCredential(new X509Certificate2(Path.Combine(".", "certs"
                                                                 , "IdentityServer4Auth.pfx")))
           .AddAspNetIdentity<AppUser>()
           .AddConfigurationStore(options => {
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(connection_string, sql => sql.MigrationsAssembly(migrations_assembly));
            })
           .AddOperationalStore(options => {
                //options.DefaultSchema = "token";
                options.ConfigureDbContext = builder =>
                    builder.UseSqlServer(connection_string, sql => sql.MigrationsAssembly(migrations_assembly));
            })
           .AddInMemoryApiResources(Config.GetApiResources())
           .AddInMemoryIdentityResources(Config.GetIdentityResources())
           .AddJwtBearerClientAuthentication()
           .AddProfileService<IdentityProfileService>();

正常,但切换为

         services.AddIdentity<ApplicationUser, IdentityRole>(options =>
        {  })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders();
        services.AddDistributedMemoryCache();

        services.AddIdentity<AppUser, AppRole>()
           .AddEntityFrameworkStores<ApplicationDbContext>()
           .AddUserManager<userManage>()
           .AddDefaultTokenProviders();

现在就杀死了它。我知道它可以设置AppUserAppRoleuserManage的范围,因为它们在我的许多应用程序中使用的设置都相同,但是一旦与IDS4现在失败了。在工作时,我扩展了IdentityUser

public class ApplicationUser : IdentityUser {}

该工具也可以正常工作,那是我将这两个应用程序混合在一起的时候,所以AppUserAppRoleuserManage都已经坏了。 我将模型放在下方

也要注意,我已经遵循了日志,而在这里杀死我的是数据库中运行的查询正确。当我运行它时,我看不到任何类型值的空值。为了安全起见,我什至在数据库中清除了所有声明区域中的任何空值,例如角色或用户级别。我在导致故障的区域上设置了一个断点,

    var signin_result = await _signInManager.PasswordSignInAsync(_user, test, model.RememberMe, false);

当我查看_user时,我看到它具有安全标记,并且所有值都正确填充

这是用户要求的

SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId]
FROM [AspNetUserClaims] AS [uc]
WHERE [uc].[UserId] = @__user_Id_0

但是我看不出问题出在哪里,什么都没有返回空值

日志

2018-10-08 13:17:47.164 -07:00 [Information] Entity Framework Core "2.1.4-rtm-31024" initialized '"ApplicationDbContext"' using provider '"Microsoft.EntityFrameworkCore.SqlServer"' with options: "SensitiveDataLoggingEnabled "
2018-10-08 13:17:47.189 -07:00 [Information] Executed DbCommand ("1"ms) [Parameters=["@__user_Id_0='11325643' (Size = 450)"], CommandType='Text', CommandTimeout='30']"
""SELECT [uc].[Id], [uc].[ClaimType], [uc].[ClaimValue], [uc].[UserId]
FROM [AspNetUserClaims] AS [uc]
WHERE [uc].[UserId] = @__user_Id_0"
2018-10-08 13:17:47.370 -07:00 [Error] An exception occurred in the database while iterating the results of a query for context type '"test.app.Data.ApplicationDbContext"'."
""System.ArgumentNullException: Value cannot be null.
Parameter name: type
at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue)
at System.Security.Claims.Claim..ctor(String type, String value)
at Microsoft.AspNetCore.Identity.IdentityUserClaim`1.ToClaim()
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.IShaper<TOut>.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.BufferlessMoveNext(DbContext _, Boolean buffer, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.MoveNext(CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)"
System.ArgumentNullException: Value cannot be null.
Parameter name: type
at System.Security.Claims.Claim..ctor(String type, String value, String valueType, String issuer, String originalIssuer, ClaimsIdentity subject, String propertyKey, String propertyValue)
at System.Security.Claims.Claim..ctor(String type, String value)
at Microsoft.AspNetCore.Identity.IdentityUserClaim`1.ToClaim()
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.ProjectionShaper.TypedProjectionShaper`3.Microsoft.EntityFrameworkCore.Query.ExpressionVisitors.Internal.IShaper<TOut>.Shape(QueryContext queryContext, ValueBuffer& valueBuffer)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.BufferlessMoveNext(DbContext _, Boolean buffer, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.SqlServer.Storage.Internal.SqlServerExecutionStrategy.ExecuteAsync[TState,TResult](TState state, Func`4 operation, Func`4 verifySucceeded, CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncQueryingEnumerable`1.AsyncEnumerator.MoveNext(CancellationToken cancellationToken)
at Microsoft.EntityFrameworkCore.Query.Internal.AsyncLinqOperatorProvider.ExceptionInterceptor`1.EnumeratorExceptionInterceptor.MoveNext(CancellationToken cancellationToken)
2018-10-08 13:17:48.680 -07:00 [Information] Executed action "WSU.Sso.Controllers.AccountController.Login (test.app)" in 2022.4589ms

模型,并进行设置(请注意,在无IDS4应用程序中,它们工作正常)

public class AppUser : IdentityUser {}
public class AppRole : IdentityRole {}
public class AppUserClaim : IdentityUserClaim<string> {}
public class AppUserRole : IdentityUserRole<string> {}
public class AppRoleClaims : IdentityRoleClaim<string> {}
public partial class CoreDbContext : IdentityDbContext
<
    AppUser, // TUser
    AppRole, // TRole
    string, // TKey
    AppUserClaim, // TUserClaim
    AppUserRole, // TUserRole,
    IdentityUserLogin<string>, // TUserLogin
    AppRoleClaims, // TRoleClaim
    IdentityUserToken<string> // TUserToken
>//, ICoreDbContext
{
    //etc.. 
}

更新

我认为问题出在https://github.com/IdentityServer/IdentityServer4.AspNetIdentity/blob/dev/src/UserClaimsFactory.cs,其中UserManager<TUser> userManager必须为userManage,因为我对此进行了扩展。我猜我需要扮演我自己的角色吗?

更新2

结果是,在移除userManage并扩展了UserManager<TUser>之后,仍然失败

  

System.Security.Claims.Claim..ctor(字符串类型,字符串值,字符串valueType,字符串发行者,字符串originalIssuer,ClaimsIdentity主题,字符串propertyKey,字符串propertyValue)   System.Security.Claims.Claim..ctor(字符串类型,字符串值)   Microsoft.AspNetCore.Identity.IdentityUserClaim.ToClaim()

曾希望简化它会成为麻烦,所以我不必重写.AddAspNetIdentity<AppUser>(),但这没用。显然,不是来自DB的东西为null,而是必须加上它的值为null的东西。我不能说什么,只是它必须在Microsoft.AspNetCore.Identity.IdentityUserClaim<TKey>.ToClaim()IdentityServer4.AspNetIdentity.UserClaimsFactory<TUser>.CreateAsync(TUser user) in UserClaimsFactory.cs之间。我可以肯定地说的是,在https://github.com/IdentityServer/IdentityServer4.AspNetIdentity/blob/dev/src/UserClaimsFactory.cs中,所有在数据库中验证了尝试设置的值是否不为空。

在添加自定义角色之前IDS4仍在工作,这也不值钱。我不是100%不确定这里是否还在发挥作用。

旁注

因此,我想知道的是,在我排除的情况下,ID的名称是否是此处的问题。在更新中,AspNetUser的表的表设置为user_id而不是IdMicrosoft Owin Security - Claims Constructor Value cannot be null是导致我考虑这一点的原因)。话虽如此,我相信设置没有任何问题,这就是我在OnModelCreating(ModelBuilder builder)

中所拥有的
builder.Entity<AppUser>().Property(p => p.Id).HasColumnName("user_id");

到目前为止,在使用它方面还没有任何问题,但是我正在消除将成为问题根源的所有用户差异。

更新3

单步执行public class IdentityUserClaim<TKey> where TKey : IEquatable<TKey>并在Claim ToClaim()上设置一个断点后,该类型为null。这是日志上的一个问题,但是我似乎无法在其起源的调用堆栈中回溯。我的问题是,如果数据库查询返回一组正确的类型和值,那么为什么要先处理一个空类型和值呢?第一次遇到断点时,类型为null。

更新4个主要停车站

在碰到每个断点之后,如果我在这里碰到一个错误,我现在会陷入困境并受伤。我进入UserManager并按照堆栈进行操作,可以看到主要声明在那里并且可以。 enter image description here

然后下一部分是运行声明存储,该存储执行上面的查询,并在该时间执行失败。我不明白为什么。我在SQL Manager中运行查询,但没有一个NULLenter image description here

有人看到发生了什么事吗?此刻我很茫然。

更新5-缩小范围

因此,当我打断设置为null的声明时,没有注意到当地人,我看到我想要的值在this的范围内

enter image description here

现在的问题是范围如何关闭,我将所需的值放在错误的位置

1 个答案:

答案 0 :(得分:0)

这个问题花了一些时间,但是现在很清楚为什么会失败。 AppUserClaim是真正的问题。很难说,在那一步过分地看着当地人,这就是为什么我不得不在这里走很长一段路。

我曾经的扩展IdentityUserClaim<string>

public class AppUserClaim : IdentityUserClaim<string>
{
    public int Id { get; set; }

    /// <summary>
    /// Gets or sets the primary key of the user associated with this claim.
    /// </summary>
    public virtual string UserId { get; set; }

    public virtual AppUser user { get; set; }

    /// <summary>
    /// Gets or sets the claim type for this claim.
    /// </summary>
    public virtual string ClaimType { get; set; }

    /// <summary>
    /// Gets or sets the claim value for this claim.
    /// </summary>
    public virtual string ClaimValue { get; set; }

}

但是ClaimTypeClaimValue的属性不需要重写。一旦完成此操作,它将在方法范围之外的地方设置值。将模型更改为

public class AppUserClaim : IdentityUserClaim<string>  {
    public virtual AppUser user { get; set; } // note this is the reason why i had to extend

}

解决问题。它没有出现在其他应用程序中,因为声明是在SSO中设置的,因此该方法始终被跳过。

要记住的经验教训,请务必确保在逐步通过时查看当地人。我走了一天才看到寂静的时刻。