I have an ASP.NET MVC/Web API backend where I have implemented a Forms Authentication for my Phonegap app. The login is executed by sending the users credentials via jQuery Ajax call like this:
$.ajax({ type: "POST", url: "/api/authentication/login", data: JSON.stringify({ Username: username, Password: password }), contentType: "application/json; charset=utf-8", dataType: "TEXT", statusCode: { 200: function (response, status, xhr) { // successfully authenticated Backbone.history.navigate("/", { trigger: true }); } } });
The backends login method looks like this:
[ActionName("login")] [AllowAnonymous] public LoginResult Login(LoginCredentials credentials) { // doing all kinds of things here // if valid credentials FormsAuthentication.SetAuthCookie(loginID, true); return loginResult; }
I have this in my Web.config:
<authentication mode="Forms"> <forms name=".ASPXAUTH" loginUrl="/login" defaultUrl="/home" protection="All" slidingExpiration="true" timeout="525600" cookieless="UseCookies" enableCrossAppRedirects="false" requireSSL="true" > </forms> </authentication>
Now the problem with Android here is that the cookie is properly set and it does work on my authorized methods after the login, but sometimes (often) when I close the app and open it again, I'm no longer logged in. The cookie isn't there anymore, I can not see it in the request. This should not happen because I have set the timeout to 525600. I have noticed that this problem often occurs when I close the app immediately after login. In other hand if I log out and then log in without closing the app, the cookie is saved properly.
But, if I get the cookie to stick, most of the time the logout behaves strangely as well. This is how I do the logout request:
$.ajax({ type: "POST", url: "/api/authentication/logout", data: "{}", contentType: "application/json; charset=utf-8", dataType: "text" success: function (response) { // successfully logged out Backbone.history.navigate("api/login", { trigger: true }); } });
The backend:
[ActionName("logout")] [AllowAnonymous] public String Logout() { FormsAuthentication.SignOut(); HttpCookie cookie = new HttpCookie(FormsAuthentication.FormsCookieName, ""); cookie.Expires = DateTime.Now.AddYears(-1); HttpContext.Current.Response.Cookies.Add(cookie); return "home"; }
Now similar to the problem with the login, the logout first seems to be successful and the cookie is no longer sent with any requests. But when I close the app and open it again, the cookie is back and I'm logged in again. I can see that the cookie has the same value as the one I thought I just removed by setting its expiration time to the past.
I have tried all kinds of tricks, like:
location.reload()
)The authentication works as intended on iOS and Windows Phone. The problem occurs only on Android (tested on KitKat and Lollipop). No problem on the Android emulator, but on real devices and Visual Studios Android emulator this happens all the time.
I don't know in which direction to go from here. Is there something in the Android WebView that could cause this kind of behavior? Is there something else I could test out? Please help!
I'm more than happy to give more information if needed.
EDIT: Inspired by Fabian's comment, I changed the logout method to this:
FormsAuthentication.SignOut(); HttpCookie cookie = HttpContext.Current.Response.Cookies[FormsAuthentication.FormsCookieName]; cookie.Expires = DateTime.Now.AddYears(-1); HttpContext.Current.Response.Cookies.Clear(); HttpContext.Current.Response.Cookies.Add(cookie); return "home";
Instead of creating a new cookie, I used the one in the response. It did not work.
I also tried something I found from here: http://techblog.dorogin.com/2013/01/formsauthentication-gotcha-with-signout.html That also did no difference, the path was not the problem. Still looking for a solution.
ANOTHER EDIT: Still not able to find a solution for this. I had to make a horrible workaround.
I'm not happy with these hacks and I'm still hoping for a better solution.
PhoneGap loads files from file://
protocol. Unfortunately, cross origin requests are not allowed and unless you open cross origin requests from all hosts *
, this problem will not resolve.
There are multiple ways this can be fixed but they are really long.
Load Html from http://
Load entire website from web server instead of local storage. This removes all issues with cross origin requests. Benefit is you don't need to publish new version of app when you change UI. But you will have to implement very powerful caching and first time opening app will take longer time.
Intercept http://
and deliver local files
As you know, phonegap simply uses WebView, in all platforms, you can simply override Url protocol to inject files from your app's local storage. This will be faster, and browser will think that it is loading html from same resource.
Setup OAuth + custom header for authentication
http://domain.com/api/login
PhoneGap localStorage
(not browser's localStorage) to store authorization.If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With