我正在使用 IdentityServer4 ,并且在访问令牌过期时我一直遇到问题。如果用户在发生这种情况后尝试执行注销等操作,则会在下面给出错误。但是当你再次尝试登录时也会发生这种情况。解决它的唯一方法是清除浏览器中的缓存和cookie。我理解错误消息,但我无法找到在哪里检查null,因为我认为 UserClaimsFactory.cs 是nuget包中的受保护资源,所以我无能为力。
System.ArgumentNullException: Value cannot be null.
Parameter name: value
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.UserClaimsPrincipalFactory`1.<GenerateClaimsAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory`2.<GenerateClaimsAsync>d__5.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Identity.UserClaimsPrincipalFactory`1.<CreateAsync>d__9.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.AspNetIdentity.UserClaimsFactory`1.<CreateAsync>d__3.MoveNext() in C:\local\identity\server4\AspNetIdentity\src\IdentityServer4.AspNetIdentity\UserClaimsFactory.cs:line 28
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Identity.SignInManager`1.<CreateUserPrincipalAsync>d__25.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Identity.SecurityStampValidator`1.<ValidateAsync>d__4.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationHandler.<HandleAuthenticateAsync>d__20.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Authentication.AuthenticationHandler`1.<AuthenticateAsync>d__47.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Authentication.AuthenticationService.<AuthenticateAsync>d__10.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at System.Runtime.CompilerServices.TaskAwaiter`1.GetResult()
at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.<Invoke>d__6.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Cors.Infrastructure.CorsMiddleware.<Invoke>d__7.MoveNext()
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at IdentityServer4.Hosting.BaseUrlMiddleware.<Invoke>d__3.MoveNext() in C:\local\identity\server4\IdentityServer4\src\IdentityServer4\Hosting\BaseUrlMiddleware.cs:line 36
--- End of stack trace from previous location where exception was thrown ---
at System.Runtime.ExceptionServices.ExceptionDispatchInfo.Throw()
at System.Runtime.CompilerServices.TaskAwaiter.HandleNonSuccessAndDebuggerNotification(Task task)
at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.<Invoke>d__7.MoveNext()
这是我的配置......
public void ConfigureServices(IServiceCollection services)
{
services.Configure<IISOptions>(iis =>
{
iis.AuthenticationDisplayName = "Windows";
iis.AutomaticAuthentication = false;
});
services.AddDbContext<UserIdentityDbContext>(builder =>
builder.UseSqlServer(Configuration.GetConnectionString("IDPDatabaseConnection"), a => a.MigrationsAssembly("SMI.IDP")));
services.AddIdentity<ApplicationUser, IdentityRole>()
.AddEntityFrameworkStores<UserIdentityDbContext>()
.AddDefaultTokenProviders();
services.AddSingleton(typeof(ILocalActiveDirectoryService), typeof(AmericasActiveDirectoryService));
services.AddSingleton(typeof(IIdentityServerUserStore<ApplicationUser>), typeof(UsersRepository));
services.AddScoped<ClaimsService>();
services.AddScoped<UsersRepository>();
services.AddMvc();
var idsrvBuilder = services.AddIdentityServer()
.AddDeveloperSigningCredential()
.AddConfigurationStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(Configuration.GetConnectionString("IDPDatabaseConnection"),
sql => sql.MigrationsAssembly(_migrationsAssembly));
})
.AddOperationalStore(options =>
{
options.ConfigureDbContext = builder =>
builder.UseSqlServer(Configuration.GetConnectionString("IDPDatabaseConnection"),
sql => sql.MigrationsAssembly(_migrationsAssembly));
// this enables automatic token cleanup. this is optional.
options.EnableTokenCleanup = true;
options.TokenCleanupInterval = 30;
})
.AddAspNetIdentity<ApplicationUser>();
idsrvBuilder.AddResourceOwnerValidator<ResourceOwnerPasswordValidator>();
idsrvBuilder.AddProfileService<ProfileService>();
}
答案 0 :(得分:1)
在对此事件进行了彻底调查之后,我发现UserClaimsPrincipalFactory是导致此问题的原因:
https://forum.manjaro.org/t/no-aufs-in-kernel-4-14/35371/9
您必须重写自己的UserManager的GetUserIdAsync,以使默认工厂功能正常运行。
这是一个示例类,您可以从中开始。
using System;
using System.Collections.Generic;
using System.Security.Claims;
using System.Security.Principal;
using System.Threading.Tasks;
using IdentityModel;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Options;
using Nozomi.Base.Identity.Models.Identity;
using Nozomi.Service.Identity.Managers;
namespace Nozomi.Service.Identity.Factories
{
public class NozomiUserClaimsPrincipalFactory: UserClaimsPrincipalFactory<User, Role>
{
public new NozomiUserManager UserManager;
public new RoleManager<Role> RoleManager;
public NozomiUserClaimsPrincipalFactory(NozomiUserManager userManager, RoleManager<Role> roleManager,
IOptions<IdentityOptions> options) : base(userManager, roleManager, options)
{
UserManager = userManager;
RoleManager = roleManager;
}
/// <summary>
/// Creates a <see cref="T:System.Security.Claims.ClaimsPrincipal" /> from an user asynchronously.
/// </summary>
/// <param name="user">The user to create a <see cref="T:System.Security.Claims.ClaimsPrincipal" /> from.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous creation
/// operation, containing the created <see cref="T:System.Security.Claims.ClaimsPrincipal" />.</returns>
public override async Task<ClaimsPrincipal> CreateAsync(User user)
{
var principal = await base.CreateAsync(user);
var identity = (ClaimsIdentity)principal.Identity;
var claims = new List<Claim>
{
new Claim(JwtClaimTypes.Role, "user")
};
identity.AddClaims(claims);
return principal;
}
/// <summary>Generate the claims for a user.</summary>
/// <param name="user">The user to create a <see cref="T:System.Security.Claims.ClaimsIdentity" /> from.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous creation operation, containing the created <see cref="T:System.Security.Claims.ClaimsIdentity" />.</returns>
protected override async Task<ClaimsIdentity> GenerateClaimsAsync(User user)
{
try
{
var userId = await UserManager.GetUserIdAsync(user);
var userNameAsync = await UserManager.GetUserNameAsync(user);
var id = new ClaimsIdentity("Identity.Application",
this.Options.ClaimsIdentity.UserNameClaimType, this.Options.ClaimsIdentity.RoleClaimType);
id.AddClaim(new Claim(this.Options.ClaimsIdentity.UserIdClaimType, userId));
id.AddClaim(new Claim(this.Options.ClaimsIdentity.UserNameClaimType, userNameAsync));
ClaimsIdentity claimsIdentity;
if (this.UserManager.SupportsUserSecurityStamp)
{
claimsIdentity = id;
string type = this.Options.ClaimsIdentity.SecurityStampClaimType;
claimsIdentity.AddClaim(new Claim(type, await this.UserManager.GetSecurityStampAsync(user)));
claimsIdentity = (ClaimsIdentity) null;
type = (string) null;
}
if (this.UserManager.SupportsUserClaim)
{
claimsIdentity = id;
claimsIdentity.AddClaims((IEnumerable<Claim>) await this.UserManager.GetClaimsAsync(user));
claimsIdentity = (ClaimsIdentity) null;
}
return id;
}
catch (Exception ex)
{
Console.WriteLine(ex);
return new ClaimsIdentity();
}
}
}
}
请确保在构造函数中将自定义对象符号链接,否则将无法正常工作。
在UserStore类中:
/// <summary>
/// Gets the user identifier for the specified <paramref name="user" />.
/// </summary>
/// <param name="user">The user whose identifier should be retrieved.</param>
/// <param name="cancellationToken">The <see cref="T:System.Threading.CancellationToken" /> used to propagate notifications that the operation should be canceled.</param>
/// <returns>The <see cref="T:System.Threading.Tasks.Task" /> that represents the asynchronous operation, containing the identifier for the specified <paramref name="user" />.</returns>
public override Task<string> GetUserIdAsync(User user, CancellationToken cancellationToken)
{
try
{
if (cancellationToken != null)
cancellationToken.ThrowIfCancellationRequested();
if (user == null)
throw new ArgumentException(nameof(user));
var res = _unitOfWork.GetRepository<User>().Get(u =>
u.Email.Equals(user.Email, StringComparison.InvariantCultureIgnoreCase)
|| user.UserName.Equals(user.UserName, StringComparison.InvariantCultureIgnoreCase))
.Select(u => u.Id)
.SingleOrDefault();
if (res == null)
throw new ArgumentOutOfRangeException(nameof(user));
return Task.FromResult(res.ToString());
}
catch (Exception ex)
{
return Task.FromResult("-1");
}
}