【问题标题】:Server side claims caching with Owin Authentication使用 Owin 身份验证的服务器端声明缓存
【发布时间】:2013-10-12 02:43:11
【问题描述】:

我有一个曾经使用FormsAuthentication 的应用程序,不久前我将它从WindowsIdentityFramework 切换为使用IdentityModel,这样我就可以从基于声明的身份验证中受益,但是使用起来相当难看,而且实施。所以现在我在看OwinAuthentication

我正在研究OwinAuthenticationAsp.Net Identity 框架。但是Asp.Net Identity 框架目前唯一的实现使用EntityModel,而我正在使用nHibernate。所以现在我想尝试绕过Asp.Net Identity,直接使用Owin Authentication。我终于能够使用来自“How do I ignore the Identity Framework magic and just use the OWIN auth middleware to get the claims I seek?”的提示获得有效登录,但现在我持有声明的 cookie 相当大。当我使用IdentityModel 时,我能够使用服务器端缓存机制来缓存服务器上的声明,并且 cookie 只是为缓存信息保存了一个简单的令牌。 OwinAuthentication 中是否有类似的功能,还是我必须自己实现?

我希望我会在其中一艘船上......

  1. cookie 保持为 3KB,哦,它有点大。
  2. Owin 中启用类似于IdentityModel 的SessionCaching 的功能,我不知道。
  3. 编写我自己的实现来缓存导致 cookie 膨胀的信息,看看我在应用程序启动时配置 Owin 时是否可以连接它。
  4. 我做错了,有一种我没有想到的方法,或者我在Owin中滥用了一些东西。

    public class OwinConfiguration
    {
        public void Configuration(IAppBuilder app)
        {
            app.UseCookieAuthentication(new CookieAuthenticationOptions
            {
                AuthenticationType = "Application",
                AuthenticationMode = AuthenticationMode.Active,
                CookieHttpOnly = true,
                CookieName = "Application",
                ExpireTimeSpan = TimeSpan.FromMinutes(30),
                LoginPath = "/Login",
                LogoutPath = "/Logout",
                ReturnUrlParameter="ReturnUrl",
                SlidingExpiration = true,
                Provider = new CookieAuthenticationProvider()
                {
                    OnValidateIdentity = async context =>
                    {
                        //handle custom caching here??
                    }
                }
                //CookieName = CookieAuthenticationDefaults.CookiePrefix + ExternalAuthentication.ExternalCookieName,
                //ExpireTimeSpan = TimeSpan.FromMinutes(5),
            });
        }
    }
    

更新 使用宏业提供的信息,我能够得到想要的效果,我想出了以下逻辑......

Provider = new CookieAuthenticationProvider()
{
    OnValidateIdentity = async context =>
    {
        var userId = context.Identity.GetUserId(); //Just a simple extension method to get the ID using identity.FindFirst(x => x.Type == ClaimTypes.NameIdentifier) and account for possible NULLs
        if (userId == null) return;
        var cacheKey = "MyApplication_Claim_Roles_" + userId.ToString();
        var cachedClaims = System.Web.HttpContext.Current.Cache[cacheKey] as IEnumerable<Claim>;
        if (cachedClaims == null)
        {
            var securityService = DependencyResolver.Current.GetService<ISecurityService>(); //My own service to get the user's roles from the database
            cachedClaims = securityService.GetRoles(context.Identity.Name).Select(role => new Claim(ClaimTypes.Role, role.RoleName));
            System.Web.HttpContext.Current.Cache[cacheKey] = cachedClaims;
        }
        context.Identity.AddClaims(cachedClaims);
    }
}

【问题讨论】:

  • 为什么不使用 ASP.NET 标识的自定义实现? NuGet 上已经有实现。
  • 我处理这个的时候没有,你指的是什么?
  • Nhibernate.AspNet.Identity 和 AspNet.Identity.NHibernate(我使用 SharpArchitecture 和 FluentNHibernate 创建了这个。不过它是一个预发布版本)
  • CookieAuthenticationOptions 对象上有一个名为“SessionStore”的字段,它被描述为“一个可选的容器,用于存储跨请求的身份。使用时,只会向客户端发送会话标识符。这可以用来缓解非常大的身份的潜在问题。”这似乎是你想要做的。不幸的是,我找不到任何关于如何实际创建这些 SessionStores 的参考。
  • 声明System.Security.Claims.ClaimGetUserId 扩展的代码?

标签: asp.net authentication claims-based-identity owin


【解决方案1】:

您可以实现 IAuthenticationSessionStore 将 cookie 存储到数据库中。

这是在 redis 中存储 cookie 的示例。

app.UseCookieAuthentication(new CookieAuthenticationOptions
{
AuthenticationType = CookieAuthenticationDefaults.AuthenticationType,
SessionStore = new RedisSessionStore(new TicketDataFormat(dataProtector)),
LoginPath = new PathString("/Auth/LogOn"),
LogoutPath = new PathString("/Auth/LogOut"),

});

查看完整示例 at here

【讨论】:

  • 如果 auth cookie 将保存在 db 中,那么客户端将存储什么?
  • 只有会话标识符存储在客户端
【解决方案2】:
Provider = new CookieAuthenticationProvider()
{
    OnResponseSignIn = async context =>
    {
        // This is the last chance before the ClaimsIdentity get serialized into a cookie. 
        // You can modify the ClaimsIdentity here and create the mapping here. 
        // This event is invoked one time on sign in. 
    }, 
    OnValidateIdentity = async context => 
    {
        // This method gets invoked for every request after the cookie is converted 
        // into a ClaimsIdentity. Here you can look up your claims from the mapping table. 
    }
}

【讨论】:

  • 我已经知道那段代码,复制/粘贴它并不能回答我的问题。
  • 查看上面显示的 OnResponseSignIn 事件以及其中的评论。我提到的 OnValidateIdentity 会为每个请求调用。基本上有 2 点 - OnResponseSignIn 创建映射,OnValidateIdentity - 查找声明。
【解决方案3】:

OWIN cookie 身份验证中间件尚不支持会话缓存之类的功能。 #2 不是一个选项。

#3 是正确的方法。正如 Prabu 建议的那样,您应该在代码中执行以下操作:

OnResponseSignIn:

  • 使用唯一键 (GUID) 将 context.Identity 保存在缓存中
  • 创建一个嵌入了唯一键的新 ClaimsIdentity
  • 将 context.Identity 替换为新的身份

OnValidateIdentity:

  • 从 context.Identity 获取唯一键声明
  • 通过唯一键获取缓存的标识
  • 用缓存的身份调用 context.ReplaceIdentity

我本来打算建议你对 cookie 进行 gzip,但我发现 OWIN 已经在它的 TicketSerializer 中这样做了。不适合你。

【讨论】:

  • 在我的案例中,导致 cookie 大小膨胀的声明是整个站点中用于权限的角色。是否有理由我应该缓存并替换整个身份,或者我可以保持身份原封不动,只缓存并在OnValidateIdentity 任务中添加缺少的声明ClaimTypes.Role
  • 当然。您绝对可以自定义代码以满足您的应用程序的要求。我发布的是从服务器缓存中引用 cookie 的通用方法。
  • Create a new ClaimsIdentity embedded with the unique keyReplace context.Identity with the new identity 的完整源代码示例?
猜你喜欢
  • 2014-02-20
  • 1970-01-01
  • 2011-03-02
  • 2013-10-24
  • 2018-02-26
  • 2017-11-26
  • 2011-11-04
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多