4

我正在调用一项服务,并且我需要在我提出的每个请求中传递用户的永久安全令牌。

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

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

4 回答 4

5

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

属性中指定的值UserData包含在身份验证票证 cookie 中,并且与其他票证字段一样,根据表单身份验证系统的配置进行加密和验证。

这是一篇文章,描述了如何将附加信息存储到表单身份验证 cookie。

是一篇大文章,它解释了有关将附加数据存储到表单身份验证中的许多内容。cookie 以及如何阅读它。代码是用VB编写的,格式不正确。您必须向下滚动到第 4 步:在工单中存储其他用户数据

主题将为您提供如何UserData从 cookie 中读取的快速答案。

我会去创建一个像这里ValueProvider描述的那样的自定义,它将从身份验证中读取安全令牌。cookie 并提供给操作参数。

于 2012-11-06T09:47:39.983 回答
1

您可以将用户安全令牌、IP 地址和时间戳放在字符串中。使用对称算法(如 AES)加密字符串并将其作为 cookie 放置。然后更改您的代码以从 cookie 中读取。您可以验证 cookie 中的 ip 地址是否与用户的 ip 地址匹配,这将防止有人窃取 cookie 值并重放它。 这里是关于 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");
    }
}
于 2012-11-03T14:47:54.740 回答
1

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

于 2012-11-04T12:14:50.037 回答
0

如果User.Identity超过 Session,为什么不将令牌作为 a 存储Claim在 Identity 中?就像是:

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);
于 2016-10-31T21:22:58.933 回答