2017-02-01 12 views
5

Mam aplikację ASP.NET Core MVC, hostowaną na stronach Azure, gdzie zaimplementowałem Session and Identity. Mój problem polega na tym, że po 30 minutach wylogowuję się. Nie ma znaczenia, czy byłem aktywny przez ostatnie 30 minut, czy nie.Limit czasu strony ASP.NET Core po 30 minutach

Przeprowadzając wyszukiwanie, okazało się, że problemem jest materiał SecurityStamp, found here. Próbowałem realizacji to w następujący sposób:

Oto mój UserManager impelmentation z rzeczy znaczka zabezpieczającego:

public class UserManager : UserManager<Login> 
{ 
    public UserManager(
     IUserStore<Login> store, 
     IOptions<IdentityOptions> optionsAccessor, 
     IPasswordHasher<Login> passwordHasher, 
     IEnumerable<IUserValidator<Login>> userValidators, 
     IEnumerable<IPasswordValidator<Login>> passwordValidators, 
     ILookupNormalizer keyNormalizer, 
     IdentityErrorDescriber errors, 
     IServiceProvider services, 
     ILogger<UserManager<Login>> logger) 
     : base(store, optionsAccessor, passwordHasher, userValidators, passwordValidators, keyNormalizer, errors, services, logger) 
    { 
     // noop 
    } 

    public override bool SupportsUserSecurityStamp => true; 

    public override async Task<string> GetSecurityStampAsync(Login login) 
    { 
     return await Task.FromResult("MyToken"); 
    } 

    public override async Task<IdentityResult> UpdateSecurityStampAsync(Login login) 
    { 
     return await Task.FromResult(IdentityResult.Success); 
    } 
} 

Oto moja metoda ConfigureServices na Startup.cs:

public void ConfigureServices(IServiceCollection services) 
{ 
    // Add framework services. 
    services.AddApplicationInsightsTelemetry(Configuration); 

    services.AddSingleton(_ => Configuration); 

    services.AddSingleton<IUserStore<Login>, UserStore>(); 
    services.AddSingleton<IRoleStore<Role>, RoleStore>(); 

    services.AddIdentity<Login, Role>(o => 
    { 
     o.Password.RequireDigit = false; 
     o.Password.RequireLowercase = false; 
     o.Password.RequireUppercase = false; 
     o.Password.RequiredLength = 6; 
     o.Cookies.ApplicationCookie.ExpireTimeSpan = TimeSpan.FromDays(365); 
     o.Cookies.ApplicationCookie.SlidingExpiration = true; 
     o.Cookies.ApplicationCookie.AutomaticAuthenticate = true; 
    }) 
     .AddUserStore<UserStore>() 
     .AddUserManager<UserManager>() 
     .AddRoleStore<RoleStore>() 
     .AddRoleManager<RoleManager>() 
     .AddDefaultTokenProviders(); 

    services.AddScoped<SignInManager<Login>, SignInManager<Login>>(); 
    services.AddScoped<UserManager<Login>, UserManager<Login>>(); 

    services.Configure<AuthorizationOptions>(options => 
    { 
     options.AddPolicy("Admin", policy => policy.Requirements.Add(new AdminRoleRequirement(new RoleRepo(Configuration)))); 
     options.AddPolicy("SuperUser", policy => policy.Requirements.Add(new SuperUserRoleRequirement(new RoleRepo(Configuration)))); 
     options.AddPolicy("DataIntegrity", policy => policy.Requirements.Add(new DataIntegrityRoleRequirement(new RoleRepo(Configuration)))); 
    }); 

    services.Configure<FormOptions>(x => x.ValueCountLimit = 4096); 
    services.AddScoped<IPasswordHasher<Login>, PasswordHasher>(); 

    services.AddDistributedMemoryCache(); 
    services.AddSession(); 

    services.AddMvc(); 

    // repos 
    InjectRepos(services); 

    // services 
    InjectServices(services); 
} 

I wreszcie , oto moja metoda Konfiguracji na Startup.cs:

public void Configure(IApplicationBuilder app, IHostingEnvironment env, ILoggerFactory loggerFactory) 
{ 
    loggerFactory.AddConsole(Configuration.GetSection("Logging")); 
    loggerFactory.AddDebug(); 

    app.UseApplicationInsightsRequestTelemetry(); 

    if (env.IsDevelopment()) 
    { 
     app.UseDeveloperExceptionPage(); 
     app.UseDatabaseErrorPage(); 
     app.UseBrowserLink(); 
    } 
    else 
    { 
     app.UseExceptionHandler("/home/error"); 
    } 

    app.UseStatusCodePages(); 

    app.UseStaticFiles(); 

    app.UseSession(); 
    app.UseIdentity(); 

    app.UseMiddleware(typeof (ErrorHandlingMiddleware)); 
    app.UseMiddleware(typeof (RequestLogMiddleware)); 

    app.UseMvc(routes => 
    { 
     routes.MapRoute(
      name: "default", 
      template: "{controller=Home}/{action=Index}/{id?}"); 
    }); 
} 

W hat's wrong z moim wdrożeniem tutaj?

AKTUALIZACJA: Co za sekundę ... Zauważyłem, że mój menadżer UserManager nie dziedziczy po żadnym interfejsie dla znaczków bezpieczeństwa, czy to jest potrzebne?

Odpowiedz

1

Jesteś hostowany w IIS? Jeśli tak, być może nic nie jest nie tak z twoim kodem, ale twoja pula aplikacji może zostać poddana recyklingowi (sprawdź zaawansowane ustawienia w puli aplikacji). Kiedy tak się stanie, czy twój plik binarny zostanie wyładowany z pamięci i zastąpiony nowym, zmieniającym się PID?

+0

Niestety, jest on hostowany na platformie Azure, więc nie wierzę, że mam kontrolę nad usługami IIS. – ganders

3

Jest to po prostu dlatego, że musisz enable and configure Data Protection. Plik cookie i ustawienia sesji wyglądają poprawnie. To, co dzieje się teraz dla ciebie, to to, że za każdym razem, gdy aplikacja jest poddawana recyklingowi lub salda obciążenia serwera do innego serwera lub nowego wdrożenia dzieje, itp., Tworzy nowy klucz ochrony danych w pamięci, więc klucze sesji użytkowników są nieważne. Więc wszystko co musisz zrobić, to dodać następujące Startup.cs:

services.AddDataProtection() 
     .PersistKeysToFileSystem(new DirectoryInfo(@"D:\writable\temp\directory\")) 
     .SetDefaultKeyLifetime(TimeSpan.FromDays(14)); 

Użyj dokumentację, aby dowiedzieć się, jak poprawnie skonfigurować to i różne opcje gdzie zapisać klucz ochrony danych (system plików, Redis , rejestr itp.). Można pomyśleć o kluczu ochrony danych jako zamienniku klucza maszynowego web.config w asp.net.

Odkąd wspomniałeś, że korzystasz z platformy Azure, możesz użyć tego pakietu Microsoft.AspNetCore.DataProtection.AzureStorage, aby zapisać klucz, aby go nie usuwał. Możesz więc use this example of how to use Azure Storage.

+0

Czy moja pula aplikacji jest poddawana recyklingowi co 30 minut i jest zsynchronizowana z czasem, w którym się ostatnio zalogowałem? To nie ma dla mnie sensu. – ganders

+0

Prawdopodobnie nie jest to recykling często, nie. Jednak dokumentacja AspNetCore wspomina, że ​​klucze ochrony danych są generowane domyślnie w pamięci - i są tym, co chroni dane cookie sesji i tożsamości (a także filtr akcji ValidateAntiForgeryToken), które nie będą ważne dla użytkownika, jeśli ten klucz ochrony danych zmiany. – truemedia

+0

Właśnie zauważyłem [domyślne ustawienia Ochrony danych] (https://docs.microsoft.com/en-us/aspnet/core/security/data-protection/configuration/default-settings#data-protection-default-settings) na platformie Azure są całkiem niezłe w ustawianiu. Możesz po prostu dodać kod, 'services.AddDataProtection();' i powinieneś być uruchomiony. Azure automatycznie utwierdzi klucze dla Ciebie. Ponadto, dla każdego, kto używa IIS, będą one również działać dobrze na jednej maszynie bez użycia opcji 'PersistKeysToFileSystem', ponieważ ustawienia domyślne dobrze ją ustawiają, jak pokazano w dokumentach. – truemedia