Phonegap上的ASP.NET窗体身份验证问题(Android)

时间:2015-08-17 13:33:14

标签: android asp.net cordova authentication cookies

我有一个ASP.NET MVC / Web API后端,我已经为我的Phonegap应用程序实现了表单身份验证。通过jQuery Ajax调用发送用户凭据来执行登录:

$.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 });
        }
    }
});

后端登录方法如下所示:

[ActionName("login")]
[AllowAnonymous]
public LoginResult Login(LoginCredentials credentials)
{
    // doing all kinds of things here

    // if valid credentials
    FormsAuthentication.SetAuthCookie(loginID, true);
    return loginResult;
}

我在我的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>

现在Android的问题是cookie已正确设置并且在登录后它可以在我的授权方法上运行,但有时(通常)当我关闭应用程序并再次打开它时,我不再登录饼干不在了,我在请求中看不到它。这不应该发生,因为我已将超时设置为525600.我注意到在登录后立即关闭应用程序时经常会出现此问题。另一方面,如果我注销然后在不关闭应用程序的情况下登录,则cookie会正确保存。

但是,如果我坚持使用cookie,大部分时间注销都会表现得很奇怪。这是我执行注销请求的方式:

$.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 });
    }
});

后端:

[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";
}

现在类似于登录的问题,首先注销似乎是成功的,并且不再向任何请求发送cookie。但当我关闭应用程序并再次打开它时,cookie又回来了,我又重新登录了。我可以看到cookie的值与我刚刚删除的那个值相同,它将过期时间设置为过去。

我尝试过各种各样的技巧,比如:

  • 登录/退出(location.reload()
  • 后的额外重新加载
  • 多次执行注销/登录请求
  • 在登录/注销后执行其他方法的请求
  • 登录/注销请求与重新加载之间的第二次超时
  • 上述
  • 的各种变体

身份验证在iOS和Windows Phone上按预期工作。问题仅发生在Android上(在KitKat和Lollipop上测试)。在Android模拟器上没有问题,但在真实设备和Visual Studios Android模拟器上这种情况一直都会发生。

我不知道从哪里开始。 Android WebView中是否存在可能导致此类行为的内容?还有其他我可以测试的东西吗?请帮忙!

如果需要,我非常乐意提供更多信息。

修改 受法比安的评论启发,我将注销方法更改为:

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";

我没有创建新的cookie,而是在响应中使用了一个。它不起作用。

我也尝试过从这里找到的东西:http://techblog.dorogin.com/2013/01/formsauthentication-gotcha-with-signout.html这也没有区别,路径不是问题。仍在寻找解决方案。

另一个编辑: 仍然无法找到解决方案。我不得不做出可怕的解决方法。

  • 登录:我在登录后再进行两次重新加载,然后请求 虚拟方法。这似乎每次都有效。
  • 退出:我使用localStorage中的一个标志来确定用户是否已注销并在启动时执行注销。这总是正确地删除cookie。

我对这些黑客不满意,我仍然希望有更好的解决方案。

3 个答案:

答案 0 :(得分:1)

我相信我找到了解决方案。 config.xml文件中的Phonegap版本为 cli-5.1.1 ,其中包括根据documentation的Android Phonegap版本 4.0.2

版本问题似乎是Android Phonegap团队最终修复了 5.2.0 版本的cookie存储问题。它可以在release notes中找到:

  

CB-10896我们从未在WebView上启用过cookies

因此,将Phonegap更新为最新版本可以解决问题。

答案 1 :(得分:1)

PhoneGap从file://协议加载文件。遗憾的是,不允许跨源请求,除非您打开来自所有主机*的跨源请求,否则此问题将无法解决。

有多种方法可以修复,但它们真的很长。

http://

加载HTML

从Web服务器而不是本地存储加载整个网站。这将删除跨源请求的所有问题。好处是您在更改UI时不需要发布新版本的应用程序。但是你必须实现非常强大的缓存,第一次打开应用程序需要更长的时间。

拦截http://并提供本地文件

如您所知,phonegap只使用WebView,在所有平台上,您只需覆盖Url协议即可从应用的本地存储中注入文件。这会更快,浏览器会认为它是从同一资源加载html。

设置OAuth +自定义标头以进行身份​​验证

  1. 重定向到您网站上托管的登录页面,请说http://domain.com/api/login
  2. 成功登录后,使用PhoneGap localStorage(不是浏览器的localStorage)来存储授权。
  3. 从app导航到您的本地html页面,并为您发送到服务器的每个json api请求,在ajax请求中将授权标头作为单独的标头发送。
  4. 设置授权模块,如果您的授权是通过http请求中的自定义标头发送的,您可以手动授权asp.net请求

答案 2 :(得分:0)

根据MSDN

  

FormsAuthentication.SignOut方法删除了   表单 - 来自cookie的身份验证票证信息。

这就是您需要将用户注销的所有内容。您无需过期或删除cookie本身。只需将Logout()更改为:

即可
[ActionName("logout")]
[AllowAnonymous]
public String Logout()
{
    FormsAuthentication.SignOut();
    return "home";
}