Try setting (in global.cs):
AntiForgeryConfig.UniqueClaimTypeIdentifier = ClaimTypes.NameIdentifier;
This will add the name identifier to your token,
As for the double login issue try to use a script to document the date and time of the original submit to stop a second submit with the same token.
// jQuery plugin to prevent double submission of forms
jQuery.fn.preventDoubleSubmission = function() {
$(this).on('submit',function(e){
var $form = $(this);
if ($form.data('submitted') === true) {
// Previously submitted - don't submit again
e.preventDefault();
} else {
// Mark it so that the next submit can be ignored
$form.data('submitted', true);
}
});
// Keep chainability
return this;
};
So we know one thing; users like the back button and have a habit of the double click, this is a big issue with AntiforgeryToken.
But depending on what your application does there are ways to limit their compulsion to do so. The simplest of which is to do your best to try and make the visitor not feel like they need to “rewind” their request to alter it.
Ensure that form error messaging is clear and concise to ensure the
user knows what is wrong. Contexual errors give bonus points.
Always maintain form state between form submissions. Apart from
passwords or credit card numbers, there’s no excuse thanks the to MVC
form helpers. @Html.LabelFor(x => x.FirstName)
If forms are spread across tabs or hidden divs such as those used in
SPA frameworks like Angular or ember.js, be smart and show the
controller layouts or form that the errors actually originated from in
the form submission when displaying the error. Don’t just direct them
to the home controller or first tab.
“What’s going on?” - Keeping the user informed
When a AntiForgeryToken doesn’t validate your website will throw an Exception of type System.Web.Mvc.HttpAntiForgeryException.
If you’ve set up correctly you’ve got friendly errors turned on and this will mean your error page will not show an Exception and show a nice error page that tells them what is up.
You can make this a little easier by at least giving the user a more informative page targeted at these exceptions by catching the HttpAntiForgeryException.
private void Application_Error(object sender, EventArgs e)
{
Exception ex = Server.GetLastError();
if (ex is HttpAntiForgeryException)
{
Response.Clear();
Server.ClearError(); //make sure you log the exception first
Response.Redirect("/error/antiforgery", true);
}
}
and your /error/antiforgery
view can tell them Sorry you have tried to submit the same information twice
Another Idea is to log the error and return the user to the login screen:
Create a HandleAntiforgeryTokenErrorAttribute
class that Overrides the OnException method.
HandleAntiforgeryTokenErrorAttribute.cs:
public class HandleAntiforgeryTokenErrorAttribute : HandleErrorAttribute
{
public override void OnException(ExceptionContext filterContext)
{
filterContext.ExceptionHandled = true;
filterContext.Result = new RedirectToRouteResult(
new RouteValueDictionary(new { action = "Login", controller = "Account" }));
}
}
Global Filter:
public class FilterConfig
{
public static void RegisterGlobalFilters(GlobalFilterCollection filters)
{
filters.Add(new HandleErrorAttribute());
filters.Add(new HandleAntiforgeryTokenErrorAttribute()
{ ExceptionType = typeof(HttpAntiForgeryException) }
);
}
}
I would also use a few tools to record all your information as login is critical part of your application
NLog for general logging and emails on critical application exceptions (including web exceptions).
Elmah for filtering and email of web exceptions.
EDIT:
Also you may want to look at a jQuery plugin called SafeForm. Link
EDIT:
I have seen allot of debate on this and everyone's views on the subject have valid points, How i look at it is (Taken from owasp.org)
Cross-Site Request Forgery (CSRF) is an attack that forces an end user
to execute unwanted actions on a web application in which they're
currently authenticated, CSRF attacks specifically target state-changing requests, not theft of data. The anti-forgery token is
specific to 'who is logged on'. So once you login, then go back, the
old token is no longer valid
Now i also use authorized IP addresses for login to allot of my applications with 2 factor authorization if the users IP address changes, so if Cross-Site Request Forgery was in play the user wouldn't match the IP address and request 2 factor authorization. almost like the way a security router would work. but if you want to keep it on your login page i don't see a problem as long as you have your friendly error pages set up people will not get upset as they will see they did something wrong.