11

PhoneGap(別名Cordova)を使用してiOSアプリケーションを作成しています。SSLを介した基本認証でXMLHttpRequestを使用してユーザーをログインさせる単純なhtmlログインページがあります。ユーザー名とパスワードを正しく入力すると、すべてが見事に機能します。ただし、間違ったユーザー名/パスワードを入力すると、コールバックは呼び出されません。

たとえば、Chromeで同じコードを間違ったユーザー名/パスワードで実行した場合、Chromeは認証チャレンジダイアログをポップアップすることを除いて、同じように動作します。Chromeのダイアログでキャンセルを押すと、JavaScriptコードに制御が戻ります。残念ながら、iOSでは、UIWebViewは認証ダイアログをポップアップすることすらなく、ハングするだけです。再試行できるように、間違ったユーザー名またはパスワードを入力したことをユーザーに通知する方法が必要です。

私が見つけた答えに最も近いのはこのhttp://www.freelock.com/2008/06/technical-note-http-auth-with-ajaxでしたが、サーバーからの応答ステータスを変更することは、正しいこと。

基本的に私のリクエストコードは次のようになりますが、不正なユーザー名またはパスワードが送信されても​​、onloadコールバックに到達することはありません(実際、onreadystatechangeコールバックは1回だけ呼び出され、readyState 1、別名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();
4

5 に答える 5

4

iOSでこれを行おうとすると、いくつかのことが明らかになりました。1つは、iOSに基本認証に関連するバグがあるため、パスワードに特定の特殊文字が含まれている場合、サーバーが認証チャレンジを取得しないため、サーバーから応答が返されることはありません。つまり、「open」メソッドでユーザー名とパスワードのフィールドを使用している場合です。

私の推測では、httpヘッダーとbase64エンコーディングを使用する必要があるときにhttp:// username:password@myorigin.com/etc経由で送信するなど、愚かなことをしていると思います。

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

私が学んだもう1つのことは、基本認証はあまり安全ではなく、100万と1つの問題が発生しやすいということです。その1つは、クライアントがユーザー名とパスワードをキャッシュすることです。これにより、「req.open(...)」を介して送信する新しい値が上書きされます。javascriptだけを使用してそれを回避するために頑張ってください、あなたはキャッシュをクリアするためにObjCでいくつかの魔法をしなければならないでしょう。

サーバーを制御できる場合は、トークン認証を使用することをお勧めします。SSL経由で接続してから、ユーザー名とパスワードを含むJSONデータを含むPOSTを送信します。次に、サーバーは認証トークンを使用してJSONデータを送り返すことができます(基本的に、推測できないほど長いランダムな文字の束、UUIDは適切に機能します。これはサーバーによって生成され、クライアントとサーバー)。次に、トークンとユーザー名をキーチェーンに保存して、ユーザーがアプリを起動するたびに資格情報を入力する必要がないようにします。

私のサーバーは常に200応答を返しますが、JSONデータには、再試行または認証トークンの保存に必要な情報が含まれています。一般的に...基本認証は基本的に最悪です。

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;
}
于 2012-11-02T17:18:41.297 に答える
1

iOS + PhoneGap + jQueryを使用しているときに、どのコールバックも呼び出されないという同じ問題が発生しました。間違ったクレデンシャルを渡して使用した場合

$.ajax({
    ...
    timeout: 5000, // Some timeout value that makes sense
    ...
});

次に、エラーコールバックがで呼び出され{"readyState":0,"status":0,"statusText":"timeout"}ます。その場合、実際のエラーはHTTP401であると推測する必要があります。

または、

$.ajax({
    ...
    async: false, // :-(
    ...
});

エラーコールバックは、{"readyState":4,"responseText":"<html>...</html>","status":401,"statusText":"Unauthorized"}backのようなものを取得します。

于 2012-10-22T20:20:45.823 に答える
1

この問題を解決するにはWWW-Authenticate、サーバーの応答からヘッダーを削除します。

于 2017-03-15T14:39:40.507 に答える
0

受け取ったコード401とコードの横に、おそらく他のHTTPステータスコードがあります。200他のステータスコードが実際に受信されていないことを確認してください。

if (req.status == 401) {
    alert("Invalid Username/Password");
    document.getElementById('password').focus();
} else if (req.status == 200) {
    window.location.href = some_secure_site;
} else {
    alert('Unfetched status code '+req.status+' captured!');
}
于 2012-06-14T00:28:46.670 に答える
0

私は同じ問題を抱えています-無効なクレデンシャルが渡された場合、リクエストのコールバックは呼び出されません。

私の推測では、UIWebViewは内部的にクレデンシャルのプロンプトを表示するように指示されていますが、そのプロンプトは抑制されており、このバグが発生しています。これは、私が試した他のすべてのブラウザ(Safari、Chrome、Firefox)に基づいており、この場合、プロンプトが閉じられるまでコールバックを呼び出さない。

別の解決策(私が使用しているもの)は、認証を行うためにJavascriptを使用せず、代わりにiOS側で行うことです-UIWebViewで認証チャレンジを表示する方法のコードを使用できますか?これを行うための大まかなテンプレートとして。

于 2012-08-03T21:50:51.617 に答える