Cookie 身份验证 ASP.NET Core

Posted

技术标签:

【中文标题】Cookie 身份验证 ASP.NET Core【英文标题】:Cookie Authentication ASP.NET Core 【发布时间】:2017-03-30 12:57:27 【问题描述】:

我可以在ITicketStore 中使用MemoryCache 来存储AuthenticationTicket 吗?

背景:我的网络应用正在使用 Cookie 身份验证:

app.UseCookieAuthentication(new CookieAuthenticationOptions

    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    LoginPath = new PathString("/Authentication/SignIn"),
    LogoutPath = new PathString("/Authentication/SignOut"),
    ReturnUrlParameter = "/Authentication/SignIn"
);

我的 web api 使用访问令牌 (OAuth2) 处理授权过程。

有时(在某些浏览器上)会抛出以下异常:

发生未处理的异常:分块的 cookie 不完整。只找到了预期的 2 个块中的 1 个,总共 4021 个字符。可能已超出客户端大小限制。

cookie 显然太大了。这很奇怪,因为我不使用很多声明。所有这些都是默认声明(nameidentifier、nonce、exp 等)。我现在正在尝试在CookieAuthenticationOptions 上实现我自己的ITicketStore 作为SessionStoreAuthenticationTicket 将存储在 MemoryCache 中(就像在这个 sample 中一样)。我对整个主题很陌生,不确定这是否是一种好方法以及MemoryCache 是否是有效的解决方案。

【问题讨论】:

github.com/aspnet/Security/issues/830 这个 github issue 可能对你有帮助。 【参考方案1】:

我可以在ITicketStore 中使用MemoryCache 来存储AuthenticationTicket 吗?

当然,这是我使用了将近一年的实现。

app.UseCookieAuthentication(new CookieAuthenticationOptions

    AuthenticationScheme = "App.Cookie",
    AutomaticAuthenticate = true,
    AutomaticChallenge = true,
    LoginPath = new PathString("/Authentication/SignIn"),
    LogoutPath = new PathString("/Authentication/SignOut"),
    ReturnUrlParameter = "/Authentication/SignIn",
    SessionStore = new MemoryCacheStore(cache)
);

MemoryCacheStore 的实现如下所示,它遵循您共享的 the example:

public class MemoryCacheStore : ITicketStore

    private const string KeyPrefix = "AuthSessionStore-;
    private readonly IMemoryCache _cache;

    public MemoryCacheStore(IMemoryCache cache)
    
        _cache = cache;
    

    public async Task<string> StoreAsync(AuthenticationTicket ticket)
    
        var key = KeyPrefix + Guid.NewGuid();
        await RenewAsync(key, ticket);
        return key;
    

    public Task RenewAsync(string key, AuthenticationTicket ticket)
    
        // https://github.com/aspnet/Caching/issues/221
        // Set to "NeverRemove" to prevent undesired evictions from gen2 GC
        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 Task RemoveAsync(string key)
    
        _cache.Remove(key);
        return Task.FromResult(0);
    

【讨论】:

感谢您的回复。与使用 cookie 相比,这种方法有什么缺点吗? Web 应用程序内存不足是我唯一能想到的。 它实际上是在使用 cookie,因此是 UseCookieAuthentication。如果内存是一个问题,请考虑这些过期并且一旦过期就会丢失内存的事实,因为它们将被释放和清理。此外,它们很小……同样,取决于您设置托管应用程序的方式,可以确定它是否会产生影响。您希望能够扩展。 没有内存并不是真正的问题。我只是在考虑一般的缺点。是的,它使用 cookie,但 AuthenticationTicket 本身并没有存储在 cookie 中,只有参考。这是正确的吗? 不正确,cookie 中的所有内容都被反序列化为 ClaimsPrinicipal .. 而这个原则构成了 AuthenticationTicket github.com/aspnet/Security/blob/…。 啊,好吧,这很有道理。但是必须为用户在本地存储一些东西吗?也许是从StoreAsync 方法返回的密钥?或者服务器是如何识别用户的?

以上是关于Cookie 身份验证 ASP.NET Core的主要内容,如果未能解决你的问题,请参考以下文章