3

I'm using angular v6 with asp.net core webapi template I want to Send Xsrf Token to angular app alongside Identity Authorization my problem starts when the user logs in. if there is no user in HttpContext.User there is no problem with the token, but when the user logs in and I regenerate the token all of my post requests fail with a status code of 400 (because of invalid Xsrf-token) here's Service my configuration :

            services.Configure<ApiSettings>(options => Configuration.GetSection("ApiSettings").Bind(options));

        services.AddAuthentication(options =>
        {
            options.DefaultChallengeScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultSignInScheme = JwtBearerDefaults.AuthenticationScheme;
            options.DefaultAuthenticateScheme = JwtBearerDefaults.AuthenticationScheme;
        })
          .AddJwtBearer(options =>
        {
            options.Audience = "Any";
            options.RequireHttpsMetadata = false;
            options.SaveToken = true;

            options.TokenValidationParameters = new TokenValidationParameters()
            {
                ValidIssuer = "http://localhost:44330/",
                ValidAudience = "http://localhost:44330/",
                IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("VeryStrongKey#123"))
            };

        });

        services.AddIdentity<User, Role>();

        services.AddSpaStaticFiles(configuration =>
        {
            configuration.RootPath = "/Ui";
        });

        services.AddAntiforgery(x => { x.HeaderName = "X-XSRF-TOKEN";x.Cookie.Name = "XSRF-TOKEN"; });
        services.AddMvc(options =>
        {
            options.Filters.Add(new AutoValidateAntiforgeryTokenAttribute());
        }).SetCompatibilityVersion(CompatibilityVersion.Version_2_1);




        var builder = new ContainerBuilder();

        services.AddScoped<IAntiForgeryCookieService, AntiForgeryCookieService>();
        services.AddScoped<ITokenStoreService, TokenStoreService>();
        services.AddSingleton<IHttpContextAccessor, HttpContextAccessor>();
        builder.Populate(services);
        builder.RegisterModule(new ManagementService.Service.DiRegister());
        return new AutofacServiceProvider(builder.Build());

and my App Configuration:

  app.UseStaticFiles();
        app.UseSpaStaticFiles();
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }

        loggerFactory.AddConsole(this.Configuration.GetSection("Logging"));
        loggerFactory.AddDebug();

        app.UseAuthentication();
        app.UseMvc();
        app.UseSpa(spa =>
        {
            spa.Options.SourcePath = "Ui";
            if (env.IsDevelopment())
            {
                spa.UseAngularCliServer(npmScript: "start");
            }
        });

here's how i generate the User Claims after the success login event:

 public async Task<(string AccessToken, List<Claim> claims)> createAccessTokenAsync(User user,List<string> roles)
    {


        var claims = new List<Claim>
        {
            // Unique Id for all Jwt tokes
            new Claim(JwtRegisteredClaimNames.Jti, Guid.NewGuid().ToString(), ClaimValueTypes.String, "http://localhost:44330/"),
            // Issuer
            new Claim(JwtRegisteredClaimNames.Iss, "http://localhost:44330/", ClaimValueTypes.String, "http://localhost:44330/"),
            // Issued at
            new Claim(JwtRegisteredClaimNames.Iat, DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString(), ClaimValueTypes.Integer64, "http://localhost:44330/"),
            new Claim(ClaimTypes.NameIdentifier, user.Id.ToString(), ClaimValueTypes.String, "http://localhost:44330/"),
            new Claim(ClaimTypes.Name, user.UserName, ClaimValueTypes.String, "http://localhost:44330/"),
            new Claim("DisplayName", user.Firstname + " " + user.LastName, ClaimValueTypes.String, "http://localhost:44330/"),
         //   new Claim(ClaimTypes.SerialNumber, user.SerialNumber, ClaimValueTypes.String, "http://localhost:44330/"),
            new Claim(ClaimTypes.UserData, user.Id.ToString(), ClaimValueTypes.String, "http://localhost:44330/")
        };

        // add roles
        //var roles = await _rolesService.FindUserRolesAsync(user.Id);
        foreach (var role in roles)
        {
            claims.Add(new Claim(ClaimTypes.Role, role, ClaimValueTypes.String, "http://localhost:44330/"));
        }

        var key = new SymmetricSecurityKey(Encoding.UTF8.GetBytes("VeryStrongKey#123"));
        var creds = new SigningCredentials(key, SecurityAlgorithms.HmacSha256);
        var now = DateTime.UtcNow;
        var token = new JwtSecurityToken(
            issuer: "http://localhost:44330/",
            audience: "http://localhost:44330/",
            claims: claims,
            notBefore: now,
            expires: now.AddMinutes(20),
            signingCredentials: creds);
        return (new JwtSecurityTokenHandler().WriteToken(token), claims);
    }

and the Token Regeneration after claims Created:

  public string RegenerateAntiForgeryCookies(ClaimsPrincipal claims)
    {
        var httpContext = _contextAccessor.HttpContext;
        httpContext.User = claims;
       // httpContext.SignInAsync(claims);

        var tokens = _antiforgery.GetAndStoreTokens(httpContext);
        DeleteAntiForgeryCookies();
        httpContext.Response.Cookies.Append(
             key: XsrfTokenKey,
              value: tokens.RequestToken,
              options: new CookieOptions
              {
                  HttpOnly = false // Now JavaScript is able to read the cookie
              });
        return tokens.RequestToken;
    }

I'm sure the clienside App Will send the token : enter image description here

and I used antiforgery.ValidateRequestAsync(HttpContext); for getting the exact error:

enter image description here

0 Answers0