Phonegap (Android) 上的 ASP.NET 表单身份验证问题

Posted

技术标签:

【中文标题】Phonegap (Android) 上的 ASP.NET 表单身份验证问题【英文标题】:Issues with ASP.NET Forms Authentication on Phonegap (Android) 【发布时间】:2015-11-10 04:09:22 【问题描述】:

我有一个 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 设置正确,登录后它确实可以在我的授权方法上运行,但有时(通常)当我关闭应用程序并再次打开它时,我不再登录. 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()) 多次执行注销/登录请求 登录/注销后对其他方法执行请求 登录/注销请求和重新加载之间的超时 1-10 秒 上述的各种变体

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

我不知道从这里往哪个方向走。 Android WebView 中是否有可能导致这种行为的东西?还有什么我可以测试的吗?请帮忙!

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

编辑: 受到 F*** 评论的启发,我将注销方法更改为:

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。

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

【问题讨论】:

我认为您应该发布您的 Android 代码以获取更多信息。 “Android 代码”是什么意思?我说的是Phonegap应用程序,所有相关的JS代码都在问题中。 我的意思是你如何设置你的 WebView Phonegap (Cordova API) 正在为我“设置”WebView。我只能通过config.xml 控制应用程序的设置。 AndroidManifest.xml 根据这些设置在构建中创建。 在黑暗中拍摄。您可以尝试将 HttpContext.Current.Response.Cookies.Add(cookie) 替换为 Response.Cookies[System.Web.Security.FormsAuthentication.FormsCookieName].Expires = DateTime.Now.AddYears(-1)。不确定它会改变什么,但可以防止您最终创建多个 cookie 并使用错误的 cookie。 【参考方案1】:

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

有多种方法可以解决这个问题,但它们真的很长。

http://加载Html

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

拦截http://并传递本地文件

如您所知,phonegap 仅使用 WebView,在所有平台上,您都可以简单地覆盖 Url 协议以从应用程序的本地存储中注入文件。这会更快,并且浏览器会认为它正在从同一资源加载 html。

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

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

【讨论】:

感谢您的详细解答。我认为您是对的,解决此问题的正确方法是将身份验证方法更改为 OAuth 或类似方法。【参考方案2】:

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

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

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

因此,将您的 Phonegap 更新到最新版本应该可以解决问题。

【讨论】:

你在哪里找到 OP 的 config.xml 文件? 我认为我没有得到这个问题。你能说得更具体一点吗? 不幸的是,这并没有解决问题。我现在使用的是 cli-6.3.0 (Android 5.2.1),登录/注销的行为完全相同。【参考方案3】:

根据MSDN:

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

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

[ActionName("logout")]
[AllowAnonymous]
public String Logout()

    FormsAuthentication.SignOut();
    return "home";

【讨论】:

以上是关于Phonegap (Android) 上的 ASP.NET 表单身份验证问题的主要内容,如果未能解决你的问题,请参考以下文章

eclipse / Android上的Cordova phonegap

Android 设备上的 PhoneGap 蓝牙插件

PhoneGap 的 getPicture() 调用不会保存到 Android 手机上的图库

如何避免仅在 Android 上的 Phonegap 应用程序黑屏?

Android 设备上的 phonegap 应用程序不发送 AJAX 请求

是否可以分析 Android 或 iOS 上的 PhoneGap 应用缓存?