iOS:使用XMLHttpRequest进行身份验证-处理401响应 [英] iOS: Authentication using XMLHttpRequest - Handling 401 response

查看:151
本文介绍了iOS:使用XMLHttpRequest进行身份验证-处理401响应的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在使用PhoneGap(又名Cordova)编写iOS应用程序,我有一个简单的html登录页面,该页面使用XMLHttpRequest通过SSL进行基本身份验证来登录用户.正确输入用户名和密码后,一切都会变得非常出色.但是,如果输入错误的用户名/密码,则不会调用我的任何回调.

I'm writing an iOS application using PhoneGap (aka Cordova), I have a simple html login page that logs the user in using an XMLHttpRequest with basic authentication over SSL. Everything works splendidly when you enter your username and password correctly. However, if you enter the wrong username/password none of my callbacks are ever called.

例如,如果您使用错误的用户名/密码在Chrome上运行相同的代码,则chrome的行为类似,只是会弹出身份验证质询对话框.在Chrome浏览器的对话框上点击取消"将控制权返回给我的JavaScript代码.不幸的是,在iOS上,UIWebView甚至不会弹出身份验证对话框,而只是挂起.我需要一种方法来告诉用户他们输入了错误的用户名或密码,以便他们可以重试.

If you run the same code on Chrome for example, with the wrong username/password, chrome behaves in a similar manner, except it pops up an authentication challenge dialog. Hitting cancel on chrome's dialog returns control to my javascript code. Unfortunately, on iOS, the UIWebView wont even popup an auth dialog, it just hangs. I need a way to tell the user that they entered the wrong username or password so they can retry.

我能找到的最接近答案的东西是 http://www.freelock.com/2008/06/technical-note-http-auth-with-ajax ,但是从服务器更改响应状态似乎不是正确的选择.

The closest thing to an answer I could find was this http://www.freelock.com/2008/06/technical-note-http-auth-with-ajax but changing the response status from the server doesn't seem like the right thing to do.

这基本上是我的请求代码的样子,但是当发送错误的用户名或密码时,它永远不会到达我的onload回调(实际上,onreadystatechange回调仅被调用一次,而对于readyState 1,也就是OPEN).

Here's basically what my request code looks like, but when a bad username or password is sent it never reaches my onload callback (in fact the onreadystatechange callback only gets called once and thats for readyState 1, aka OPEN).

var req = new XMLHttpRequest();
req.onload = function(ev) {
    if (req.status == 401) {
        alert("Invalid Username/Password");
        document.getElementById('password').focus();
    } else if (req.status == 200) {
        window.location.href = some_secure_site;
    } else {
        // edit //
        alert("Some other status");
    }
}
req.onerror = function (ev) { alert('Error'); };
req.ontimeout = function(ev) { alert('Timeout'); };
req.open('GET', uri, true, userValue, passValue);
req.withCredentials = true;
req.send();

推荐答案

在iOS上尝试执行此操作时,一些事情对我来说很明显.一个是iOS有一个与基本身份验证有关的错误,因此,如果您的密码中包含某些特殊字符,则您将永远不会从服务器返回响应,因为您的服务器将永远不会收到身份验证挑战.也就是说,如果您在打开"方法中使用用户名和密码字段.

A few things became apparent to me while trying to do this on iOS. One is that iOS has a bug relating to basic auth, so if your password has certain special characters in it you'll never get a response back from your server because your server will never get an authentication challenge. That is, if you're using the username and password field in the "open" method.

我的猜测是,当他们应该使用http标头和base64编码凭据时,他们正在做一些愚蠢的事情,例如通过 http://username:password@myorigin.com/etc 发送

My guess is they are doing something stupid like sending it via http://username:password@myorigin.com/etc when they should be using http headers and base64 encoding the creds like so

req.setRequestHeader("Authorization", "Basic " + base64(username) + ':' + base64(password));

我了解到的另一件事是,基本身份验证不是非常安全,并且容易出现一百万个问题.其中一个会让您感到烦恼的是,客户端将缓存用户名和密码,这将覆盖您通过"req.open(...)"发送的所有新值.祝您好运,仅使用JavaScript就能解决该问题,您必须在ObjC中做一些魔术来清除缓存.

The other thing I learned is that Basic Auth isnt very secure and is prone to a million and one problems. One of which that will annoy you is that the client will cache the username and password, which will override any new values you send via "req.open(...)". Good luck getting around that using javascript alone, you'll have to do some magic in ObjC to clear the cache.

如果您可以控制服务器,则建议使用令牌身份验证.通过SSL连接,然后发送包含用户名和密码的JSON数据的POST.然后,服务器可以发送带有身份验证令牌的JSON数据(本质上是一堆随机字符,长度足够长,以至于无法猜测),UUID可以很好地工作.这是由服务器生成的,只有客户端知道并且服务器).然后将令牌和用户名存储在钥匙串中,这样用户每次启动您的应用程序时都无需输入凭据.

If you have control over your server, I would suggest using token authentication. Connect over SSL and then send a POST with JSON data containing the username and password. The server could then send back JSON data with an authentication token (essentially a bunch of random characters long enough that it can't ever be guessed, a UUID works well. this is generated by the server and can only be known to the client and the server). Then store the token and the username in the keychain so the user doesnt need to enter their creds everytime they start your app.

我的服务器将始终发送回200响应,但是JSON数据将包含重试或存储auth令牌所需的信息.一般来说,基本身份验证基本上很烂.

My server will always send back a 200 response but the JSON data will contain the information needed to either retry or to store the auth token. In general... basic auth basically sucks.

try {
    var req = new XMLHttpRequest();
    req.onload = function(ev) {
        var response = JSON.parse(this.responseText);
        if (response.success === true) {
            // The server will respond with a token that will allow us to login
            storeCredentials(userValue, response.token);
            // redirect with token
        else if (req.status == 401) {
            alert("Invalid Username/Password");
            document.getElementById('password').focus();
        } else {
            alert("Some other status");
        }
    }
    req.ontimeout = setTimeout(function(ev) { navigator.notification.alert('Timeout trying to contact the server'); }, 10000);
    req.onerror = function(ev) { clearTimeout(this.ontimeout); navigator.notification.alert('Error connecting to the server during authentication.'); };

    var uri = myWebOrigin + '/authenticate';
    req.open('POST', uri, true);
    req.setRequestHeader('Cache-Control', 'no-cache');
    req.setRequestHeader('Content-Type', 'application/json');
    json_data = {username : Base64.encode(userValue), password : Base64.encode(passValue)};
    req.send(JSON.stringify(json_data));
} catch(error) {
    navigator.notification.alert('Uh oh, an error occurred trying to login! ' + error);
    return;
}

这篇关于iOS:使用XMLHttpRequest进行身份验证-处理401响应的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆