identityserver4 - ArgumentNullException:值不能为空

时间:2018-05-21 12:42:05

标签: identityserver4

我正在使用 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>();
    }

1 个答案:

答案 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");
            }
        }