MVC在会话中保存令牌

时间:2012-11-01 03:40:42

标签: asp.net-mvc session authentication asp.net-membership

我正在调用一个服务,我需要在每次发出请求时传递用户的永久安全令牌。

为此,我已将此方法添加到我的基本控制器类:

protected UserData getUsr()
{
        try
        {
            UserData usr = new UserData();
            usr.SecurityToken = Session["secToken"].ToString();

            MembershipUser mvcUser = Membership.GetUser(HttpContext.User.Identity.Name);
            usr.Id = (int)mvcUser.ProviderUserKey;

            return usr;
        }
        catch (Exception ex)
        {
            log.Debug("Could not create usr object", ex);
            throw new Exception("Could not authenticate");
        }
    }

这里的问题是,有时User.Identity数据超出了会话数据,导致用户看到他们登录但随后他们的请求失败时会发生奇怪的错误。

是否有更好的方法来存储此令牌/我可以存储它以便在User.Identity对象到期时它将过期吗?

另外,如果有人知道HttpContext和MVC授权过滤器的一些好的基本理解示例/文档会很棒。

4 个答案:

答案 0 :(得分:5)

我会在表单身份验证cookie本身中存储用户的安全令牌。 FormsAuthenticationTicket类包含UserData属性,您可以在其中包含附加信息。

  

UserData属性中指定的值包含在内   身份验证票证cookie和其他票证字段一样   基于表单身份验证系统进行加密和验证   配置。

以下是article,其中介绍了如何将其他信息存储到表单身份验证Cookie。

This是一篇很重要的文章,解释了将更多数据存储到表单身份验证中。 cookie以及如何阅读它。代码是用VB编写的,格式不正确。您必须向下滚动到步骤4:在故障单中存储其他用户数据

这个thread会让您快速回答如何从Cookie中读取UserData

我会创建一个自定义ValueProvider,就像描述here的那个,它将从auth中读取安全令牌。 cookie和动作参数的提要。

答案 1 :(得分:1)

您可以将用户安全令牌,IP地址和时间戳放在字符串中。使用AES等对称算法对字符串进行加密,并将其作为cookie进行加密。然后更改您的代码以从cookie中读取。您可以验证cookie中的IP地址是否与用户IP地址匹配,这可以防止有人窃取cookie值并重放它。 Here是关于AES的MSDN文档(Rjindael是原始名称)。在此方案中,令牌将在cookie到期和/或达到超时之前到期。我强烈建议你放一个超时而不是永久或持久,这将使该方案不太安全,以排除超时。同时将时间戳放在cookie值的开头,由于这些算法的CBC模式,它会影响加密字符串看起来的方式,因为开始时位的变化(雪崩效应)。

ASP.NET成员资格提供程序还有一个身份验证cookie,因此该cookie不应在成员资格cookie之前到期。会话必须在超时时间到期,因为无法保证用户仍然在那里,因为HTTP是无状态的,而cookie在用户的控制之下,并且每次发出请求时都会传递。

getUsr功能

protected UserData getUsr()
{
    try
    {
        UserData usr = new UserData();

        string token = Request.Cookies["secToken"].Value;

        // implement RijndaelManaged encryption/decryption scheme
        // this can also be serialized as an object to make cleaner
        var tokenValues = Decrypt(token).Split(',');

        // The timeout expired
        if (DateTime.Now > DateTime.Parse(tokenValues[1]))
        {
            throw new Exception("Timeout");
        }

        // someone stole this cookie or is on a different internet connection
        if (tokenValues[0] != System.Web.HttpContext.Current.Request.UserHostAddress)
        {
            throw new Exception("Invalid IP");
        }

        // You're ok everything checks out
        usr.SecurityToken = tokenValues[3].ToString();

        MembershipUser mvcUser = Membership.GetUser(HttpContext.Current.User.Identity.Name);
        usr.Id = (int)mvcUser.ProviderUserKey;

        return usr;
    }
    catch (Exception ex)
    {
        log.Debug("Could not create usr object", ex);
        throw new Exception("Could not authenticate");
    }
}

答案 2 :(得分:1)

也许我说的是非常愚蠢的,但在过去我遇到了类似的问题,我通过简单地设置会话到期时间大于登录的到期时间来解决它。此外,您可以使用安全令牌进入网站b,刷新会话数据,因此确保它们将在用户登录的整个时间内持续。 会话具有更长持续时间的事实不会导致问题,因为只有登录用户可以使用该数据,并且当新用户登录时,旧会话条目被替换。

答案 3 :(得分:0)

如果User.Identity比会话更长,为什么不将令牌存储为身份中的Claim?类似的东西:

var claims = new[]
{
    new Claim("access_token", string.Format("Bearer {0}", token)),
};

var identity = new ClaimsIdentity(claims, DefaultAuthenticationTypes.ApplicationCookie);

Request.GetOwinContext().Authentication.SignIn(options, identity);