我们一直在“未提供所需的防伪令牌或无效。”错误,并进行了一些进一步的调查,我设法以最简单的形式重新创建问题 - 我要么做一些完全错误的事情,要么这是反伪造令牌系统的限制。
无论哪种方式,我都会感激一些建议!
清空MVC 2项目: 一个视图页面,一个控制器
视图:
<%--Sign in form:--%>
<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
<%= Html.AntiForgeryToken()%>
<input type="submit" value="Sign in" />
<%}%>
控制器:
public ActionResult Index()
{
ViewData["status"] = "Index";
return View();
}
[ValidateAntiForgeryToken]
public ActionResult SignIn()
{
ViewData["status"] = "Signed In!";
FormsAuthentication.SetAuthCookie("username", false);
return View("Index");
}
[编辑:简化代码示例]
要重新创建例外,请打开两个非登录标签 - 在第一个标签页上登录,然后在第二个标签页上登录。
第二个选项卡将始终抛出防伪异常,我想正确的行为是重定向到登录页面(共享原始登录选项卡的会话/身份验证)
任何建议都将不胜感激!
干杯, 戴夫
答案 0 :(得分:5)
查看MVC 2源代码,看起来AntiForgeryToken隐藏字段包含User.Identity.Name序列化,如果您已登录。在ValidateAntiForgeryTokenAttribute
的第69行,它似乎随后检查您的令牌当前的User.Identity.Name。
string currentUsername = AntiForgeryData.GetUsername(filterContext.HttpContext.User);
if (!String.Equals(formToken.Username, currentUsername, StringComparison.OrdinalIgnoreCase)) {
// error: form token is not valid for this user
// (don't care about cookie token)
throw CreateValidationException();
}
因为在您的其他标签中,您现在已登录上面的代码,使现有的令牌无效,该令牌不包含User.Identity.Name。
这可以通过在该检查周围添加!string.IsNullOrEmpty(formToken.Username)
来解决,但我不知道这是否会打开安全问题加上它意味着拥有自定义MVC 2 Build。
答案 1 :(得分:0)
你可以使用相同的盐:
<% using(Html.BeginForm("SignIn", "Home", FormMethod.Post)) {%>
<%= Html.AntiForgeryToken("123")%>
<input type="submit" value="Sign in" />
<%}%>
<% using(Html.BeginForm("Protected", "Home", FormMethod.Post)) {%>
<%= Html.AntiForgeryToken("456")%>
<input type="submit" value="Do secret stuff" />
<%}%>
在你的控制器中:
[ValidateAntiForgeryToken(Salt = "123")]
public ActionResult SignIn()
{
ViewData["status"] = "Signed In!";
FormsAuthentication.SetAuthCookie("username", false);
return View("Index");
}
[Authorize]
[ValidateAntiForgeryToken(Salt = "456")]
public ActionResult Protected()
{
ViewData["status"] = "Authed";
return View("Index");
}
对另一个标记执行相同操作,但请务必选择不同的盐。
答案 2 :(得分:-2)
这个问题的真正答案就是你不应该在登录表格上使用反伪造令牌!
“伪造”成为登录表单上的用户毫无意义 - 他们没有登录!