Używam ASP.NET Core 3.1 z tożsamością. A oto moja cała konfiguracja w klasie startup. Próbuję zmusić zalogowany użytkownik do wylogowania się, jeśli ich konta wygasły podczas korzystania z aplikacji. Powinienem poprawnie skonfigurować plik cookie, ale utknąłem na tym, jak to zrobić, mając uzupełnienie.

Oto mój start

 // This method gets called by the runtime. Use this method to add services to the container.
        public void ConfigureServices(IServiceCollection services)
        {
        services.AddDbContext<ApplicationDbContext>(options =>
           options.UseSqlServer(
               Configuration.GetConnectionString("DefaultConnection")));

        services.AddIdentity<IdentityUser, IdentityRole>(options => {
            options.SignIn.RequireConfirmedAccount = false;
        })
            .AddEntityFrameworkStores<ApplicationDbContext>()
            .AddDefaultTokenProviders(); 

        services.AddIdentityCore<ApplicationUser>()
            .AddRoles<IdentityRole>()
            .AddClaimsPrincipalFactory<UserClaimsPrincipalFactory<ApplicationUser, IdentityRole>>()
            .AddEntityFrameworkStores<ApplicationDbContext>()
            //.AddDefaultTokenProviders()  
            .AddDefaultUI(); 

        services.AddSingleton<IEmailSender, EmailSender>();
        services.Configure<EmailOptions>(Configuration);
   
        services.AddHangfire(config => config.UseSqlServerStorage(Configuration.GetConnectionString("DefaultConnection")));
        services.AddHangfireServer();

        services.AddControllersWithViews(); //?
        services.AddRazorPages().AddRazorRuntimeCompilation(); //?
        services.AddScoped<IExpirationJob, ExpirationJob>();
        services.AddScoped<IReminderJob, EmailReminder>();
        services.AddSingleton<IActionContextAccessor, ActionContextAccessor>();
        services.Configure<IdentityOptions>(options =>
        {
            // Password settings.
            //options.Password.RequireDigit = true;
            //options.Password.RequireLowercase = true;
            //options.Password.RequireNonAlphanumeric = true;
            //options.Password.RequireUppercase = true;
            //options.Password.RequiredLength = 6;
            //options.Password.RequiredUniqueChars = 1;

            // Lockout settings.
            //options.Lockout.DefaultLockoutTimeSpan = TimeSpan.FromMinutes(5);
            //options.Lockout.MaxFailedAccessAttempts = 5;
            //options.Lockout.AllowedForNewUsers = true;

            // User settings.
            //options.User.AllowedUserNameCharacters =
            //    "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-._@+ ";
            //options.User.RequireUniqueEmail = false;
        });

        services.ConfigureApplicationCookie(config =>
        {
            config.Cookie.Name = "my.Cookie";
            config.LoginPath = "/Home/Login";
            config.AccessDeniedPath = "/Identity/Account/AccessDenied";
            config.Cookie.HttpOnly = true;
            config.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
        });
     }

    // This method gets called by the runtime. Use this method to configure the HTTP request pipeline.
    public void Configure(IApplicationBuilder app,
        IWebHostEnvironment env,
        IRecurringJobManager recurringJobManager,
        IServiceProvider serviceProvider)
    {
        if (env.IsDevelopment())
        {
            app.UseDeveloperExceptionPage();
            app.UseDatabaseErrorPage();
        }
        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.UseHangfireDashboard();
        //app.UseHangfireDashboard("/hangfire", new DashboardOptions()
        //{
        //    Authorization = new[] { new CustomAuthorizeFilter() }
        //});

        app.UseRouting();

        app.UseAuthentication();
        app.UseAuthorization();
      
     
        app.UseAuthentication();
        app.UseAuthorization();
      
        recurringJobManager.AddOrUpdate(
           "End Users Subscription",
           () => serviceProvider.GetService<IExpirationJob>().SetExpired(),
           Cron.Minutely
           );

        recurringJobManager.AddOrUpdate(
           "Send End of Subscription Reminder",
           () => serviceProvider.GetService<IReminderJob>().SendReminder(),
           Cron.Daily
           );

        app.Use(async (context, next) =>
        {
            _ = ExpirationJob.SetExpired(context);//pass the HttpContext to SetExpired
            await next();
        });

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

Oto moje ValidateasyNC klasa

 public class ValidateAsync
{
    public static async Task ValidatingAsync(CookieValidatePrincipalContext context)
    {
        context = context ?? throw new ArgumentNullException(nameof(context));
        var claimsIdentity = context.Principal.Identity as ClaimsIdentity;
        if (claimsIdentity?.Claims == null || !claimsIdentity.Claims.Any())
        {
            await RejectPrincipal();
            return;
        }
        UserManager<IdentityUser> userManager = context.HttpContext.RequestServices.GetRequiredService<UserManager<IdentityUser>>();
        var user = await userManager.FindByNameAsync(context.Principal.FindFirstValue(ClaimTypes.NameIdentifier));
        if (user == null || user.SecurityStamp != context.Principal.FindFirst(new ClaimsIdentityOptions().SecurityStampClaimType)?.Value)
        {
            await RejectPrincipal();
            return;
        }
        async Task RejectPrincipal()
        {
            context.RejectPrincipal();
            await context.HttpContext.SignOutAsync(CookieAuthenticationDefaults.AuthenticationScheme);
        }
    }
}

Oto moja metoda setexpired

      public interface IExpirationJob
{
    Task SetExpired();

}
public class ExpirationJob : IExpirationJob
{
    private readonly ApplicationDbContext _db;
    private readonly IEmailSender _emailSender;
    private readonly HttpContext _context;

    public ExpirationJob(ApplicationDbContext db, IEmailSender emailSender, HttpContext context)
    {
        _db = db;
        _emailSender = emailSender;
        _context = context;
    }

    public async Task SetExpired()
    {
        foreach(var item in _db.Institution)
        {
            if (item.SubsEndDate != null)
            {
                if (item.SubsEndDate <= DateTime.Now) 
                {
                   
                    item.Status = SD.StatusExpired;

                    Guid securityStamp = Guid.NewGuid();
                    item.Admin.SecurityStamp = securityStamp.ToString();

                    _context.Response.Cookies.Append("my.Cookie", "expired");
                }
            }
        }
        await _db.SaveChangesAsync();
    }
}
0
shahad alshuhail 22 listopad 2020, 14:36

1 odpowiedź

Najlepsza odpowiedź

Po zrozumieniu logiki biznesowej możesz uzyskać oprogramowanie pośrednie {X0}} i zmodyfikować wartość plików cookie, aby wymusić wylogowanie. Oto przykład.

Najpierw skonfiguruj podstawowe pliki cookie w ConfigureServices.

 services.ConfigureApplicationCookie(config =>
        {
            config.Cookie.Name = "my.Cookie";
            config.LoginPath = "/Home/Login";
            config.AccessDeniedPath = "/Identity/Account/AccessDenied";
            config.Cookie.HttpOnly = true;
            config.ReturnUrlParameter = CookieAuthenticationDefaults.ReturnUrlParameter;
        });

Po drugie, skonfiguruj oprogramowanie pośrednie.

public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
       IExpirationJob expirationJob)
    {
        //...
        app.UseRouting();
        app.UseAuthentication();
        app.UseAuthorization();
        app.Use(async(context,next)=>
        {
            expirationJob.SetExpired(context);//pass the HttpContext to SetExpired
            await next();
        });
        app.UseEndpoints(endpoints =>
        {
            endpoints.MapControllerRoute(
                name: "default",
                pattern: "{controller=Home}/{action=Index}/{id?}");
        });
    }

Trzy, określ, czy zastąpić plik cookie przez czas wygaśnięcia SubscriptionEndDate bazy danych.

public async Task SetExpired(HttpContext httpContext)
    {
        foreach (var item in _db.Institution)
        {
            if (item.SubscriptionEndDate != null)
            {
                if (item.SubscriptionEndDate == DateTime.Today)
                {
                    item.Status = SD.StatusExpired;
                    Guid securityStamp = Guid.NewGuid();
                    item.SecurityStamp = securityStamp;
                    
                    httpContext.Response.Cookies.Append("my.Cookie", "expired");
                }
            }
        }
        await _db.SaveChangesAsync();
    }

Następnie plik cookie jest nieprawidłowy, a ten użytkownik nie będzie dostępu do zasobu.

enter image description here

Aktualizacja:

Inną metodą, jeśli chcesz przekazać HttpContext do SetExpired jako parametr.

  1. Możesz napisać klasę statyczną, taką jak:
    public static class MyClass
    {
        public static HttpContext http { get; set; }
    }
  1. Następnie możesz przypisać wartości do http w startup.cs .

     public void Configure(IApplicationBuilder app, IWebHostEnvironment env,
        IExpirationJob expirationJob)
     {
         //...
         app.UseRouting();
         app.UseAuthentication();
         app.UseAuthorization();
         app.Use(async(context,next)=>
         {
             MyClass.http = context;
             expirationJob.SetExpired();
             await next();
         });
         app.UseEndpoints(endpoints =>
         {
             endpoints.MapControllerRoute(
                 name: "default",
                 pattern: "{controller=Home}/{action=Index}/{id?}");
         });
     }
    
  2. Zdobądź to.

     public async Task SetExpired()
     {
         var path=MyClass.http.Request.Path;
    
         //foreach (var item in _db.Institution)
         //{
         //    if (item.SubsEndDate != null)
         //    {
         //...
         await _db.SaveChangesAsync();
     }
    
0
Karney. 23 listopad 2020, 14:09