MVC обновляет токен `__RequestVerificationToken` при входе через angularjs - PullRequest
0 голосов
/ 14 октября 2018

У меня есть веб-сайт MVC с некоторыми компонентами AngularJS.

Когда я делаю запрос на публикацию с помощью angularjs, я всегда включаю токен __RequestVerificationToken со скрытого ввода на странице.

Моя проблема заключается в следующем:

Пользователь запускает анонимный сеанс, т.е. не вошел в систему.

Пользователь входит в систему, используя компонент angularjs, который отправляет запрос на публикацию.Мой контроллер MVC проверяет учетные данные и '__RequestVerificationToken'.Как только пользователь вошел в систему, он возвращает новый токен.

Затем контроллер angularjs берет новый токен и обновляет скрытый ввод, который будет использоваться для любых будущих запросов.

Однако следующийзапрос, который я использую с помощью angularjs, не проходит проверку, потому что var tokenCookie = filterContext.HttpContext.Request.Cookies.Get(AntiForgeryConfig.CookieName); (см. пример кода ниже) все еще является старым токеном от анонимного сеанса.

Хотя «X-XSRF-Token» (см. пример кода ниже)приходит как новый.

Как мне также обновить / обновить файл cookie http (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(),
    };
}

1 Ответ

0 голосов
/ 22 октября 2018

Ваш код немного отличается от того, как вы присваиваете значение существующему файлу 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"]');

A const не позволит вам переназначить значение.Следовательно, newToken никогда не будет переназначаться новому значению токена на стороне клиента.Возможно, вы захотите использовать вместо этого let или var.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...