javascript - 通过angularjs登录时,MVC更新`__RequestVerificationToken`令牌
问题描述
我有一个包含一些 AngularJS 组件的 MVC 网站。
当我使用 angularjs 发出帖子请求时,我总是__RequestVerificationToken
在页面上包含来自隐藏输入的令牌。
我的问题是这样的:
用户启动匿名会话,即未登录。
用户使用 angularjs 组件登录,该组件发送一个 post 请求。我的 MVC 控制器验证凭据和“__RequestVerificationToken”。用户登录后,它会返回一个新令牌。
然后 angularjs 控制器获取新令牌并更新隐藏输入以用于任何未来的请求。
但是,我使用 angularjs 发出的下一个请求验证失败,因为
var tokenCookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName);
(请参见下面的代码示例)仍然是来自匿名会话的旧令牌。
尽管“X-XSRF-Token”(见下面的代码示例)是新的。
如何将包含令牌的 http cookie (tokenCookie) 更新/更新为新的?
我在下面发布了我的代码副本。
我的动作过滤器:
public sealed class WebApiValidateAntiForgeryTokenAttribute : ActionFilterAttribute
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
var headers = filterContext.HttpContext.Request.Headers;
var tokenCookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName);
var tokenHeader = string.Empty;
if (headers.AllKeys.Contains("X-XSRF-Token"))
{
tokenHeader = headers.GetValues("X-XSRF-Token").FirstOrDefault();
}
AntiForgery.Validate(tokenCookie != null ? tokenCookie.Value : null, tokenHeader);
base.OnActionExecuting(filterContext);
}
}
我的登录控制器:
[WebApiValidateAntiForgeryTokenAttribute]
[HttpPost]
public ActionResult login(string email, string password)
{
if (string.IsNullOrWhiteSpace(email) || string.IsNullOrWhiteSpace(password)) return new HttpUnauthorizedResult();
var rq = HttpContext.Request;
var r = validateLogin(email, password, true); // my login handling
if (r.Success)
{
Response.StatusCode = (int)HttpStatusCode.OK;
// within an action construct AJAX response and pass updated token to client
return Json(new
{
__RequestVerificationToken = UpdateRequestVerificationToken(Request)
});
}
else
{
return new HttpUnauthorizedResult();
}
}
/// <summary>
/// resets AntiForgery validation token and update a cookie
/// The new antiforgery cookie is set as the results and sent
/// back to client with Ajax
/// </summary>
/// <param name="Request">request from current context</param>
/// <returns>string - a form token to pass to AJAX response</returns>
private string UpdateRequestVerificationToken(HttpRequestBase Request)
{
string formToken;
string cookieToken;
const string __RequestVerificationToken = "__RequestVerificationToken";
AntiForgery.GetTokens(Request.Form[__RequestVerificationToken], out cookieToken, out formToken);
if (Request.Cookies.AllKeys.Contains(__RequestVerificationToken))
{
HttpCookie cookie = Request.Cookies[__RequestVerificationToken];
cookie.HttpOnly = true;
cookie.Name = __RequestVerificationToken;
cookie.Value = cookieToken;
Response.Cookies.Add(cookie);
}
return formToken;
}
我的 angularjs 登录处理:
login(email, password) {
return new Promise((resolve, reject) => {
return this.AccountRequest.login(email, password)
.then(response => {
const newToken = response.data['__RequestVerificationToken'];
const oldTokenElement = angular.element('input[name="__RequestVerificationToken"]');
oldTokenElement.val(newToken); // confirmed the new token has been updated in the hidden element
resolve(this.refresh.bind(this));
});
})
}
每次我使用 angularjs 发出帖子请求时:
post(uri, queryParams = {}, data = null) {
this.$http.defaults.headers.common['X-XSRF-Token'] = angular.element('input[name="__RequestVerificationToken"]').attr('value');
this.$http.defaults.headers.common["X-Requested-With"] = 'XMLHttpRequest'; // Needed to ensure we get back http error instead of a webpage
const config = this.makeConfig('POST', uri, queryParams, data);
return this.$http(config);
}
makeConfig(method, uri, params = {}, data = null) {
return {
method,
data,
params,
url: uri.toString(),
};
}
解决方案
您的代码与您将值分配给现有 cookie 的方式有点不一致。
您的方法与方法返回的令牌 (
formToken
) 与您的 cookie (cookieToken
) 中设置的令牌不匹配。注意方法的最后一行...
const string __RequestVerificationToken = "__RequestVerificationToken";
HttpCookie cookie = Request.Cookies[__RequestVerificationToken];
// check for null
if (cookie == null)
{
// no cookie found, create it... or respond with an error
throw new NotImplementedException();
}
// grab the cookie
AntiForgery.GetTokens(
Request.Form[__RequestVerificationToken],
out string cookieToken,
out string formToken);
if (!String.IsNullOrEmpty(cookieToken)
{
// update the cookie value(s)
cookie.Values[__RequestVerificationToken] = cookieToken;
//...
}
// update the expiration timestamp
cookie.Expires = DateTime.UtcNow.AddDays(30);
// overwrite the cookie
Response.Cookies.Add(cookie);
// return the NEW token!
return cookieToken;
边注..
你可能不应该const
在这里使用......
const newToken = response.data['__RequestVerificationToken']; // <-- doesn't look right...
const oldTokenElement = angular.element('input[name="__RequestVerificationToken"]');
Aconst
不允许您重新分配该值。因此,newToken
永远不会在客户端重新分配新的令牌值。您可能要考虑在此处使用 alet
或 a 。var
推荐阅读
- ios - 如何使用 xamarin 更新谷歌地图上的 pin 信息
- mysql - 如何导出包含 500 万个原始数据的数据?
- fonts - Github 操作引发“convert-im6.q16:无法读取字体‘FreeMono’”错误和类似情况
- python - 如何在 Airflow Dag 脚本中捕获从 Python 类返回的值?
- .net - 使用 Amazon S3 客户端配置重试策略
- javascript - 在无效时更改输入背景颜色
- bash - 使用 Bash 将字符串转换为 Git 分支名称格式
- java - 将巨大的 CSV 文件内容转换为可快速查询的数据存储的最佳方法?
- reactjs - 每次点击页面时 React Typescript Mutation 调用 api
- wordpress - 我的网站的实时版本和 hpanel 出现不同