Anti forgery token está destinado para el usuario ""pero el usuario actual es" nombre de usuario"


Estoy creando una aplicación de una sola página y estoy experimentando un problema con los tokens anti-falsificación.

Sé por qué sucede el problema, pero no sé cómo solucionarlo.

Recibo el error cuando sucede lo siguiente:

  1. El usuario que no ha iniciado sesión carga un diálogo (con un token anti-falsificación generado)
  2. El usuario cierra el diálogo
  3. El usuario inicia sesión
  4. El usuario abre el mismo diálogo
  5. El usuario envía un formulario en diálogo

Anti el token de falsificación está destinado al usuario"", pero el usuario actual es "nombre de usuario"

La razón por la que esto sucede es porque mi aplicación es 100% de una sola página, y cuando un usuario inicia sesión con éxito a través de un mensaje ajax a /Account/JsonLogin, simplemente cambio las vistas actuales con las "vistas autenticadas" devueltas desde el servidor, pero no recarga la página.

Sé que esta es la razón porque si simplemente recargo la página entre los pasos 3 y 4, no hay error.

So parece que @Html.AntiForgeryToken() en la forma cargada todavía devuelve un token para el usuario anterior hasta que la página se vuelva a cargar.

¿Cómo puedo cambiar @Html.AntiForgeryToken() para devolver un token para el nuevo usuario autenticado?

Inyecto un nuevo GenericalPrincipal con un IIdentity personalizado en cada Application_AuthenticateRequest por lo que cuando @Html.AntiForgeryToken() se llama HttpContext.Current.User.Identity es, de hecho, mi identidad personalizada con la propiedad IsAuthenticated establecida en true y, sin embargo, @Html.AntiForgeryToken todavía parece representar un token para el usuario anterior a menos que haga una recarga de página.

Author: Ahmed, 2013-02-20

10 answers

Esto sucede porque el token anti-falsificación incrusta el nombre de usuario del usuario como parte del token cifrado para una mejor validación. Cuando llama por primera vez a @Html.AntiForgeryToken() el usuario no está conectado, por lo que el token tendrá una cadena vacía para el nombre de usuario, después de que el usuario inicie sesión, si no reemplaza el token anti-falsificación, no pasará la validación porque el token inicial era para un usuario anónimo y ahora tenemos un usuario autenticado con un nombre de usuario conocido.

Usted tiene algunas opciones para resolver este problema:

  1. Solo esta vez deje que su SPA haga una PUBLICACIÓN completa y cuando la página se vuelva a cargar tendrá un token antifalsificación con el nombre de usuario actualizado incrustado.

  2. Tenga una vista parcial con solo @Html.AntiForgeryToken() y justo después de iniciar sesión, haga otra solicitud AJAX y reemplace su token anti-falsificación existente con la respuesta de la solicitud.

  3. Simplemente desactive la comprobación de identidad que realiza la validación anti-falsificación. Añadir lo siguiente a su Método Application_Start : AntiForgeryConfig.SuppressIdentityHeuristicChecks = true.

 159
Author: epignosisx,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-04 08:13:33

Para corregir el error, debe colocar la Anotación de datos OutputCache en la página Get ActionResult de inicio de sesión como:

[OutputCache(NoStore=true, Duration = 0, VaryByParam= "None")] 
public ActionResult Login(string returnUrl)
 17
Author: user3401354,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-11-10 07:12:18

Sucede muchas veces con mi aplicación,así que decidí buscar en Google!

He encontrado una explicación simple sobre este error! El usuario está haciendo doble clic en el botón para iniciar sesión! Puedes ver a otro usuario hablando de eso en el siguiente enlace:

MVC 4 proporcionado anti-falsificación token estaba destinado para el usuario ""pero el usuario actual es "usuario"

¡Espero que ayude! =)

 6
Author: Ricardo França,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-08-18 18:39:18

Tuve el mismo problema, y este truco sucio lo arregló, al menos hasta que pueda arreglarlo de una manera más limpia.

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

...

 3
Author: Saúl Jacinto,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-12-19 19:57:03

Tuve un problema bastante específico pero similar dentro del proceso de registro. Una vez que el usuario haga clic en el enlace de correo electrónico que se le envía, se inicia sesión y se envía directamente a una pantalla de detalles de la cuenta para completar más información. Mi código era:

    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

Encontré que la vista Return ("AccountDetails") me estaba dando la excepción token, supongo que porque la función ConfirmEmail estaba decorada con AllowAnonymous pero la función AccountDetails tenía Valida el rescate.

Cambiar el Retorno a Return RedirectToAction("AccountDetails") resolvió el problema para mí.

 1
Author: Liam,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2016-08-12 11:48:10

Tengo la misma excepción ocurriendo la mayor parte del tiempo en el servidor de producción.

¿por Qué sucede?

Sucede cuando el usuario inicia sesión con credenciales válidas y una vez iniciado sesión y redirige a otra página, y después de presionar el botón atrás se mostrará la página de inicio de sesión y de nuevo ingresó credenciales válidas que cuando se producirá esta excepción.

Cómo resolver?

Simplemente agregue esta línea y trabaje perfecto, no obtenga un error.

[OutputCache(NoStore = true, Duration = 0, VaryByParam = "None")]
 1
Author: Brijesh Mavani,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 12:41:22
[OutputCache(NoStore=true, Duration=0, VaryByParam="None")]

public ActionResult Login(string returnUrl)

Puede probar esto poniendo un punto de interrupción en la primera línea de su acción de inicio de sesión (Get). Antes de agregar la directiva OutputCache, el punto de interrupción sería alcanzado en la primera carga, pero después de hacer clic en el botón de retroceso del navegador no. Después de agregar la directiva, debería terminar con el punto de interrupción siendo alcanzado cada vez, por lo que el AntiForgeryToken será el corect, no el vacío.

 1
Author: Marian Dalalau,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2018-09-06 12:41:52

Tuve el mismo problema con una sola página ASP.NET Aplicación MVC Core. Lo resolví configurando HttpContext.User en todas las acciones del controlador que cambian las notificaciones de identidad actuales (ya que MVC solo hace esto para solicitudes posteriores, como se discutió aquí). Utilicé un filtro de resultados en lugar de middleware para agregar las cookies antiforgery a mis respuestas, lo que se aseguró de que solo se generaran después de que la acción MVC hubiera regresado.

Controlador (NB. Estoy administrando usuarios con ASP.NET Básica Identidad):

[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" });
    }
}

Filtro de resultados para añadir cookies 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)
    {

    }
}

Inicio.extracto cs:

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)
    {
        //...
    }
}
 0
Author: Ned Howley,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-07-25 09:10:18

El mensaje aparece cuando inicia sesión cuando ya está autenticado.

Este Ayudante hace exactamente lo mismo que el atributo [ValidateAntiForgeryToken].

System.Web.Helpers.AntiForgery.Validate()

Elimine el atributo [ValidateAntiForgeryToken] del controlador y coloque este ayudante en el método de acción.

Entonces, cuando el usuario ya está autenticado, redirija a la página de inicio o si no continúa con la verificación del token anti-falsificación válido después de esta verificación.

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

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

Para intentar reproducir el error, proceda como seguir: Si está en su página de inicio de sesión y no está autenticado. Si duplica la pestaña e inicia sesión con la segunda pestaña. Y si vuelves a la primera pestaña de la página de inicio de sesión e intentas iniciar sesión sin recargar la página ... tienes este error.

 0
Author: A. Morel,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-19 09:17:07

Tiene un problema con la validación anti-falsificación-token en internet-shop: los usuarios abren muchas pestañas (con los productos) y después de iniciar sesión en un intento de iniciar sesión en otro y consiguió tal AntiForgeryException. Por lo tanto, AntiForgeryConfig.SuppressIdentityHeuristicChecks = true no me ayudó, así que usé un hackfix tan feo, tal vez sea útil para alguien:

   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());
    }
}

Creo que será genial si se pueden establecer opciones de generación de tokens anti-falsificación, para excluir el nombre de usuario o algo por el estilo.

 -3
Author: user3364244,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2014-02-28 09:59:47