ASP.NET标识如何在不将cookie添加到数据存储区的情况下往返cookie中的自定义声明?

时间:2014-10-14 10:34:01

标签: asp.net-identity asp.net-identity-2

使用ASP.NET Identity 2.1.0,

我正在尝试添加自定义声明,以便将其添加到往返Cookie中,而不是添加到数据存储区。

声明是针对唯一会话 ID,唯一登录,即使是针对相同的UserId(为了更好地审核每个会话/客户端IP地址所执行的操作)。

到目前为止的尝试是:

            Provider = new CookieAuthenticationProvider
            {
                OnResponseSignIn = (x) =>
                {

                    //Let's pretend this is a Session table Id:
                    var st = x.Identity.FindFirstValue("ST");
                    if (string.IsNullOrEmpty(st))
                    {
                        //Damn! always needs regeneration because not round-tripping coming back :-(
                        //Could use Session, but that defeats the purpose of using a cookie...
                        st = Guid.NewGuid().ToString();
                    }
                    x.Identity.AddClaim(new Claim("ST", st));
                    x.OwinContext.Authentication.SignIn(x.Identity);
                },
                // Enables the application to validate the security stamp when the user logs in.
                // This is a security feature which is used when you change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator.OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromSeconds(6),
                    regenerateIdentity: async (manager, user) =>
                    {

                        var x = await user.GenerateUserIdentityAsync(manager);
                        return x;
                    }
                    )
            }
        });   

使用SessionId的缓存(Session / load balanced Shared / etc。),使用UserId作为密钥显然不会起作用(无论ClientIP都会返回相同的SessionId)

使用UserId + ClientIP作为密钥将返回一个SessionId ...但ClientIP明显容易出错,因此等待发生故障。

使用辅助cookie听起来也许它可以工作但是我不愿意为安全系统创建cookie而不了解我将如何减轻这可能带来的每一个劫持问题.......

任何人都有更好的(希望更简单)解决方案吗?

管理将Cookie反序列化为标识的类是什么,然后再返回,检查它是否仍然有效?我可以自定义一个,并在序列化之前在其中添加二级值吗?

感谢您的帮助!

2 个答案:

答案 0 :(得分:0)

user.GenerateUserIdentityAsync(manager);正在向您提出索赔委托人。这是您可以添加自己的声明的理想场所。

或者您可以实施IClaimsIdentityFactory并将其提交给UserManager.ClaimsIdentityFactory。但更好的方法是覆盖提供的ClaimsIdentityFactory并在此之后添加您的声明

blogged about it a while ago,向下滚动到“添加默认声明”部分。

答案 1 :(得分:0)

我想研究如何完全按照我的意愿生成ASP.NET Identity cookie(包含Identity + Claims,以及我的Session),但直到我明白,这就是我用它做的第二次饼干:

OnResponseSignIn = (x) =>
{
    string key = "SessionId";
    string serializedSessionId;
    var cookie = x.OwinContext.Request.Cookies.SingleOrDefault(y => y.Key == key);
    if (!string.IsNullOrEmpty(cookie.Value))
    {
        var serializedAndEncryptedText = cookie.Value;
        serializedSessionId = /*decode*/ serializedAndEncryptedText;
        //...maybe update the Session record's last known Activity date?
        //and or check that the value contains the SessionId:UserId, and if UserId has changed,
        //rebuild a new Session (that's in case Sign out fails to destroy all occurances of it)...
    }
    else
    {
        var check = x.OwinContext.Request.Environment;
        serializedSessionId = new SessionService().CreateSession(HttpContext.Current.Request.UserHostAddress).ToString(); //pretend that we hit the db...
        //TODO: how can we encrypt this value so that it's safer than just ClearText?
        string serializedAndEncryptedText = serializedSessionId; 
        cookie = new KeyValuePair<string, string>(key,serializedAndEncryptedText);
        x.Response.Cookies.Append(cookie.Key, cookie.Value);  
    }
    //TODO: what's not good is that we have to remember to destroy the cookie
    //every time we sign out...there's risk we don't catch every single occurance of it
    //(eg: if the underlying Manager is invoked, rather than the ApplicationManager)

    serializedSessionId = cookie.Value;
    x.Identity.AddClaim(new Claim(key, serializedSessionId));
    x.OwinContext.Authentication.SignIn(x.Identity);
},

然后在单击Login,ExternalLogin或Logout按钮时使用类似于以下内容的方式销毁cookie:

    [HttpPost]
    [ValidateAntiForgeryToken]
    public ActionResult LogOff()
    {

        var sessionIdCookie = this.HttpContext.Request.Cookies["SessionId"];
        if (sessionIdCookie != null)
        {
            sessionIdCookie.Value = string.Empty;
            sessionIdCookie.Expires = DateTime.Now.AddYears(-1);
            this.HttpContext.Response.Cookies.Add(sessionIdCookie);
        }
        AuthenticationManager.SignOut();

        return RedirectToAction("Index", "Home");
    }

sesionservice只不过是我以后为DI优化的以下糟糕的代码:

public class SessionService
{
    public Guid CreateSession(string clientIP)
    {
        Session session =new Session();
        session.DateTimeStartedUtc = DateTime.UtcNow;
        session.ClientIP = clientIP;
        ApplicationDbContext applicationDbContext = new ApplicationDbContext();
        applicationDbContext.Set<Session>().Add(session);
        applicationDbContext.SaveChanges();
        return session.Id;
    }   
}

所有POC代码都进行了大量清理,但是现在它可以在演示MVC应用程序中运行,其中Cookie很常见。接下来,让它在SPA应用程序中工作(但我必须先了解Bearer令牌的工作原理/方式,然后我才能继续前进)。

如果有人看到上述任何愚蠢的内容,请告诉我......正确的做法对我们来说非常重要(显然,安全和所有...... :-))

感谢。