غیرمعتبر شدن کوکیهای برنامههای ASP.NET Core هاست شدهی در IIS پس از ریاستارت آن
نویسنده: وحید نصیری
تاریخ: ۱۳۹۶/۰۵/۱۰ ۱۰:۴۵
آدرس: www.dntips.ir
| مطالب | ۳۶۹۴ |
| نویسندگان | ۲۷۶ |
| گروههای مطالب | ۱۰۲۴ |
| نقشههای راه | ۱۱۹ |
| دورهها | ۱۴ |
| اشتراکها | ۱۷۹۱۴ |
.\Provision-AutoGenKeys.ps1 DefaultAppPool
public void ConfigureServices(IServiceCollection services)
{
services.AddDataProtection()
.PersistKeysToFileSystem(new DirectoryInfo(@"\\server\share\directory\"))
.ProtectKeysWithCertificate("thumbprint");
} public class AppDataProtectionKey
{
public int Id { get; set; }
public string FriendlyName { get; set; }
public string XmlData { get; set; }
}
public virtual DbSet<AppDataProtectionKey> AppDataProtectionKeys { get; set; } modelBuilder.Entity<AppDataProtectionKey>(builder =>
{
builder.ToTable("AppDataProtectionKeys");
builder.HasIndex(e => e.FriendlyName).IsUnique();
}); public class DataProtectionKeyService : IXmlRepository
{
private readonly IServiceProvider _serviceProvider;
public DataProtectionKeyService(IServiceProvider serviceProvider)
{
_serviceProvider = serviceProvider;
_serviceProvider.CheckArgumentIsNull(nameof(_serviceProvider));
}
public IReadOnlyCollection<XElement> GetAllElements()
{
return _serviceProvider.RunScopedContext<ReadOnlyCollection<XElement>>(context =>
{
var dataProtectionKeys = context.Set<AppDataProtectionKey>();
return new ReadOnlyCollection<XElement>(dataProtectionKeys.Select(k => XElement.Parse(k.XmlData)).ToList());
});
}
public void StoreElement(XElement element, string friendlyName)
{
// We need a separate context to call its SaveChanges several times,
// without using the current request's context and changing its internal state.
_serviceProvider.RunScopedContext(context =>
{
var dataProtectionKeys = context.Set<AppDataProtectionKey>();
var entity = dataProtectionKeys.SingleOrDefault(k => k.FriendlyName == friendlyName);
if (null != entity)
{
entity.XmlData = element.ToString();
dataProtectionKeys.Update(entity);
}
else
{
dataProtectionKeys.Add(new AppDataProtectionKey
{
FriendlyName = friendlyName,
XmlData = element.ToString()
});
}
context.SaveChanges();
});
}
} private static void addCustomDataProtection(this IServiceCollection services, SiteSettings siteSettings)
{
services.AddScoped<IXmlRepository, DataProtectionKeyService>();
services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(serviceProvider =>
{
return new ConfigureOptions<KeyManagementOptions>(options =>
{
var scopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
options.XmlRepository = scope.ServiceProvider.GetService<IXmlRepository>();
}
});
});
services
.AddDataProtection()
.SetDefaultKeyLifetime(siteSettings.CookieOptions.ExpireTimeSpan)
.SetApplicationName(siteSettings.CookieOptions.CookieName)
.UseCryptographicAlgorithms(new AuthenticatedEncryptorConfiguration
{
EncryptionAlgorithm = EncryptionAlgorithm.AES_256_CBC,
ValidationAlgorithm = ValidationAlgorithm.HMACSHA256
});
} services.AddScoped<IXmlRepository, DataProtectionKeyService>()
services.AddSingleton<IXmlRepository, DataProtectionKeyService>()
services.AddSingleton<IXmlRepository, DataProtectionKeyService>();
services.AddSingleton<IConfigureOptions<KeyManagementOptions>>(serviceProvider =>
{
return new ConfigureOptions<KeyManagementOptions>(options =>
{
var scopeFactory = serviceProvider.GetRequiredService<IServiceScopeFactory>();
using (var scope = scopeFactory.CreateScope())
{
options.XmlRepository = scope.ServiceProvider.GetService<IXmlRepository>();
}
});
}); services.Configure<KeyManagementOptions>(options => options.XmlRepository = new DataProtectionKeyService(services.BuildServiceProvider()));
services.AddDataProtection
dotnet add package Microsoft.AspNetCore.DataProtection.EntityFrameworkCore
public class MyKeysContext : DbContext, IDataProtectionKeyContext
{
// A recommended constructor overload when using EF Core
// with dependency injection.
public MyKeysContext(DbContextOptions<MyKeysContext> options)
: base(options) { }
// This maps to the table that stores keys.
public DbSet<DataProtectionKey> DataProtectionKeys { get; set; }
} public int Id { get; set; }
public string FriendlyName { get; set; }
public string XmlData { get; set; } public void ConfigureServices(IServiceCollection services)
{
// using Microsoft.AspNetCore.DataProtection;
services.AddDataProtection()
.PersistKeysToDbContext<MyKeysContext>();
} "C:\Program Files\Git\usr\bin\openssl.exe" genrsa -out private.key 2048 "C:\Program Files\Git\usr\bin\openssl.exe" req -new -x509 -key private.key -out publickey.cer -days 1398 "C:\Program Files\Git\usr\bin\openssl.exe" pkcs12 -export -out idp.pfx -inkey private.key -in publickey.cer
private static X509Certificate2 loadCertificateFromFile(string filePath, string password)
{
// NOTE:
// You should check out the identity of your application pool and make sure
// that the `Load user profile` option is turned on, otherwise the crypto susbsystem won't work.
// For decryption the certificate must be in the certificate store. It's a limitation of how EncryptedXml works.
using (var store = new X509Store(StoreName.My, StoreLocation.CurrentUser))
{
store.Open(OpenFlags.ReadWrite);
store.Add(new X509Certificate2(filePath, password, X509KeyStorageFlags.Exportable));
}
return new X509Certificate2(
filePath,
password,
keyStorageFlags: X509KeyStorageFlags.MachineKeySet | X509KeyStorageFlags.PersistKeySet
| X509KeyStorageFlags.Exportable);
} services
.AddDataProtection()
.SetDefaultKeyLifetime(...)
.SetApplicationName(...)
.ProtectKeysWithCertificate(loadCertificateFromFile("path ...", "123"));