我正在调用一个服务,我需要在每次发出请求时传递用户的永久安全令牌。
为此,我已将此方法添加到我的基本控制器类:
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授权过滤器的一些好的基本理解示例/文档会很棒。
答案 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);