简体   繁体   中英

Value cannot be null. (Parameter 'value')

I have created a method where a user can log into my application and then a Token is sent to the user so it can be used to view any other views in the application.When i test the login method on postman i get the 500 server error as below instead of the token. I have seen similar questions/posts but haven't seen one that is related to JWT

Below is the output

System.ArgumentNullException: Value cannot be null. (Parameter '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 Coop_Marketing.Controllers.AccountController.Login(LoginViewModel formdata) in /Users/Ken/Desktop/Coop_Marketing/Coop_Marketing/Coop_Marketing/Controllers/AccountController.cs:line 101 at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfIActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|10_0(ControllerActionInvoker invoker , Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.g__Awaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|24_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.Rethrow(ResourceExecutedContextSealed context) at Microsoft.AspNetCore.Mvc.Infrastructu re.ResourceInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|19_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted) at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.g__Awaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope) at Microsoft.AspNetCore.Routing.EndpointMiddleware.g__AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger) at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context) at Microsoft.AspNetCore.Diagnostics.DeveloperExceptionPageMiddleware.Invoke(HttpContext context)

The Account controller with the login method is below

   public async Task<IActionResult> Login([FromBody] LoginViewModel formdata)
    {
        // Get the User from database
         var user = await _userManager.FindByNameAsync(formdata.Username);

         var roles = await _userManager.GetRolesAsync(user);

        

        var key = new SymmetricSecurityKey(Encoding.ASCII.GetBytes(_appSettings.Secret));
        double tokenExpiryTime = Convert.ToDouble(_appSettings.ExpireTime);

        if(user !=null && await _userManager.CheckPasswordAsync(user,formdata.Password))
        {

            
            var tokenhandler = new JwtSecurityTokenHandler();

            // Describe the token used by the user to log in

            var tokenDescriptor = new SecurityTokenDescriptor
                          
            {
               
                Subject = new ClaimsIdentity(new Claim[]
                {
                    
                    new Claim(JwtRegisteredClaimNames.Sub, formdata.Username),
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    new Claim(ClaimTypes.NameIdentifier, user.Id),
                    new Claim(ClaimTypes.Role, roles.FirstOrDefault()),
                    new Claim("LoggedOn", DateTime.Now.ToString()),

                    
                }),
                

                SigningCredentials = new SigningCredentials(key, SecurityAlgorithms.HmacSha256Signature),
                Issuer = _appSettings.Site,
                Audience = _appSettings.Audience,
                Expires = DateTime.UtcNow.AddMinutes(tokenExpiryTime)
            };
            // Generate the token
            var token = tokenhandler.CreateToken(tokenDescriptor);
            return Ok(new {token= tokenhandler.WriteToken(token), expiration = token.ValidTo,username = user.UserName,userRole = roles.FirstOrDefault()});


        }

        
        // Return error
        ModelState.AddModelError("","Username/Password was not Found");
        return Unauthorized(new { LoginError = "Please check the Login Credentials - Invalid Username/Password was entered" });
    }
}

}

And the LoginViewModel

public class LoginViewModel
{
    [Required]
    [Display(Name = "User Name")]

    public string Username { get; set; }

    [Required]
    [DataType(DataType.Password)]
    public string Password { get; set; }
} 

The problem is with > var tokenDescriptor = new SecurityTokenDescriptor as per line 101 in the code which is mentioned in the output. However,I have failed to figure out why I am getting the error.

So it is like Claim has a null parameter. for that, you found this issue.

Update your code like below:-

.....

 Subject = new ClaimsIdentity(new Claim[]
                {
                   
                    new Claim(JwtRegisteredClaimNames.NameId,formdata.UserName), //modified
                    new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString()),
                    new Claim(JwtRegisteredClaimNames.Sub, user.Id.ToString()), //modified
                    new Claim(ClaimTypes.Role, roles.FirstOrDefault()),
                    new Claim("LoggedOn", DateTime.Now.ToString()),

                    
                }),

.....

Hope it will resolve your issue.

As you can see in the official documentation , the constructor will throw an argument null exception when the claim type/value is null. So it seems you are passing a null value(s) to the Claim constructor when creating the Claim object array.

As @Jasen mentioned to make the debugging easier change the one-line Claims array creation just for debugging and put a breakpoint to identify which claim is the culprit.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM