When implementing ASP.NET applications which make usage of AJAX and Windows Forms Authentication, there are few critical issues you have to be aware of. in this post you can find few very interesting information related to AJAX and FormsAuthentication.
Assume there is an ASP.NET application which use Windows Forms authentication and has a page called WebFormSessionTest.Aspx. Additionally the application is configured to use FormsAuthentication when user requests this page. This is a common scenario based on forms authentication in ASP.NET.
To configure application like this we would usually change web.config as shown below:
<forms name=".MYCOOKIE" loginUrl="Login.aspx" protection="All" timeout="15" path="/" />
Please note the attribute timeout="15" in this example. This value defines the validity time the token (cookie), which is internally created after successfully login. It means, the user will be required to login again if the user has no taken any action for more than 15 minutes. Forcing the user to take a logon again means "redirecting of user to "Login.aspx" page (defined by attribute 'loginUrl').
Assuming that this is well known scenario, I'm not going to describe it in more detail.
Now, imagine the page WebFormSessionTest.Aspx is designed to operate with AJAX callbacks. In other words this means the page implement interface ICallbackEventHandler.
The critical issue, which I would like to describe begins at the moment when the user initiate AJAX callback, which should be handled by page WebFormSessionTest.Aspx. For example, the AJAX callback is initiated on press of some button B in the browser. As long the windows forms security token is valid all will work fine. However, if the user was inactive for a while (e.g.: 17 minutes) the token will expire and next request should be redirected to Login.aspx. Unfortunately, this does not work. At least not the way you could make any usage of it.
When the AJAX request (callback) is received by the ASP.NET server, the FormsAuthentication runtime finds out that the token is expired (actually the cookie '.MYCOOKIE' has expired) and redirects the request to the login page. This is fine, but after the Login.aspx page is rendered, usually the browser should show it to the user. Unfortunately this does not happen. Instead the user will not get any message, after pressing on button B. It means, user press button B and nothing happens. No any action, no any error, just nothing.
"Why it does happen nothing?"
This string is consisted as :
Lenght(EventValidationValue) | EventValidationValue + Result
As result of this behavior AJAX will no more work in the application, as long some postback is initiated.
After some experimenting, fiddlering and reflectoring the solution looks like:
1. Check in Global.ASAX.cs if the request is none-authenticated AJAX request. (Assuming ScriptManage.AuthenticationService is not used).
2. If it is not just proceed.
3. If it is none-authenticated AJAX callback, enforce redirecting to login page by appending some additional parameter.
4. The Login.aspx page checks for additional parameter. If found the page will know that is is in callback context. Note that AJAX-callback has to be checked in Global.Asax.cs, because Login page is always invoked by redirect even if previous request has been AJAX callback.
5. If the Login page is called within AJAX callback (additional parameter is contained in request) we send the browser expected AJAX stream instead of rendered Login.aspx html. In this stream we append some marker, which indicates that the tokens has been expired.
6. Adopt AJAX java script handler function to be able to catch this information.
Putting all together:
GlobalAsax.cs: (Steps 1, 2 and 3):
Here is the code to be appended in the Global.Asax.cs:
Login.cs (Steps 4 and 5):
Here is the code to be appended in the Login.cs:
The string returned here can be parsed by java script handler as a valid response. Response.End() ensures that Login.ascx HTML is not rendered.
Java Script handler changes (Step 6)
Following JAVA script is used to create request (AJAX callback) and to handle failed authentication. The function go()
is called when the user presses the button B. After the request has been successfully processed by server handler the
function onSuccess is called. If the argument equals "authenticationfailed" teh response has been created by Login.cs and it menas
that the user is no more logged in.
Related article: http://developers.de/blogs/damir_dobric/archive/2006/10/09/939.aspx.