简体   繁体   中英

Asp.Net Core 3.1 Cookie Authentication loop to login page

my configuration is:

HomeController.cs

public class HomeController : Controller
{
    [Authorize]
    public IActionResult Index()
    {
        return this.View("Index");
    }
}

Startup.cs

public void ConfigureServices(IServiceCollection services)
    {
        services.AddAuthentication(CookieAuthenticationDefaults.AuthenticationScheme)
            .AddCookie(options =>
            {
                options.LoginPath = "/auth/login/";
                options.ExpireTimeSpan = TimeSpan.FromDays(7);
                options.Events.OnValidatePrincipal = ValidateAsync;
            });

        services.AddControllersWithViews();

        services.AddAntiforgery();

        services.AddDbContext<ApplicationDbContext>((serviceProvider, options) =>
        {
            options.UseSqlServer(this.Configuration.GetConnectionString("DefaultConnection"));
            options.EnableSensitiveDataLogging();
        });
    }

public void Configure(IApplicationBuilder app, IWebHostEnvironment env)
    {
        if(env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
        }
        else
        {
            app.UseExceptionHandler("/Home/Error");
            // The default HSTS value is 30 days. You may want to change this for production scenarios, see https://aka.ms/aspnetcore-hsts.
            app.UseHsts();
        }

        app.UseHttpsRedirection();
        app.UseStaticFiles();

        app.UseRouting();

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

        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }

public static async Task ValidateAsync(CookieValidatePrincipalContext context)
    {
        context = context ?? throw new ArgumentNullException(nameof(context));

        String userId = context.Principal.Claims.FirstOrDefault(claim => claim.Type == ClaimTypes.NameIdentifier)?.Value;

        if(userId == null)
        {
            context.RejectPrincipal();
            await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return;
        }

        ApplicationDbContext dbContext = context.HttpContext.RequestServices.GetRequiredService<ApplicationDbContext>();
        User user = await dbContext.Users.FindAsync(Guid.Parse(userId));

        if(user == null)
        {
            context.RejectPrincipal();
            await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return;
        }

        if(!user.StaySignedIn && 
            user.LastLogin != null && 
            (user.LastLogin.Subtract(TimeSpan.FromDays(1)) > DateTimeOffset.Now))
        {
            context.RejectPrincipal();
            await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
            return;
        }
    }

AuthController.cs

[Route("/login")]
    [Route("/auth/login")]
    public async Task<IActionResult> Login([FromForm]LoginModel loginModel)
    {
        Claim nameIdentifier = new Claim(ClaimTypes.NameIdentifier, user.Id.ToString());

        ClaimsIdentity userIdentity = new ClaimsIdentity(new List<Claim> { nameIdentifier }, CookieAuthenticationDefaults.AuthenticationScheme);
        ClaimsPrincipal claimsPrincipal = new ClaimsPrincipal(userIdentity);

        await this.HttpContext.SignInAsync(CookieAuthenticationDefaults.AuthenticationScheme, claimsPrincipal);
        return this.RedirectToAction("Index", "Home");
    }

Problem: When i successfull signed in to the http context and i'm redirected to the home controller, the Authorize Attribute of the HomeController redirect me to the login path, because i dont know. (Infinite loop)

The validate async method dont sign me out or reject the cookie (I checked it.)

But where's the problem? I've the same authentication process in a asp.net core 2.1 project and there it works perfectly.

I test it with a custom authorize attribute to check the context. In the context i've a principal and i'm authenticated.

But why redirect me the standard authorize attribute?

Regards, duesmannr

I found the solution for my problem.

The order of

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

Must be changed and then it works.

The issue closed When using identity is not allowed to use the cookies. It overrides some of the information. Git Discussion

Cookie options tell the authentication middleware how the cookie works in the browser.In the Startup class, add this code in your ConfigureServices Method

     services.AddAuthentication(options =>
        {
            options.DefaultSignInScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultAuthenticateScheme = CookieAuthenticationDefaults.AuthenticationScheme;
            options.DefaultChallengeScheme = CookieAuthenticationDefaults.AuthenticationScheme;
        }).AddCookie(options => { options.LoginPath = "/Login"; });

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