无法读取策略 AuthorizationHandler 中的会话数据
Can't read session data in policy AuthorizationHandler
使用 .NET Core 1.1,我创建了一个 AuthorizationHandler:
public class HasStoreAccountAuthorizationHandler : AuthorizationHandler<HasStoreAccountRequirement>
{
private SessionHelper SessionHelper { get; }
public HasStoreAccountAuthorizationHandler(SessionHelper sessionHelper)
{
this.SessionHelper = sessionHelper;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasStoreAccountRequirement requirement)
{
if (this.SessionHelper?.Accounts != null && this.SessionHelper.Accounts.Any()) context.Succeed(requirement);
return Task.FromResult(0);
}
}
我有一个 SessionHelper class,它可以将非原始值序列化到会话中:
public class SessionHelper
{
public IEnumerable<AccountInformation> Accounts
{
get => this.Session.Get<IEnumerable<AccountInformation>>(AccountsKey);
set => this.Session.Set<IEnumerable<AccountInformation>>(AccountsKey, value);
}
public static class SessionHelperExtensionMethods
{
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
}
访问 SessionHelper.Accounts 代码中的任何其他地方都可以正常工作。但是,每当调用策略 AuthorizationHandler 时,都会抛出以下错误:
An exception was thrown while deserializing the token.
System.InvalidOperationException: The antiforgery token could not be decrypted.
---> System.Security.Cryptography.CryptographicException: The key {KEYNAME} was not found in the key ring.
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) --- End of inner exception stack trace --- at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext) System.Security.Cryptography.CryptographicException: The key {KEYNAME} was not found in the key ring.
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
网站机器密钥在web.config和IIS中设置,使用SHA1/AES同时勾选和取消勾选"Generate a unique key for each application"(例如"KEY_VALUE,IsolateApps"和"KEY_VALUE").
我还创建了一个数据保护注册表配置单元 并且 配置了 IIS 应用程序池以根据此 link.
加载用户配置文件
我还在 Startup.cs 中添加了数据保护(多行 added/removed):
services.AddAntiforgery();
services.AddDataProtection()
.SetApplicationName("APPNAME")
.SetDefaultKeyLifetime(TimeSpan.FromDays(365))
.PersistKeysToFileSystem(new DirectoryInfo(Configuration["DataProtection:LocalPaths:KeyLocation"]));
在某些情况下,SessionHelper.Accounts被正确读取并且没有抛出异常。但是,一旦应用程序回收,最终 SessionHelper.Accounts 为 null 并抛出异常。注销系统重新登录对报错没有影响
想法?
我已经通过传递的 AuthorizationHandlerContext 上下文而不是 IHttpContextAccessor 上下文访问会话数据来解决这个问题。
在 SessionHelper 中:
public static IEnumerable<AccountInformation> GetAccounts(HttpContext context)
{
return context.Session.Get<IEnumerable<AccountInformation>>(AccountsKey);
}
在授权处理程序中:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasStoreAccountRequirement requirement)
{
var accounts = SessionHelper.GetAccounts(this.Context.HttpContext);
if (accounts != null && accounts.Any()) context.Succeed(requirement);
return Task.FromResult(0);
}
使用 .NET Core 1.1,我创建了一个 AuthorizationHandler:
public class HasStoreAccountAuthorizationHandler : AuthorizationHandler<HasStoreAccountRequirement>
{
private SessionHelper SessionHelper { get; }
public HasStoreAccountAuthorizationHandler(SessionHelper sessionHelper)
{
this.SessionHelper = sessionHelper;
}
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasStoreAccountRequirement requirement)
{
if (this.SessionHelper?.Accounts != null && this.SessionHelper.Accounts.Any()) context.Succeed(requirement);
return Task.FromResult(0);
}
}
我有一个 SessionHelper class,它可以将非原始值序列化到会话中:
public class SessionHelper
{
public IEnumerable<AccountInformation> Accounts
{
get => this.Session.Get<IEnumerable<AccountInformation>>(AccountsKey);
set => this.Session.Set<IEnumerable<AccountInformation>>(AccountsKey, value);
}
public static class SessionHelperExtensionMethods
{
public static void Set<T>(this ISession session, string key, T value)
{
session.SetString(key, JsonConvert.SerializeObject(value));
}
public static T Get<T>(this ISession session, string key)
{
var value = session.GetString(key);
return value == null ? default(T) : JsonConvert.DeserializeObject<T>(value);
}
}
}
访问 SessionHelper.Accounts 代码中的任何其他地方都可以正常工作。但是,每当调用策略 AuthorizationHandler 时,都会抛出以下错误:
An exception was thrown while deserializing the token.
System.InvalidOperationException: The antiforgery token could not be decrypted.
---> System.Security.Cryptography.CryptographicException: The key {KEYNAME} was not found in the key ring.
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) --- End of inner exception stack trace --- at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgery.GetCookieTokenDoesNotThrow(HttpContext httpContext) System.Security.Cryptography.CryptographicException: The key {KEYNAME} was not found in the key ring.
at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.UnprotectCore(Byte[] protectedData, Boolean allowOperationsOnRevokedKeys, UnprotectStatus& status) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.DangerousUnprotect(Byte[] protectedData, Boolean ignoreRevocationErrors, Boolean& requiresMigration, Boolean& wasRevoked) at Microsoft.AspNetCore.DataProtection.KeyManagement.KeyRingBasedDataProtector.Unprotect(Byte[] protectedData) at Microsoft.AspNetCore.Antiforgery.Internal.DefaultAntiforgeryTokenSerializer.Deserialize(String serializedToken)
网站机器密钥在web.config和IIS中设置,使用SHA1/AES同时勾选和取消勾选"Generate a unique key for each application"(例如"KEY_VALUE,IsolateApps"和"KEY_VALUE").
我还创建了一个数据保护注册表配置单元 并且 配置了 IIS 应用程序池以根据此 link.
加载用户配置文件我还在 Startup.cs 中添加了数据保护(多行 added/removed):
services.AddAntiforgery();
services.AddDataProtection()
.SetApplicationName("APPNAME")
.SetDefaultKeyLifetime(TimeSpan.FromDays(365))
.PersistKeysToFileSystem(new DirectoryInfo(Configuration["DataProtection:LocalPaths:KeyLocation"]));
在某些情况下,SessionHelper.Accounts被正确读取并且没有抛出异常。但是,一旦应用程序回收,最终 SessionHelper.Accounts 为 null 并抛出异常。注销系统重新登录对报错没有影响
想法?
我已经通过传递的 AuthorizationHandlerContext 上下文而不是 IHttpContextAccessor 上下文访问会话数据来解决这个问题。
在 SessionHelper 中:
public static IEnumerable<AccountInformation> GetAccounts(HttpContext context)
{
return context.Session.Get<IEnumerable<AccountInformation>>(AccountsKey);
}
在授权处理程序中:
protected override Task HandleRequirementAsync(AuthorizationHandlerContext context, HasStoreAccountRequirement requirement)
{
var accounts = SessionHelper.GetAccounts(this.Context.HttpContext);
if (accounts != null && accounts.Any()) context.Succeed(requirement);
return Task.FromResult(0);
}