我有一个ASP.NET Core MVC应用程序,托管在Azure网站上,我已经实现了Session和Identity。我的问题是,30分钟后,我退出了。如果我在过去30分钟内一直活跃,那无所谓。
进行一些搜索,我发现问题是SecurityStamp的内容found here。我尝试通过以下方式实现此目的:
这是我的UserManager impelmentation与安全标记的东西:
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);
}
}
这是我在Startup.cs上的ConfigureServices方法:
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);
}
最后,这是我在Startup.cs上的Configure方法:
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?}");
});
}
我在这里的实施有什么问题?
更新:什么秒......我注意到我的UserManager没有继承任何安全标记的接口,是不是需要什么?
答案 0 :(得分:5)
这只是因为你需要enable and configure Data Protection。 Cookie和会话设置看起来正确。现在正在发生的事情是,无论何时应用程序被回收或服务器负载均衡到另一台服务器或发生新部署等,它都会在内存中创建一个新的数据保护密钥,因此用户的会话密钥无效。所以你需要做的就是将以下内容添加到Startup.cs:
class Program
{
static void Main(string[] args)
{
List<int> IntList1 = new List<int> { 42, 43 };
List<int> IntList2 = new List<int> { 42 };
var intResultList = IntList1.Except(IntList2).ToList();
intResultList.ForEach(s => Console.WriteLine(s));
List<DataStructure> List1 = new List<DataStructure> { new DataStructure { DataID = 42, SomeText = "42" }, new DataStructure {DataID = 43, SomeText = "43"} };
List<DataStructure> List2 = new List<DataStructure> { new DataStructure { DataID = 42, SomeText = "42" }};
var comparer = new DataStructureComparer();
var resultList = List1.Except(List2, comparer).ToList();
resultList.ForEach(s => Console.WriteLine(s.SomeText));
Console.ReadLine();
}
}
public class DataStructureComparer: IEqualityComparer<DataStructure>
{
public bool Equals(DataStructure x, DataStructure y)
{
return x.DataID == y.DataID;
}
public int GetHashCode(DataStructure obj)
{
return obj.GetHashCode();
}
}
public class DataStructure
{
public int DataID;
public string SomeText;
}
使用文档了解如何正确设置此文件以及保存数据保护密钥(文件系统,redis,注册表等)的位置的不同选项。您可以将数据保护密钥视为替换asp.net中的web.config机器密钥。
由于您提到您正在使用Azure,因此可以使用此程序包 services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"D:\writable\temp\directory\"))
.SetDefaultKeyLifetime(TimeSpan.FromDays(14));
来保存密钥以使其保持不变。所以你可以use this example of how to use Azure Storage。
答案 1 :(得分:1)
您是否在IIS下托管?如果是这样,您的代码可能没有任何问题,但您的应用程序池可能会被回收(请检查应用程序池上的高级设置)。当发生这种情况时,你的二进制文件是否从内存中卸载并被一个新的替换,它的PID会发生变化吗?