question

AsjadButt-2119 avatar image
0 Votes"
AsjadButt-2119 asked cooldadtx commented

User.FindFirst(ClaimTypes.NameIdentifier) doesn't retrieve anything

I'm trying to make an update user endpoint and to get the user i use the return user.FindFirst(ClaimTypes.NameIdentifier)?.Value; method but when i call this my controller update user endpoint it doesnt return any value the user variable which it is assigned to is null after its execution and when i execute this method in post man the following error occurs

{
"statusCode": 500,
"message": "Value cannot be null. (Parameter 'entity')",
"details": " at Microsoft.EntityFrameworkCore.Utilities.Check.NotNull[T](T value, String parameterName)\r\n at Microsoft.EntityFrameworkCore.DbContext.Entry[TEntity](TEntity entity)\r\n at API.Repository.UserRepository.Update(AppUser user) in D:\\Dating App\\DatingAppAPI\\API\\API\\Repository\\UserRepository.cs:line 64\r\n at API.Controllers.UsersController.UpdateUser(MemberUpdateDto memberUpdateDto) in D:\\Dating App\\DatingAppAPI\\API\\API\\Controllers\\UsersController.cs:line 47\r\n at lambda_method13(Closure , Object )\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ActionMethodExecutor.TaskOfActionResultExecutor.Execute(IActionResultTypeMapper mapper, ObjectMethodExecutor executor, Object controller, Object[] arguments)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeActionMethodAsync>g_Awaited|12_0(ControllerActionInvoker invoker, ValueTask`1 actionResultValueTask)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeNextActionFilterAsync>gAwaited|10_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Rethrow(ActionExecutedContextSealed context)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.Next(State& next, Scope& scope, Object& state, Boolean& isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ControllerActionInvoker.<InvokeInnerFilterAsync>gAwaited|13_0(ControllerActionInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeFilterPipelineAsync>gAwaited|20_0(ResourceInvoker invoker, Task lastTask, State next, Scope scope, Object state, Boolean isCompleted)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>gAwaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\r\n at Microsoft.AspNetCore.Mvc.Infrastructure.ResourceInvoker.<InvokeAsync>gAwaited|17_0(ResourceInvoker invoker, Task task, IDisposable scope)\r\n at Microsoft.AspNetCore.Routing.EndpointMiddleware.<Invoke>g_AwaitRequestTask|6_0(Endpoint endpoint, Task requestTask, ILogger logger)\r\n at Microsoft.AspNetCore.Authorization.Policy.AuthorizationMiddlewareResultHandler.HandleAsync(RequestDelegate next, HttpContext context, AuthorizationPolicy policy, PolicyAuthorizationResult authorizeResult)\r\n at Microsoft.AspNetCore.Authorization.AuthorizationMiddleware.Invoke(HttpContext context)\r\n at Microsoft.AspNetCore.Authentication.AuthenticationMiddleware.Invoke(HttpContext context)\r\n at API.MiddleWare.ExceptionMiddleware.InvokeAsync(HttpContext httpContext) in D:\\Dating App\\DatingAppAPI\\API\\API\\MiddleWare\\ExceptionMiddleware.cs:line 24"
}
242536-error-2.png242479-error-1.png


dotnet-csharpdotnet-aspnet-core-webapi
error-2.png (39.8 KiB)
error-1.png (49.2 KiB)
· 4
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

user endpoint it doesnt return any value the user variable which it is assigned to is null after its execution and when i execute this method in post man the following error occurs

If I understand the User object is null. Most likely you did not send the token (Web API) to the action in PostMan. There's not much else we can do since you have not explained how your security works and you did not include any relevant code.

0 Votes 0 ·

This is the login method that uses JWT authentication and also included postman test for the token the authorization token is there i got some help which said that i had to store the username object in the claim principal if that is something i may be missing

242748-image.png


242679-image.png


0 Votes 0 ·
image.png (77.9 KiB)
image.png (60.4 KiB)
AgaveJoe avatar image AgaveJoe AsjadButt-2119 ·

I'm not sure if you are still having an issue or not. Keep in mind, we cannot see the LoginDto or the the CreateToken code and we have no idea what claims you are setting.

Can you explain why you are not sharing the most important bits of the code? Did you copy this code and do not understand how it works? Can you provide the source code or at a link to the code you're using?

0 Votes 0 ·
Show more comments
cooldadtx avatar image
0 Votes"
cooldadtx answered cooldadtx commented

Put a breakpoint in your controller on the line var user = . Debug the code and when the breakpoint is hit confirm what is in the object.

Note that the user name in most auth systems is read by simply looking at User.Identity.Name. This should map to the user name.

If you really want to use the claim then you need to be aware of how your identity system sets it. There are actually 2 different claims that can be used. NameIdentifier is generally an immutable ID (often a GUID) that uniquely represents the user. Name is the display-friendly version. They may both be set or not. It depends on your identity provider.

· 3
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.

Well its returning null on both name and name identifier i asked a friend and asked how is was passing the name to the claims principal or the name identifier if that is something i am missing

242756-image.png
242757-image.png


0 Votes 0 ·
image.png (15.3 KiB)
image.png (23.8 KiB)

You are authenticated at the point the call is made right? That means you have enabled authentication for your app, you are either applying the Authorize attribute to the controller or action or globally and the user is actually set. Look at the properties of User. You should have at least 1 Identity and IsAuthenticated should be true. If this isn't happening then your endpoint isn't requiring authentication.

0 Votes 0 ·

Looking at your screenshot, the username would be null at this point because you haven't executed the line yet. If you step once (F10) then it should move to line 45. It is at this point that I assume username is still null. Please post the values shown for User.

Show us the controller declaration that this action is defined in.

0 Votes 0 ·
ZhiLv-MSFT avatar image
0 Votes"
ZhiLv-MSFT answered

Hi @AsjadButt-2119,

First, try to use the online JWT token Decode tools to check whether the JWT token contains the claims or not? If not, the issue relates the token generate method, check your token service and the CreateToken method.

Second, check the JWT token when using postman to call the API method, make sure it is correct.

According to your description, I create a sample and using the following code to generate the token and add claims:

     [AllowAnonymous]
     [HttpPost]
     public IActionResult Login([FromBody] UserModel login)
     {
         IActionResult response = Unauthorized();
         var user = AuthenticateUser(login);

         if (user != null)
         {
             var tokenString = GenerateJSONWebToken(user);
             response = Ok(new { token = tokenString });
         }

         return response;
     }

     private string GenerateJSONWebToken(UserModel userInfo)
     { 
         var securityKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(_config["Jwt:Key"]));
         var credentials = new SigningCredentials(securityKey, SecurityAlgorithms.HmacSha256);

         var claims = new[] {
             new Claim(JwtRegisteredClaimNames.Sub, userInfo.Username),
             new Claim(JwtRegisteredClaimNames.Email, userInfo.EmailAddress),
             new Claim("DateOfJoing", DateTime.Now.ToString()),
             new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString())
         };

         var token = new JwtSecurityToken(_config["Jwt:Issuer"],
             _config["Jwt:Issuer"],
             claims,
             expires: DateTime.Now.AddMinutes(120),
             signingCredentials: credentials);
         return new JwtSecurityTokenHandler().WriteToken(token);
     }

After generate the token, if we decode it, the result like this: we can see it contains the relate claims:

242860-image.png

Then use postman to call the API method with this token, the result like this: we can get the claims using the FindFirst method.

242906-1.gif

More detail information about the JWT Auth, see JWT Authentication In ASP.NET Core


If the answer is the right solution, please click "Accept Answer" and kindly upvote it. If you have extra questions about this answer, please click "Comment".
Note: Please follow the steps in our documentation to enable e-mail notifications if you want to receive the related email notification for this thread.

Best regards,
Dillion


image.png (110.6 KiB)
1.gif (852.5 KiB)
5 |1600 characters needed characters left characters exceeded

Up to 10 attachments (including images) can be used with a maximum of 3.0 MiB each and 30.0 MiB total.