问题描述
我正在构建一个单页应用程序并遇到防伪令牌问题.
我知道为什么会出现这个问题,只是不知道如何解决.
发生以下情况时我收到错误消息:
- 未登录的用户加载一个对话框(带有生成的防伪令牌)
- 用户关闭对话框
- 用户登录
- 用户打开同一个对话框
- 用户在对话框中提交表单
防伪令牌适用于用户",但当前用户是用户名"
发生这种情况的原因是我的应用程序是 100% 单页的,当用户通过 ajax 帖子成功登录到 /Account/JsonLogin
时,我只需用从服务器返回的经过身份验证的视图",但不重新加载页面.
我知道这是原因,因为如果我在第 3 步和第 4 步之间简单地重新加载页面,就不会出错.
所以看起来加载的表单中的 @Html.AntiForgeryToken()
在页面重新加载之前仍然返回旧用户的令牌.
如何更改 @Html.AntiForgeryToken()
以返回新的、经过身份验证的用户的令牌?
我在每个 Application_AuthenticateRequest
上注入了一个带有自定义 IIdentity
的新 GenericPrincipal
,所以到 @Html.AntiForgeryToken()
被调用 HttpContext.Current.User.Identity
实际上是我的自定义身份,IsAuthenticated
属性设置为 true 并且 @Html.AntiForgeryToken
似乎仍然为旧用户呈现令牌,除非我重新加载页面.
发生这种情况是因为防伪令牌将用户的用户名作为加密令牌的一部分嵌入,以便更好地进行验证.当您第一次调用 @Html.AntiForgeryToken()
时,用户未登录,因此用户名的令牌将为空字符串,在用户登录后,如果您不替换反伪造令牌它不会通过验证,因为初始令牌是用于匿名用户的,现在我们有一个具有已知用户名的经过身份验证的用户.
您有几个选项可以解决这个问题:
这一次让您的 SPA 执行完整的 POST,当页面重新加载时,它将嵌入一个防伪令牌,其中嵌入了更新后的用户名.
仅使用
@Html.AntiForgeryToken()
获得局部视图,并在登录后立即执行另一个 AJAX 请求并将现有的防伪令牌替换为请求的响应.
请注意,设置 AntiForgeryConfig.SuppressIdentityHeuristicChecks = true
不会禁用用户名验证,它只会更改验证的工作方式.请参阅 ASP.NET MVC 文档,源代码,其中读取该属性,以及 源代码,无论该配置的值如何,都会验证令牌中的用户名.
I'm building a single page application and experiencing an issue with anti-forgery tokens.
I know why the issue happens I just don't know how to fix it.
I get the error when the following happens:
- Non-logged-in user loads a dialog (with a generated anti-forgery token)
- User closes dialog
- User logs in
- User opens the same dialog
- User submits form in dialog
The reason this happens is because my application is 100% single-page, and when a user successfully logs in through an ajax post to /Account/JsonLogin
, I simply switch out the current views with the "authenticated views" returned from the server but do not reload the page.
I know this is the reason because if I simple reload the page between steps 3 and 4, there is no error.
So it seems that @Html.AntiForgeryToken()
in the loaded form still returns a token for the old user until the page is reloaded.
How can I change @Html.AntiForgeryToken()
to return a token for the new, authenticated user?
I inject a new GenericalPrincipal
with a custom IIdentity
on every Application_AuthenticateRequest
so by the time @Html.AntiForgeryToken()
gets called HttpContext.Current.User.Identity
is, in fact my custom Identity with IsAuthenticated
property set to true and yet @Html.AntiForgeryToken
still seems to render a token for the old user unless I do a page reload.
This is happening because the anti-forgery token embeds the username of the user as part of the encrypted token for better validation. When you first call the @Html.AntiForgeryToken()
the user is not logged in so the token will have an empty string for the username, after the user logs in, if you do not replace the anti-forgery token it will not pass validation because the initial token was for anonymous user and now we have an authenticated user with a known username.
You have a few options to solve this problem:
Just this time let your SPA do a full POST and when the page reloads it will have an anti-forgery token with the updated username embedded.
Have a partial view with just
@Html.AntiForgeryToken()
and right after logging in, do another AJAX request and replace your existing anti-forgery token with the response of the request.
Note that setting AntiForgeryConfig.SuppressIdentityHeuristicChecks = true
does not disable username validation, it simply changes how that validation works. See the ASP.NET MVC docs, the source code where that property is read, and the source code where the username in the token is validated regardless of the value of that config.
这篇关于防伪令牌适用于用户“"但当前用户是“用户名"的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!