ASP.Net role-based Authorization: HttpContext.User is null after login

79 views Asked by At

I have the following problem: When a user logs in, during the login process claims are set correctly. One can see that ClaimsPrincipal.Identity.Name contains the correct value. However, when tring to access the logged-in user via HttpContext.User, it's null! What am I doing wrong? startup.cs

    {
        public IConfiguration Configuration { get; }

        public Startup(IConfiguration configuration)
        {
            Configuration = configuration;
        }

        public void ConfigureServices(IServiceCollection services)
        {
            // Add service and create Policy with options
            services.AddCors();
            services.AddMvc().AddJsonOptions(options =>
            {
                options.JsonSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
            });
            services.AddMvc(options =>
            {
                options.SuppressAsyncSuffixInActionNames = false;
            });

            services.AddControllersWithViews()
                .AddNewtonsoftJson(options =>
                    options.SerializerSettings.ReferenceLoopHandling = Newtonsoft.Json.ReferenceLoopHandling.Ignore);
            services.AddAuthentication("JwtAuth")
           .AddCookie("JwtAuth", options =>
           {
               options.LoginPath = "/login";
           });
            services.AddAuthorization();
            services.AddScoped<IUserRepository, UserRepository>();
            services.AddDbContext<ProPlanContext>();
            services.AddHttpContextAccessor();
            services.AddScoped<Jwt>();
            services.AddSignalR().AddJsonProtocol(options => {
                options.PayloadSerializerOptions.Converters.Add(new JsonStringEnumConverter(JsonNamingPolicy.CamelCase));
            });
            services.AddSwaggerGen(c =>
            {
                c.SwaggerDoc("v1", new OpenApiInfo
                {
                    Title = "Eckelmann Servie API",
                    Version = "v1"
                });

                c.AddSecurityDefinition("Bearer", new OpenApiSecurityScheme()
                {
                    Name = "Authorization",
                    Description = "Specify the authorization token.",
                    In = ParameterLocation.Header,
                    Type = SecuritySchemeType.ApiKey,
                });

                c.AddSecurityRequirement(new OpenApiSecurityRequirement()
                {
                    {
                         new OpenApiSecurityScheme {
                             Reference = new OpenApiReference
                             {
                                 Type = ReferenceType.SecurityScheme,
                                 Id = "Bearer"
                             }
                         },
                         new string[] { }
                    },
                });
            });
        }

        public void Configure(IApplicationBuilder app, IWebHostEnvironment env, ILoggerFactory loggerFactory )
        {
            var logger = loggerFactory.CreateLogger<Startup>();

            app.Use(async (context, next) =>
            {
                try
                {
                    logger.LogInformation("Data sent at " + DateTime.Now.ToString());
                    await Console.Out.WriteLineAsync("__________________________________________");
                    await next.Invoke();
                }
                catch (Exception ex)
                {
                    logger.LogInformation($"{ex.Message}");
                }
               
            });
           

            if (env.IsDevelopment())
                app.UseDeveloperExceptionPage();

            // Cross-Origin Resource Sharing (cors) 
            app.UseCors(options => options
                .SetIsOriginAllowed(origin => true)
                .AllowAnyMethod()
                .AllowAnyHeader()
                .AllowCredentials()
                );

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

            app.UseCookiePolicy(new CookiePolicyOptions
            {
                MinimumSameSitePolicy = SameSiteMode.Strict,
                HttpOnly = HttpOnlyPolicy.Always,
                Secure = CookieSecurePolicy.SameAsRequest
            });
            app.Use(async (context, next) =>
            {
                Thread.CurrentPrincipal = context.User;
                await next(context);
            });
            app.UseEndpoints(endpoints => {
                endpoints.MapControllers();
                try
                {
                    endpoints.MapHub<Hub>("/signalr");
                }
                catch (Exception ex)
                {
                    Console.WriteLine(ex.Message);
                }
            });
        }
    }

// Login Controller {
    [ApiController]
    [Route("api")]
    public class AuthenticationController: ControllerBase
    {
        private readonly Jwt _jwt;
        private readonly IUserRepository _userRepository;
        private readonly ProPlanContext _dbContext;

        public AuthenticationController(Jwt jwt, IUserRepository userRepository, ProPlanContext dbContext)
        {
            _jwt = jwt;
            _userRepository = userRepository;
            _dbContext = dbContext;
        }

        [HttpPost("login")]
        public IActionResult Login(LoginPoco loginPoco)
        {
            User? user = _userRepository.IdentifyUserViaEmail(loginPoco.Email);

            if (user != null && Verify(user, loginPoco.Password, 15000))
            {
                var claimsPrincipal = GetClaimsPrincipal(user.Email);
                HttpContext.SignInAsync(claimsPrincipal).Wait();
                var token = _jwt.IssueJwt(user.Id);
                var cookieOptions = new Microsoft.AspNetCore.Http.CookieOptions { HttpOnly = true, IsEssential
= true };
                Response.Cookies.Append("jwt", token, cookieOptions);

                return Ok(new { Token = token });
            }
            else
            {
                return Unauthorized("Incorrect email or password!");
            }
        }


        private bool Verify(User user, string enteredPassword, int iterations)
        {
            string hashedPassword = SignupController.HashPassword(user.Salt, enteredPassword, iterations);
            return hashedPassword == user.Password;
        }

        [HttpGet("login")]
        public IActionResult GetUserViaJwt()
        {
            try
            {
                var jwt = Request.Cookies["jwt"];
                User? user = null;
                if (jwt != null)
                {
                    JwtSecurityToken token = _jwt.ValidateJwt(jwt);
                    int id = int.Parse(token.Issuer);
                    user = _userRepository.IdentifyUserViaId(id);
                }

                return (user != null) ? Ok(user) as IActionResult : Unauthorized();

            }
            catch (Exception)
            {
                return Unauthorized();
            }
        }

        public static ClaimsPrincipal GetClaimsPrincipal(string email)
        {
            var claims = new List<Claim>
            {
                new Claim(ClaimTypes.Name, email),
            };

            var claimsIdentity = new ClaimsIdentity(claims, "custom");
            var claimsPrincipal = new ClaimsPrincipal(claimsIdentity);

            return claimsPrincipal;
        }


        [HttpPost("logout")]
        public IActionResult logout()
        {
            try
            {
                Response.Cookies.Delete("jwt");

                return Ok(SuccessMessages.SuccessLogout);
            }
            catch(Exception ex)
            {
                return BadRequest(ex.Message);
            }

        }
    } } // A method within another controller which is called after login: [HttpDelete("{id}")]
        public ActionResult DeleteProject(int id)
        {
            bool admin = IsAdmin() == true;
            if (!admin)
            {
                return Forbid();
            }

            try
            {
                Project? project = _dbContext.Projects.Find(id);
                if (project == null)
                {
                    return NotFound();
                }

                _dbContext.Projects.Remove(project);
                _dbContext.SaveChanges();

                return Ok();
            }
            catch (Exception ex)
            {
                Log.Error(ex.ToString());
                return Problem(ex.Message);
            }
        }  public bool IsAdmin()
        {
            var email = HttpContext.User.FindFirst(ClaimTypes.Email)?.Value;

            User? user = _dbContext.Users.FirstOrDefault(user => user.Email == email);

            return user?.Role == "Administrator";
        }

The variable isAdmin always returns false as the user in the IsAdmin method is always null due to HttpContext.User always being null!!! By the way, JWt tokens are always issued and validated successfully. The login function via JWT works properly.

0

There are 0 answers