This behavior is correct. The anti-forgery tokens are tied to specific users (or the 'guest' user if the current user is not logged in). The first time the form is generated, the user is not logged in, so a token is generated for the user GUEST. The user
hits the login button, the token validates correctly (since the user has not yet been logged in), your controller logs the user in, and life is good. Let's assume he logged in as JOE.
Now, if the user hits the back button, he'll be taken back to the original form. (More specifically, he'll see the cached version of the original form, complete with GUEST token.) When he tries to submit the login again, the GUEST token cannot be used
for a request coming from JOE, so the system rejects the token.
This is pretty much the same behavior you'll see at some banking and other web sites, many of which don't allow you to use the back button once you've logged in. Their tokens follow a similar pattern of being tied to a specific user, and if an old token
is used with a logged-in user they will fail.
Presumably this shouldn't be problematic, as the particular scenario under consideration (submitting the exact same form under two different identities) isn't something most users do and isn't something that's always expected to work properly. If this is
however a problem for you, you could remove [ValidateAntiForgeryToken] from the Login() action.
Marked as answer by webster354 on May 21, 2010 12:29 AM
Thanks for explanation, I understand why the exception is occurring now. Out of curiosity how come if I create a custom ActionFilter it does not fire before the ValidateAntiForgeryToken.
[HttpPost]
[RedirectIfAlreadyAuthenticated(Order = 1)]
[ValidateAntiForgeryToken(Order = 2)]
public ActionResult Login(LoginModel loginModel, string returnUrl)
{
}
public class RedirectIfAlreadyAuthenticatedAttribute : ActionFilter
{
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
if(filterContext.HttpContext.Request.IsAuthenticated)
{
// redirect somewhere
}
}
}
Out of curiosity how come if I create a custom ActionFilter it does not fire before the ValidateAntiForgeryToken.
ValidateAntiForgeryTokenAttribute is an authorization filter (it implements IAuthorizationFilter), while your filter is a regular action filter (it implements IActionFilter and IResultFilter via subclassing ActionFilterAttribute). Authorization filters
are always executed before action filters, regardless of ordering. Ordering can only be used to order authorization filters relative to other authorization filters, action filters relative to other action filters, etc.
Instead, your filter should subclass FilterAttribute (instead of ActionFilterAttribute) and implement the IAuthorizationFilter interface. From the OnAuthorization() method, perform the necessary check + redirect. Since both your attribute and the [ValidateAntiForgeryToken]
filter are authorization filters, their Order properties will be respected.
Marked as answer by ricka6 on May 21, 2010 03:12 PM
But I am unsure that whether this will execute before or after the other AuthorizeAttribute methods ,
I am also ask Levib that which method is executed first, IAuthorizationFilter.OnAuthorization OR AuthorizeAttribute
"And whoever is removed away from the Fire and admitted to Paradise, he indeed is successful." (The Holy Quran)
Excellent Windows VPS Hosting Imran Baloch MVP, MVB, MCP, MCTS, MCPD
Marked as answer by ricka6 on May 21, 2010 03:18 PM
Filter execution is grouped by filter type: authorization filter, action filter, response filter, and exception filter. *All* of the authorization filters go first, then *all* of the action filters, then *all* of the response filters. Within these particular
groups, ordering is determined by the rules detailed at
http://msdn.microsoft.com/en-us/library/dd381609.aspx (Order of Execution for Action Filters).
By the rules detailed at this article, the Controller.OnAuthorization() method will execute before any authorization filter, regardless of the filter's Order.
Marked as answer by ricka6 on May 21, 2010 03:13 PM
By the rules detailed at this article, the Controller.OnAuthorization() method will execute before any authorization filter,
But these rules are specific to Action Filters
MSDN
The implementation of the OnActionExecuting and OnActionExecuted methods on the controller always go first.
Is same rules are applied to Authorization Filters?
"And whoever is removed away from the Fire and admitted to Paradise, he indeed is successful." (The Holy Quran)
Excellent Windows VPS Hosting Imran Baloch MVP, MVB, MCP, MCTS, MCPD
Presumably this shouldn't be problematic, as the particular scenario under consideration (submitting the exact same form under two different identities) isn't something most users do and isn't something that's always expected to work properly. If this is
however a problem for you, you could remove [ValidateAntiForgeryToken] from the Login() action.
Perhaps even more important, there is no value in adding anti-forgery tokens to pages which are designed to be submitted by anonymous users (like the logon page), because there is no identity to be forged. They are really only useful for submissions which take
advantage of the currenty logged in user's credentials.
Marked as answer by ricka6 on Oct 25, 2010 09:44 PM
My reasoning for adding the ValidateAntiForgeryToken to the login action is to only allow validation of a user to occur from my form. I don't want to allow other applications from posting to this action.
Am I being overly precautious or is there a better way to handle this situation?
webster354
Member
15 Points
22 Posts
A required anti-forgery token was not supplied or was invalid
May 20, 2010 05:48 PM|LINK
This exception is thrown by doing the following:
[HttpPost] [ValidateAntiForgeryToken] public ActionResult Login(LoginModel loginModel, string returnUrl) { // validate login, set authcookie }How do I prevent this from happening?
levib
Star
7702 Points
1099 Posts
Microsoft
Re: A required anti-forgery token was not supplied or was invalid
May 20, 2010 10:39 PM|LINK
This behavior is correct. The anti-forgery tokens are tied to specific users (or the 'guest' user if the current user is not logged in). The first time the form is generated, the user is not logged in, so a token is generated for the user GUEST. The user hits the login button, the token validates correctly (since the user has not yet been logged in), your controller logs the user in, and life is good. Let's assume he logged in as JOE.
Now, if the user hits the back button, he'll be taken back to the original form. (More specifically, he'll see the cached version of the original form, complete with GUEST token.) When he tries to submit the login again, the GUEST token cannot be used for a request coming from JOE, so the system rejects the token.
This is pretty much the same behavior you'll see at some banking and other web sites, many of which don't allow you to use the back button once you've logged in. Their tokens follow a similar pattern of being tied to a specific user, and if an old token is used with a logged-in user they will fail.
Presumably this shouldn't be problematic, as the particular scenario under consideration (submitting the exact same form under two different identities) isn't something most users do and isn't something that's always expected to work properly. If this is however a problem for you, you could remove [ValidateAntiForgeryToken] from the Login() action.
webster354
Member
15 Points
22 Posts
Re: A required anti-forgery token was not supplied or was invalid
May 20, 2010 11:13 PM|LINK
Thanks for explanation, I understand why the exception is occurring now. Out of curiosity how come if I create a custom ActionFilter it does not fire before the ValidateAntiForgeryToken.
[HttpPost] [RedirectIfAlreadyAuthenticated(Order = 1)] [ValidateAntiForgeryToken(Order = 2)] public ActionResult Login(LoginModel loginModel, string returnUrl) { } public class RedirectIfAlreadyAuthenticatedAttribute : ActionFilter { public override void OnActionExecuting(ActionExecutingContext filterContext) { if(filterContext.HttpContext.Request.IsAuthenticated) { // redirect somewhere } } }levib
Star
7702 Points
1099 Posts
Microsoft
Re: A required anti-forgery token was not supplied or was invalid
May 21, 2010 12:24 AM|LINK
ValidateAntiForgeryTokenAttribute is an authorization filter (it implements IAuthorizationFilter), while your filter is a regular action filter (it implements IActionFilter and IResultFilter via subclassing ActionFilterAttribute). Authorization filters are always executed before action filters, regardless of ordering. Ordering can only be used to order authorization filters relative to other authorization filters, action filters relative to other action filters, etc.
Instead, your filter should subclass FilterAttribute (instead of ActionFilterAttribute) and implement the IAuthorizationFilter interface. From the OnAuthorization() method, perform the necessary check + redirect. Since both your attribute and the [ValidateAntiForgeryToken] filter are authorization filters, their Order properties will be respected.
imran_ku07
All-Star
45815 Points
7698 Posts
MVP
Re: A required anti-forgery token was not supplied or was invalid
May 21, 2010 05:52 AM|LINK
you can also use this in your controller
protected override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.RouteData.Values["contoller"] == "Login" && filterContext.RouteData.Values["action"] == "Login" && filterContext.RequestContext.HttpContext.Request.IsAuthenticated)
{
//redirect
}
base.OnAuthorization(filterContext);
}
But I am unsure that whether this will execute before or after the other AuthorizeAttribute methods ,
I am also ask Levib that which method is executed first, IAuthorizationFilter.OnAuthorization OR AuthorizeAttribute
Excellent Windows VPS Hosting
Imran Baloch MVP, MVB, MCP, MCTS, MCPD
levib
Star
7702 Points
1099 Posts
Microsoft
Re: A required anti-forgery token was not supplied or was invalid
May 21, 2010 06:09 AM|LINK
Filter execution is grouped by filter type: authorization filter, action filter, response filter, and exception filter. *All* of the authorization filters go first, then *all* of the action filters, then *all* of the response filters. Within these particular groups, ordering is determined by the rules detailed at http://msdn.microsoft.com/en-us/library/dd381609.aspx (Order of Execution for Action Filters).
By the rules detailed at this article, the Controller.OnAuthorization() method will execute before any authorization filter, regardless of the filter's Order.
imran_ku07
All-Star
45815 Points
7698 Posts
MVP
Re: A required anti-forgery token was not supplied or was invalid
May 21, 2010 06:59 AM|LINK
But these rules are specific to Action Filters
Is same rules are applied to Authorization Filters?
Excellent Windows VPS Hosting
Imran Baloch MVP, MVB, MCP, MCTS, MCPD
levib
Star
7702 Points
1099 Posts
Microsoft
Re: A required anti-forgery token was not supplied or was invalid
May 21, 2010 07:03 AM|LINK
The same rules apply to all filter groups.
bradwils
Contributor
5779 Points
691 Posts
Microsoft
Re: A required anti-forgery token was not supplied or was invalid
May 21, 2010 03:32 PM|LINK
webster354
Member
15 Points
22 Posts
Re: A required anti-forgery token was not supplied or was invalid
May 21, 2010 05:28 PM|LINK
My reasoning for adding the ValidateAntiForgeryToken to the login action is to only allow validation of a user to occur from my form. I don't want to allow other applications from posting to this action.
Am I being overly precautious or is there a better way to handle this situation?