Токен защиты от подделки предназначен для пользователя ""но текущий пользователь-это" имя пользователя"


Я создаю одностраничное приложение и испытываю проблему с маркерами защиты от подделки.

Я знаю, почему проблема происходит, я просто не знаю, как это исправить.

я получаю ошибку, когда происходит следующее:

  1. незарегистрированный пользователь загружает диалоговое окно (с сгенерированным токеном защиты от подделки)
  2. пользователь закрывает диалоговое окно
  3. пользователь входит в систему
  4. пользователь открывает тот же диалог
  5. пользователь отправляет форму в диалоге

маркер защиты от подделки предназначен для пользователя "" но текущий пользователь "имя пользователя"

причина этого заключается в том, что мое приложение на 100% одностраничное, и когда пользователь успешно входит в систему через ajax post в /Account/JsonLogin, Я просто переключаю текущие представления с" аутентифицированными представлениями", возвращенными с сервера, но не перезагружайте страницу.

Я знаю, что это причина, потому что если я простая перезагрузка страницы между шагами 3 и 4, нет ошибки.

получается, что @Html.AntiForgeryToken() в загруженной форме по-прежнему возвращает маркер для старого пользователя, пока страница не будет перезагружена.

как я могу изменить @Html.AntiForgeryToken() чтобы вернуть токен для нового аутентифицированного пользователя?

Я ввожу новый GenericalPrincipal с пользовательским IIdentity на каждые Application_AuthenticateRequest так @Html.AntiForgeryToken() вызывается HttpContext.Current.User.Identity это, на самом деле моя пользовательская идентичность с IsAuthenticated набор свойств к истине и все же @Html.AntiForgeryToken по-прежнему кажется, чтобы сделать токен для старого пользователя, если я не делаю перезагрузку страницы.

10 113

10 ответов:

это происходит потому, что анти-подделки маркер используется имя пользователя в качестве части зашифрованного маркера для лучшей проверки. При первом вызове @Html.AntiForgeryToken() пользователь не вошел в систему, поэтому маркер будет иметь пустую строку для имени пользователя, после входа пользователя в систему, если вы не замените маркер защиты от подделки, он не пройдет проверку, потому что первоначальный маркер был для анонимного пользователя, и теперь у нас есть аутентифицированный пользователь с известным именем пользователя.

у вас есть несколько вариантов решения этой проблемы:

  1. только на этот раз пусть ваш спа-центр сделает полный пост, и когда страница перезагрузится, у нее будет маркер защиты от подделки с внедренным обновленным именем пользователя.

  2. есть частичный вид только с @Html.AntiForgeryToken() и сразу после входа в систему выполните еще один запрос AJAX и замените существующий маркер защиты от подделки ответом на запрос.

  3. просто отключите проверку личности анти-подделка выполняется проверка. Добавьте следующее к вашему событий Application_Start способ: AntiForgeryConfig.SuppressIdentityHeuristicChecks = true.

чтобы исправить ошибку вам нужно разместить OutputCache Аннотация данных на Get ActionResult страницы входа в систему как:

[OutputCache(NoStore=true, Duration = 0, VaryByParam= "None")] 
public ActionResult Login(string returnUrl)

Это происходит много раз с моим приложением, поэтому я решил google для него!

Я нашел простое объяснение этой ошибки! Пользователь дважды щелкает кнопку для входа в систему! Вы можете увидеть другого пользователя, говорящего об этом по ссылке ниже:

MVC 4 при условии, что маркер защиты от подделки был предназначен для пользователя"", но текущий пользователь - "пользователь"

Я надеюсь, что это помогает! =)

У меня была та же проблема, и этот грязный хак исправил ее, по крайней мере, пока я не смогу исправить ее более чистым способом.

    public ActionResult Login(string returnUrl)
    {
        if (AuthenticationManager.User.Identity.IsAuthenticated)
        {
            AuthenticationManager.SignOut();
            return RedirectToAction("Login");
        }

...

У меня была довольно специфическая, но похожая проблема в процессе регистрации. Как только пользователь нажал на ссылку электронной почты, отправленную им, они вошли в систему и отправили прямо на экран сведений об учетной записи, чтобы заполнить дополнительную информацию. Мой код:

    Dim result = Await UserManager.ConfirmEmailAsync(userId, code)
    If result.Succeeded Then
        Dim appUser = Await UserManager.FindByIdAsync(userId)
        If appUser IsNot Nothing Then
            Dim signInStatus = Await SignInManager.PasswordSignInAsync(appUser.Email, password, True, shouldLockout:=False)
            If signInStatus = SignInStatus.Success Then
                Dim identity = Await UserManager.CreateIdentityAsync(appUser, DefaultAuthenticationTypes.ApplicationCookie)
                AuthenticationManager.SignIn(New AuthenticationProperties With {.IsPersistent = True}, identity)
                Return View("AccountDetails")
            End If
        End If
    End If

Я обнаружил, что представление возврата ("AccountDetails") давало мне исключение токена, я предполагаю, потому что функция ConfirmEmail была украшена AllowAnonymous, но функция AccountDetails имела ValidateAntiForgeryToken.

изменение возврата на Return RedirectToAction ("AccountDetails") решило проблему для меня.

У меня есть то же самое исключение, происходящее большую часть времени на рабочем сервере.

Почему это происходит?

это происходит, когда пользователь войти с действительными учетными данными и после входа в систему и перенаправить на другую страницу, и после того, как они нажимают кнопку Назад покажет страницу входа и снова он ввел действительные учетные данные, что время это исключение будет происходить.

как решить?

просто добавьте эту строку и работать идеально, нет получить ошибку.

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
[OutputCache(NoStore=true, Duration=0, VaryByParam="None")]

public ActionResult Login(string returnUrl)

вы можете проверить это, поставив точку останова в первой строке вашего действия входа (Get). Перед добавлением директивы OutputCache точка останова будет хит на первой загрузке, но после нажатия на кнопку Назад в браузере не. После добавления директивы вы должны в конечном итоге с точки останова попадания каждый раз, поэтому AntiForgeryToken будет правильно, а не пустой.

у меня была такая же проблема с одной страницей ASP.NET MVC Core application. Я решил это, установив HttpContext.User во всех действиях контроллера, которые изменяют текущие утверждения идентификации (поскольку MVC делает это только для последующих запросов, как обсуждалось здесь). Я использовал фильтр результатов вместо промежуточного программного обеспечения, чтобы добавить файлы cookie antiforgery к моим ответам, которые убедились, что они были созданы только после того, как действие MVC вернулось.

контроллер (NB. Я управляю пользователями с помощью ASP.NET ядро идентичности):

[Authorize]
[ValidateAntiForgeryToken]
public class AccountController : Controller
{
    private SignInManager<IdentityUser> signInManager;
    private UserManager<IdentityUser> userManager;
    private IUserClaimsPrincipalFactory<IdentityUser> userClaimsPrincipalFactory;

    public AccountController(SignInManager<IdentityUser> signInManager, UserManager<IdentityUser> userManager, IUserClaimsPrincipalFactory<ApplicationUser> userClaimsPrincipalFactory)
    {
        this.signInManager = signInManager;
        this.userManager = userManager;
        this.userClaimsPrincipalFactory = userClaimsPrincipalFactory;
    }

    [HttpPost]
    [AllowAnonymous]
    public async Task<IActionResult> Login(string username, string password)
    {
        if (username == null || password == null)
        {
            return BadRequest(); // Alias of 400 response
        }

        var result = await signInManager.PasswordSignInAsync(username, password, false, lockoutOnFailure: false);
        if (result.Succeeded)
        {
            var user = await userManager.FindByNameAsync(username);

            // Must manually set the HttpContext user claims to those of the logged
            // in user. Otherwise MVC will still include a XSRF token for the "null"
            // user and token validation will fail. (MVC appends the correct token for
            // all subsequent reponses but this isn't good enough for a single page
            // app.)
            var principal = await userClaimsPrincipalFactory.CreateAsync(user);
            HttpContext.User = principal;

            return Json(new { username = user.UserName });
        }
        else
        {
            return Unauthorized();
        }
    }

    [HttpPost]
    public async Task<IActionResult> Logout()
    {
        await signInManager.SignOutAsync();

        // Removing identity claims manually from the HttpContext (same reason
        // as why we add them manually in the "login" action).
        HttpContext.User = null;

        return Json(new { result = "success" });
    }
}

фильтр результатов для добавления файлов cookie antiforgery:

public class XSRFCookieFilter : IResultFilter
{
    IAntiforgery antiforgery;

    public XSRFCookieFilter(IAntiforgery antiforgery)
    {
        this.antiforgery = antiforgery;
    }

    public void OnResultExecuting(ResultExecutingContext context)
    {
        var HttpContext = context.HttpContext;
        AntiforgeryTokenSet tokenSet = antiforgery.GetAndStoreTokens(context.HttpContext);
        HttpContext.Response.Cookies.Append(
            "MyXSRFFieldTokenCookieName",
            tokenSet.RequestToken,
            new CookieOptions() {
                // Cookie needs to be accessible to Javascript so we
                // can append it to request headers in the browser
                HttpOnly = false
            } 
        );
    }

    public void OnResultExecuted(ResultExecutedContext context)
    {

    }
}

Автозагрузка.КС выдержка:

public partial class Startup
{
    public Startup(IHostingEnvironment env)
    {
        //...
    }

    public IConfigurationRoot Configuration { get; }

    public void ConfigureServices(IServiceCollection services)
    {

        //...

        services.AddAntiforgery(options =>
        {
            options.HeaderName = "MyXSRFFieldTokenHeaderName";
        });


        services.AddMvc(options =>
        {
            options.Filters.Add(typeof(XSRFCookieFilter));
        });

        services.AddScoped<XSRFCookieFilter>();

        //...
    }

    public void Configure(
        IApplicationBuilder app,
        IHostingEnvironment env,
        ILoggerFactory loggerFactory)
    {
        //...
    }
}

сообщение появляется при входе в систему, когда вы уже прошли проверку подлинности.

этот помощник делает то же самое, что и .

System.Web.Helpers.AntiForgery.Validate()

удалить [ValidateAntiForgeryToken] attribut от контроллера и поместите этот помощник в действие methode.

поэтому, когда пользователь уже аутентифицирован, перенаправьте на домашнюю страницу или, если не продолжите проверку действительного маркера защиты от подделки после этой проверки.

if (User.Identity.IsAuthenticated)
{
    return RedirectToAction("Index", "Home");
}

System.Web.Helpers.AntiForgery.Validate();

To попытайтесь воспроизвести ошибку, выполните следующие действия: Если вы находитесь на своей странице входа, и вы не прошли проверку подлинности. Если вы дублируете вкладку и входите во вторую вкладку. И если вы вернетесь на первую вкладку на странице входа в систему, и вы пытаетесь войти в систему без перезагрузки страницы ... у вас есть эта ошибка.

есть проблема с проверкой анти-подделки токенов в интернет-магазине: пользователи открывают много вкладок (с товарами) и после входа в один пытаются войти в другой и получили такое исключение AntiForgeryException. Итак, AntiForgeryConfig.SuppressIdentityHeuristicChecks = true не помогло мне, поэтому я использовал такой уродливый hackfix, может быть, это будет полезно для кого-то:

   public class ExceptionPublisherExceptionFilter : IExceptionFilter
{
    public void OnException(ExceptionContext exceptionContext)
    {
        var exception = exceptionContext.Exception;

        var request = HttpContext.Current.Request;
        if (request != null)
        {
            if (exception is HttpAntiForgeryException &&
                exception.Message.ToLower().StartsWith("the provided anti-forgery token was meant for user \"\", but the current user is"))
            {
                var isAjaxCall = string.Equals("XMLHttpRequest", request.Headers["x-requested-with"], StringComparison.OrdinalIgnoreCase);
                var returnUrl = !string.IsNullOrWhiteSpace(request["returnUrl"]) ? request["returnUrl"] : "/";
                var response = HttpContext.Current.Response;

                if (isAjaxCall)
                {
                    response.Clear();
                    response.StatusCode = 200;
                    response.ContentType = "application/json; charset=utf-8";
                    response.Write(JsonConvert.SerializeObject(new { success = 1, returnUrl = returnUrl }));
                    response.End();
                }
                else
                {
                    response.StatusCode = 200;
                    response.Redirect(returnUrl);
                }
            }
        }


        ExceptionHandler.HandleException(exception);
    }
}

public class FilterConfig
{
    public static void RegisterGlobalFilters(GlobalFilterCollection filters)
    {
        filters.Add(new ExceptionPublisherExceptionFilter());
        filters.Add(new HandleErrorAttribute());
    }
}

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