Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/asp.net/31.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/design-patterns/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Asp.net 将SessionStore(ITicketStore)添加到我的应用程序cookie会使我的数据保护提供程序无法工作_Asp.net_Cookies_Asp.net Core_Asp.net Core 2.0 - Fatal编程技术网

Asp.net 将SessionStore(ITicketStore)添加到我的应用程序cookie会使我的数据保护提供程序无法工作

Asp.net 将SessionStore(ITicketStore)添加到我的应用程序cookie会使我的数据保护提供程序无法工作,asp.net,cookies,asp.net-core,asp.net-core-2.0,Asp.net,Cookies,Asp.net Core,Asp.net Core 2.0,tl;博士 拥有.NET Core 2.0应用程序,该应用程序使用数据保护提供程序,在我的域中的所有站点上持久保存密钥文件 工作正常,但应用程序cookie变得太大 使用ITicketStore在cookie上实现会话存储 Cookie的大小大大减小,但是,来自DPP的密钥不再在我的站点中存在 在我的ITicketStore实现中,我应该做些什么来解决这个问题吗?我假设是这样的,因为这就是问题产生的地方,然而,我无法解决它 一些片段: Startup.cs-->配置服务() var key

tl;博士

  • 拥有.NET Core 2.0应用程序,该应用程序使用数据保护提供程序,在我的域中的所有站点上持久保存密钥文件
  • 工作正常,但应用程序cookie变得太大
  • 使用ITicketStore在cookie上实现会话存储
  • Cookie的大小大大减小,但是,来自DPP的密钥不再在我的站点中存在
在我的ITicketStore实现中,我应该做些什么来解决这个问题吗?我假设是这样的,因为这就是问题产生的地方,然而,我无法解决它

一些片段:


Startup.cs-->配置服务()

var keysFolder = $@"c:\temp\_WebAppKeys\{_env.EnvironmentName.ToLower()}";
var protectionProvider = DataProtectionProvider.Create(new DirectoryInfo(keysFolder));
var dataProtector = protectionProvider.CreateProtector(
            "Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware",
            "Cookies",
            "v2");

--snip--

services.AddSingleton<ITicketStore, TicketStore>();

--snip--

services.AddDataProtection()
    .PersistKeysToFileSystem(new DirectoryInfo(keysFolder))
    .SetApplicationName("app_auth");

services.ConfigureApplicationCookie(options =>
{
    options.Cookie.Name = ".XAUTH";
    options.Cookie.Domain = ".domain.com";
    options.ExpireTimeSpan = TimeSpan.FromDays(7);
    options.LoginPath = "/Account/Login";
    options.DataProtectionProvider = protectionProvider;
    options.TicketDataFormat = new TicketDataFormat(dataProtector);
    options.CookieManager = new ChunkingCookieManager();
    options.SessionStore = services.BuildServiceProvider().GetService<ITicketStore>();
});
var keysFolder=$@“c:\temp\\u WebAppKeys\{{u env.EnvironmentName.ToLower()}”;
var protectionProvider=DataProtectionProvider.Create(newdirectoryinfo(keysFolder));
var dataProtector=protectionProvider.CreateProtector(
“Microsoft.AspNetCore.Authentication.Cookies.CookieAuthenticationMiddleware”,
“饼干”,
“v2”);
--剪断--
services.AddSingleton();
--剪断--
services.AddDataProtection()
.PersistKeySystem(新目录信息(密钥文件夹))
.SetApplicationName(“app_auth”);
services.configureApplicationOK(选项=>
{
options.Cookie.Name=“.XAUTH”;
options.Cookie.Domain=“.Domain.com”;
options.ExpireTimeSpan=TimeSpan.FromDays(7);
options.LoginPath=“/Account/Login”;
options.DataProtectionProvider=protectionProvider;
options.TicketDataFormat=新的TicketDataFormat(dataProtector);
options.CookieManager=新建ChunkingCookieManager();
options.SessionStore=services.BuildServiceProvider().GetService();
});

TicketStore.cs

public class TicketStore : ITicketStore
{
    private IMemoryCache _cache;
    private const string KeyPrefix = "AuthSessionStore-";

public TicketStore(IMemoryCache cache)
{
    _cache = cache;
}

public Task RemoveAsync(string key)
{
    _cache.Remove(key);
    return Task.FromResult(0);
}

public Task RenewAsync(string key, AuthenticationTicket ticket)
{
    var options = new MemoryCacheEntryOptions
    {
        Priority = CacheItemPriority.NeverRemove
    };
    var expiresUtc = ticket.Properties.ExpiresUtc;

    if (expiresUtc.HasValue)
    {
        options.SetAbsoluteExpiration(expiresUtc.Value);
    }

    options.SetSlidingExpiration(TimeSpan.FromMinutes(60));

    _cache.Set(key, ticket, options);

    return Task.FromResult(0);
}

public Task<AuthenticationTicket> RetrieveAsync(string key)
{
    AuthenticationTicket ticket;
    _cache.TryGetValue(key, out ticket);
    return Task.FromResult(ticket);
}

public async Task<string> StoreAsync(AuthenticationTicket ticket)
{
    var key = KeyPrefix + Guid.NewGuid();
    await RenewAsync(key, ticket);
    return key;
}
public class TicketStore:ITicketStore
{
私有IMemoryCache\u缓存;
private const string KeyPrefix=“AuthSessionStore-”;
公共票证存储(IMemoryCache缓存)
{
_缓存=缓存;
}
公共任务RemoveAsync(字符串键)
{
_缓存。删除(键);
返回Task.FromResult(0);
}
公共任务续订异步(字符串密钥、身份验证票证)
{
var options=newmemorycacheentryoptions
{
优先级=CacheItemPriority.NeverRemove
};
var expiresUtc=ticket.Properties.expiresUtc;
if(expiresUtc.HasValue)
{
options.SetAbsoluteExpiration(expiresUtc.Value);
}
选项。设置LidingExpiration(TimeSpan.FromMinutes(60));
_cache.Set(键、票据、选项);
返回Task.FromResult(0);
}
公共任务检索同步(字符串键)
{
认证票证;
_cache.TryGetValue(key,out-ticket);
返回任务.FromResult(票证);
}
公共异步任务StoreAsync(身份验证票证)
{
var key=KeyPrefix+Guid.NewGuid();
等待续订异步(密钥、票证);
返回键;
}

我也遇到了这个问题

Microsoft.Owin.Security.Cookies中的sessiondClaim值为“Microsoft.Owin.Security.Cookies SessionId”,而Microsoft.AspNetCore.Authentication.Cookies中的sessiondClaim值为“Microsoft.AspNetCore.Authentication.Cookies SessionId”

即使您实现了分布式会话存储(例如使用RedisCacheTicketStore),这也会导致AspNetCore端由于此代码而导致SessionId丢失错误,如下所述:

我能够用新字符串重新编译AspNetKatana项目,然后在.NET核心端找到SessionID

此外,AuthenticationTicket类似乎不同,因此我通过实现转换方法来转换 Microsoft.Owin.Security.AuthenticationTicket票证到Microsoft.AspNetCore.Authentication.AuthenticationTicket票证,然后使用AspNetCore序列化程序(Microsoft.AspNetCore.Authentication.TicketSerializer)存储票证

使用这些附加方法,可以将RenwAsync方法更改为:

      public Task RenewAsync(string key, Microsoft.Owin.Security.AuthenticationTicket ticket)
        {
            var options = new DistributedCacheEntryOptions();
            var expiresUtc = ticket.Properties.ExpiresUtc;
            if (expiresUtc.HasValue)
            {
                options.SetAbsoluteExpiration(expiresUtc.Value);
            }

            var netCoreTicket = ConvertTicket(ticket);                      
// convert to .NET Core format     
            byte[] netCoreVal = SerializeToBytesNetCore(netCoreTicket);     
// serialize ticket using .NET Core Serializer
            _cache.Set(key, netCoreVal, options);


            return Task.FromResult(0);
        }
我不确定这是否是最好的方法,但它似乎在我的测试项目中起作用,承认我没有在生产中使用它,希望这会有所帮助

更新#1:避免重新编译的替代方法

通过在OWIN端使用两个SessionId声明值重新创建cookie,这似乎也可以起到作用。这将允许您使用标准库,而无需重新编译。我今天上午尝试了它,但没有机会对其进行彻底测试,尽管在我的初始测试中,它确实在两侧正确加载声明。基本上,如果如果修改身份验证票证使其具有两个SessionId声明,它将在两个应用程序中找到会话。此代码段获取cookie,取消保护,添加附加声明,然后替换CookieAuthenticationProvider的OnValidateIdentity事件中的cookie

string cookieName = "myappname";
string KatanaSessionIdClaim = "Microsoft.Owin.Security.Cookies-SessionId";
string NetCoreSessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId";

Microsoft.Owin.Security.Interop.ChunkingCookieManager cookieMgr = new ChunkingCookieManager();

OnValidateIdentity = ctx =>
{
    var incomingIdentity = ctx.Identity;
    var cookie = cookieMgr.GetRequestCookie(ctx.OwinContext, cookieName);
    if (cookie != null)
    {
        var ticket = TicketDataFormat.Unprotect(cookie);
        if (ticket != null)
        {
            Claim claim = ticket.Identity.Claims.FirstOrDefault(c => c.Type.Equals(KatanaSessionIdClaim));
            Claim netCoreSessionClaim = ticket.Identity.Claims.FirstOrDefault(c => c.Type.Equals(NetCoreSessionIdClaim));
            if (netCoreSessionClaim == null)
            {
                // adjust cookie options as needed.
                CookieOptions opts = new CookieOptions();
                opts.Expires = ticket.Properties.ExpiresUtc == null ? 
    DateTime.Now.AddDays(14) : ticket.Properties.ExpiresUtc.Value.DateTime;
                opts.HttpOnly = true;
                opts.Path = "/";
                opts.Secure = true;

                netCoreSessionClaim = new Claim(NetCoreSessionIdClaim, claim.Value);
                ticket.Identity.AddClaim(netCoreSessionClaim);
                string newCookieValue = TicketDataFormat.Protect(ticket);
                cookieMgr.DeleteCookie(ctx.OwinContext, cookieName, opts);
                cookieMgr.AppendResponseCookie(ctx.OwinContext, cookieName, newCookieValue, opts);
            }
        }
    }
}

如果有更好的方法,我很想知道,或者有更好的地方来交换cookie。

我也遇到了这个问题

Microsoft.Owin.Security.Cookies中的sessiondClaim值为“Microsoft.Owin.Security.Cookies SessionId”,而Microsoft.AspNetCore.Authentication.Cookies中的sessiondClaim值为“Microsoft.AspNetCore.Authentication.Cookies SessionId”

即使您实现了分布式会话存储(例如使用RedisCacheTicketStore),这也会导致AspNetCore端由于此代码而导致SessionId丢失错误,如下所述:

我能够用新字符串重新编译AspNetKatana项目,然后在.NET核心端找到SessionID

此外,AuthenticationTicket类似乎不同,因此我通过实现转换方法来转换 Microsoft.Owin.Security.AuthenticationTicket票证到Microsoft.AspNetCore.Authentication.AuthenticationTicket票证,然后使用AspNetCore序列化程序(Microsoft.AspNetCore.Authentication)存储票证
string cookieName = "myappname";
string KatanaSessionIdClaim = "Microsoft.Owin.Security.Cookies-SessionId";
string NetCoreSessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId";

Microsoft.Owin.Security.Interop.ChunkingCookieManager cookieMgr = new ChunkingCookieManager();

OnValidateIdentity = ctx =>
{
    var incomingIdentity = ctx.Identity;
    var cookie = cookieMgr.GetRequestCookie(ctx.OwinContext, cookieName);
    if (cookie != null)
    {
        var ticket = TicketDataFormat.Unprotect(cookie);
        if (ticket != null)
        {
            Claim claim = ticket.Identity.Claims.FirstOrDefault(c => c.Type.Equals(KatanaSessionIdClaim));
            Claim netCoreSessionClaim = ticket.Identity.Claims.FirstOrDefault(c => c.Type.Equals(NetCoreSessionIdClaim));
            if (netCoreSessionClaim == null)
            {
                // adjust cookie options as needed.
                CookieOptions opts = new CookieOptions();
                opts.Expires = ticket.Properties.ExpiresUtc == null ? 
    DateTime.Now.AddDays(14) : ticket.Properties.ExpiresUtc.Value.DateTime;
                opts.HttpOnly = true;
                opts.Path = "/";
                opts.Secure = true;

                netCoreSessionClaim = new Claim(NetCoreSessionIdClaim, claim.Value);
                ticket.Identity.AddClaim(netCoreSessionClaim);
                string newCookieValue = TicketDataFormat.Protect(ticket);
                cookieMgr.DeleteCookie(ctx.OwinContext, cookieName, opts);
                cookieMgr.AppendResponseCookie(ctx.OwinContext, cookieName, newCookieValue, opts);
            }
        }
    }
}
public class OwinAspNetCompatibleCookieManager : ICookieManager
{
    private const string OwinSessionIdClaim = "Microsoft.Owin.Security.Cookies-SessionId";
    private const string AspNetCoreSessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId";

    private readonly ICookieManager actualCookieManager;

    public OwinAspNetCompatibleCookieManager(ICookieManager actualCookieManager) => this.actualCookieManager = actualCookieManager;

    // TODO oh this async void is so so bad, i have to find another way
    public async void AppendResponseCookie(HttpContext context, string key, string value, CookieOptions options)
    {
        IAuthenticationHandler handler = await context.RequestServices.GetRequiredService<IAuthenticationHandlerProvider>().GetHandlerAsync(context, CookieAuthenticationDefaults.AuthenticationScheme).ConfigureAwait(false);

        if (handler is CookieAuthenticationHandler cookieHandler)
        {
            value = MakeOwinAspNetCoreCompatible(key, value, cookieHandler.Options);
        }

        actualCookieManager.AppendResponseCookie(context, key, value, options);
    }

    public void DeleteCookie(HttpContext context, string key, CookieOptions options)
    {
        actualCookieManager.DeleteCookie(context, key, options);
    }

    public string GetRequestCookie(HttpContext context, string key)
    {
        return actualCookieManager.GetRequestCookie(context, key);
    }

    private string MakeOwinAspNetCoreCompatible(string key, string cookieValue, CookieAuthenticationOptions options)
    {
        if (key.Equals("MySharedCookieName") && !string.IsNullOrWhiteSpace(cookieValue))
        {
            AuthenticationTicket ticket = options.TicketDataFormat.Unprotect(cookieValue);

            ClaimsPrincipal principal = ticket.Principal;
            Claim aspNetCoreClaim = ticket.Principal.Claims.FirstOrDefault(x => x.Type.Equals(AspNetCoreSessionIdClaim));
            Claim owinClaim = ticket.Principal.Claims.FirstOrDefault(x => x.Type.Equals(OwinSessionIdClaim));
            Claim[] claims = null;

            if (aspNetCoreClaim != null && owinClaim == null)
            {
                claims = new Claim[] { aspNetCoreClaim, new Claim(OwinSessionIdClaim, aspNetCoreClaim.Value) };
            }
            else if (aspNetCoreClaim == null && owinClaim != null)
            {
                claims = new Claim[] { owinClaim, new Claim(AspNetCoreSessionIdClaim, owinClaim.Value) };
            }

            if (claims?.Length > 0)
            {
                var newIdentity = new ClaimsIdentity(claims, principal.Identity.AuthenticationType);
                principal = new ClaimsPrincipal(newIdentity);
                ticket = new AuthenticationTicket(principal, ticket.AuthenticationScheme);
                cookieValue = options.TicketDataFormat.Protect(ticket);
            }
        }

        return cookieValue;
    }
}
...
options.CookieManager = new OwinAspNetCompatibleCookieManager(new ChunkingCookieManager());
...
public class AspNetCoreCompatibleTicketDataFormat : ISecureDataFormat<AuthenticationTicket> {

    private const string OwinSessionIdClaim = "Microsoft.Owin.Security.Cookies-SessionId";
    private const string AspNetCoreSessionIdClaim = "Microsoft.AspNetCore.Authentication.Cookies-SessionId";

    private readonly ISecureDataFormat<AuthenticationTicket> dataFormat;

    public AspNetCoreCompatibleTicketDataFormat(IDataProtector protector) {
        this.dataFormat = new AspNetTicketDataFormat(protector);
    }

    public string Protect(AuthenticationTicket data) {
        var sessionClaim = data.Identity.FindFirst(OwinSessionIdClaim);
        if (sessionClaim != null) {
            data.Identity.AddClaim(new Claim(AspNetCoreSessionIdClaim, sessionClaim.Value));
        }
        return this.dataFormat.Protect(data);
    }

    public AuthenticationTicket Unprotect(string protectedText) {
        return this.dataFormat.Unprotect(protectedText);
    }
}
app.UseCookieAuthentication(new CookieAuthenticationOptions {
    TicketDataFormat = new AspNetCoreCompatibleTicketDataFormat(
        new DataProtectorShim(...