Search code examples
authenticationjwtblazorasp.net-core-3.1usermanager

Change Userpassword (ASP.Identity) with localstorage based JWT-Token in ASP.NET Core


Good day, i´m a very beginning C# developer and trying to do my first steps with ASP.NET Core.

For now i´m at a point where i need some external help. I developed a Blazor based website and added some users to my database. Now i would like to add a function for loggedin users to change their password. My projekt is splitted to a serverside and a clientside. The clientside contains all my blazor/razor pages include the ChangePasswordView and the serverside receives the REST-requests from the client.

For authorisation i´m using the JWT (JSON WebToken) and i added this token with some claims to a local storage in browser.

The procedure is as following:

  1. User is logged in
  2. User inputs the old and the new password and hits a submit button
  3. The request function goes from the clientside to the serverside
  4. The POST-request gets to serverside UserController class which contains a "ChangePassword(ChangePasswordModel pwModel)" method. It receives the pwModel with the old and the new password successfully.
  5. .... and now i have some problems.... I think i have to verify the JWTtoken from the local browserstorage or something like that, because the _userManager.GetUserAsync(User) always returns null.

How can help me to fix this issues to get a full functional "changePassword" method and what informations do you need?

Best regards, Larry

p.s. For sorry, this i my very first question on Stackoverflow and i tried to describe the issue as best as i can.


Solution

  • It seems a little, you forgot to implement some details. First of all, you need to add JWT authentication to your Startup.

    ConfigureServices:

            services.AddAuthentication()
                .AddJwtBearer(option =>
                {
                    string jwtKey = Configuration.GetSection("Identity").GetSection("Token").GetValue<string>("JwtSecurityKey");
    
                    option.TokenValidationParameters = new TokenValidationParameters()
                    {
                        ValidateIssuer = true,
                        ValidateAudience = true,
                        ValidateLifetime = true,
                        ValidateIssuerSigningKey = true,
                        ValidIssuer = Configuration.GetSection("Identity").GetSection("Token").GetValue<string>("JwtIssuer"),
                        ValidAudience = Configuration.GetSection("Identity").GetSection("Token").GetValue<string>("JwtAudience"),
                        IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(jwtKey))
                    };
                });
    

    Configure:

            app.UseAuthentication();
            app.UseAuthorization();
    

    The Controller method has to be decorated with the Authorize(AuthenticationSchemes = "Bearer") attribute

        [HttpPost("ChangePasswort")]
        [Authorize(AuthenticationSchemes = "Bearer")]
        public async Task<IActionResult> ChangePasswortAsync([FromBody] ChangePasswordModel model)
        {
            string claim = HttpContext.User.FindFirstValue(ClaimsIdentity.DefaultNameClaimType);
    
            var user = await UserManager.GetUserAsync(HttpContext.User);
    
            var result = await UserManager.ChangePasswordAsync(user, model.OldPassword, model.NewPassword);
    
            if(!result.Succeeded)
            {
                ...
            }
            ...
            return Ok(...);
        }
    

    When you make a call to the controller, the HTTP request must have the Authorization header.

    HttpClient.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Bearer", bearerToken);