Solução de problemas de token anti-falsificação

Eu tenho um post de formulário que consistentemente me dá um erro de token anti-falsificação.

Aqui está minha forma:

@using (Html.BeginForm()) { @Html.AntiForgeryToken() @Html.EditorFor(m => m.Email) @Html.EditorFor(m => m.Birthday) 

}

Aqui está o meu método de ação:

 [HttpPost] [ValidateAntiForgeryToken] public ActionResult Join(JoinViewModel model) { //a bunch of stuff here but it doesn't matter because it's not making it here } 

Aqui está a machineKey no web.config:

    

E aqui está o erro que recebo:

 A required anti-forgery token was not supplied or was invalid. 

Eu li que alterar usuários no HttpContext invalidará o token, mas isso não está acontecendo aqui. O HttpGet na minha ação Join apenas retorna a view:

 [HttpGet] public ActionResult Join() { return this.View(); } 

Então não tenho certeza do que está acontecendo. Eu pesquisei por aí, e tudo parece sugerir que é a mudança de machineKey (ciclos de aplicativos) ou a alteração de usuário / session.

O que mais poderia estar acontecendo? Como posso resolver isso?

Eu não sei se você quer dizer que você é capaz de obter o erro sob demanda – ou você está vendo isso em seus logs, mas de qualquer forma, aqui está uma maneira de garantir um erro de token antiforgery.

Espere por isso…

  • Certifique-se de estar desconectado e, em seguida, insira seu login
  • Clique duas vezes no botão de login
  • Você terá :

O token anti-falsificação fornecido foi destinado ao usuário “”, mas o usuário atual é “XXX@yahoo.com”.

(Por enquanto eu vou assumir que esta mensagem de erro exata mudou no MVC4 e que esta é essencialmente a mesma mensagem que você está recebendo).

Há um monte de gente por aí que ainda clica duas vezes em tudo – isso é ruim! Eu só percebi isso depois de apenas acordar, então como isso passou por testes eu realmente não sei. Você nem precisa clicar duas vezes – Eu mesmo tenho esse erro quando clico uma segunda vez se o botão não responder.

Acabei de remover o atributo de validação. Meu site é sempre SSL e não estou muito preocupado com o risco. Eu só preciso que funcione agora. Outra solução seria desabilitar o botão com javascript.

Isso pode ser duplicado no modelo de instalação inicial do MVC4.

Após a ajuda do Adam, eu obtive o código fonte do MVC adicionado ao meu projeto, e pude ver que há muitos casos que resultam no mesmo erro.

Aqui está o método usado para validar o token anti-falsificação:

  public void Validate(HttpContextBase context, string salt) { Debug.Assert(context != null); string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null); string cookieName = AntiForgeryData.GetAntiForgeryTokenName(context.Request.ApplicationPath); HttpCookie cookie = context.Request.Cookies[cookieName]; if (cookie == null || String.IsNullOrEmpty(cookie.Value)) { // error: cookie token is missing throw CreateValidationException(); } AntiForgeryData cookieToken = Serializer.Deserialize(cookie.Value); string formValue = context.Request.Form[fieldName]; if (String.IsNullOrEmpty(formValue)) { // error: form token is missing throw CreateValidationException(); } AntiForgeryData formToken = Serializer.Deserialize(formValue); if (!String.Equals(cookieToken.Value, formToken.Value, StringComparison.Ordinal)) { // error: form token does not match cookie token throw CreateValidationException(); } string currentUsername = AntiForgeryData.GetUsername(context.User); if (!String.Equals(formToken.Username, currentUsername, StringComparison.OrdinalIgnoreCase)) { // error: form token is not valid for this user // (don't care about cookie token) throw CreateValidationException(); } if (!String.Equals(salt ?? String.Empty, formToken.Salt, StringComparison.Ordinal)) { // error: custom validation failed throw CreateValidationException(); } } 

Meu problema era aquela condição em que ele compara o nome do usuário Identity com o nome de usuário do token do formulário. No meu caso, eu não tinha o nome de usuário definido (um era null, o outro era uma string vazia).

Embora eu duvide que muitos irão se deparar com este mesmo cenário, esperamos que outros acharão útil ver as condições subjacentes que estão sendo verificadas.

Você deve evitar o envio de formulários duplos. Eu evito esse tipo de problema usando código como este:

 $('#loginForm').on('submit',function(e){ var $form = $(this); if (!$form.data('submitted') && $form.valid()) { // mark it so that the next submit can be ignored $form.data('submitted', true); return; } // form is invalid or previously submitted - skip submit e.preventDefault(); }); 

ou

 $('#loginForm').submit(function () { $(this).find(':submit').attr('disabled', 'disabled'); }); 

O AntiForgeryToken também verifica se suas credenciais de usuário não foram alteradas – elas também são criptografadas no cookie. Você pode desativar isso definindo AntiForgeryConfig.SuppressIdentityHeuristicChecks = true no arquivo global.asax.cs.

Acabei de @Html.AntiForgeryToken() um problema em que @Html.AntiForgeryToken() estava sendo chamado duas vezes, então o token Anti- @Html.AntiForgeryToken() foi @Html.AntiForgeryToken() na carga HTTP Post.

Você está em um servidor ou em um farm da web? Se for um único servidor, comente seu elemento machineKey no seu web.config e tente novamente como um ponto de partida básico. Qualquer mudança? Além disso, você pode pensar em qualquer motivo para que seus cookies sejam eliminados ou expirem – eles são necessários para que isso funcione corretamente também.

Eu também tive esse mesmo problema quando tive que migrar meu aplicativo para uma nova máquina. Eu não conseguia entender porque esse erro se manifestou repentinamente, mas tive certeza de que tinha algo a ver com a migration, então comecei a investigar o registro do database através do aspnet_reqsql, quando isso foi eliminado, percebi que deveria ter a ver com o registro do aplicativo e com certeza eu encontrei a resposta em um lugar semelhante. Eu também na minha jornada descobri que existem 2 maneiras de resolver isso.

  1. O ASP.NET gera automaticamente uma chave de criptografia para cada aplicativo e armazena a chave na seção de registro HKCU. Quando o aplicativo é migrado ou acessado em um farm de servidores, essas chaves não correspondem, portanto, o método um é adicionar uma chave de máquina exclusiva ao web.config. A chave da máquina pode ser gerada a partir do console de gerenciamento do IIS e adicionada à seção do seu web.config

  2. O segundo método é conceder access ao registro HKCU para o processo de trabalho por meio do appPool usando AspNet_RegIIS e o switch -ga ou para todos os aplicativos usando -i

aspnet_regiis -ga “IIS APPPOOL \ nome do pool de aplicativos”

Seja qual for o método escolhido, você deve resolver esse problema, mas, para mim, a maneira mais robusta de futuras migrações e alterações no servidor será a chave exclusiva do web.config, lembrando que isso fará com que o aplicativo substitua o registro HKCU. e manter sua aplicação em execução.

Outra coisa possível para verificar o que causou este erro para mim: eu tinha dois @Html.AntiForgeryToken() em um dos meus formulários.

Uma vez que isso foi removido, o problema desapareceu.

É necessário verificar o formulário é válido, antes de desativar o botão de envio.

  

logger de erro html não é a linha correta.

você deve verificar todo o valor de carregamento na página não é nulo.

Eu só tive um problema semelhante. Eu tenho:

 The required anti-forgery form field "__RequestVerificationToken" is not present. 

O que é de interesse é que eu tentei depurá-lo e vi o token em ambos os lugares que eu esperava para encontrá-lo no controlador

 var formField = HttpContext.Request.Params["__RequestVerificationToken"]; var cookie = System.Web.HttpContext.Current.Request.Cookies["__RequestVerificationToken"].Value; 

Na verdade, eu deveria estar olhando aqui:

 var formField = HttpContext.Request.Form["__RequestVerificationToken"]; 

Como Params contém mais do que apenas os campos de formulário, ele contém o QueryString, Form, Cookies e ServerVariables.

Uma vez que o arenque vermelho estava fora do caminho, encontrei o AntiForgeryToken estava na forma errada!