2013-03-08 53 views
0

使用Dojo與服務器通信時,是否可以在瀏覽器攔截之前捕獲401狀態代碼?嘗試使用Dojo捕獲HTTP 401

我使用Dojo 1.8與通過SSL使用基本身份驗證的RESTful服務器進行通信。客戶捕捉客戶的用戶名和密碼,然後包括他們對服務器的請求是這樣:

request.get(this.url, { 
    handleAs: "json", 
    user: creds.username, 
    password: creds.password 
}).then(
    function(user) { 
    console.log("user", user); 
    }, 
    function(error) { 
    console.log("error", error); 
    }); 

當客戶端憑證是正確的,這工程確定。但是,如果憑據錯誤,瀏覽器會在我的錯誤函數獲取它之前攔截返回的401狀態碼。

我已經看到有關此問題的其他討論,包括解決方法,其中服務器在發生認證錯誤時返回401以外的內容。然而,在我走下那條路線之前,我想知道是否有辦法讓我的代碼在瀏覽器之前獲得401狀態。

或者,使用SSL以外的其他基本身份驗證功能可以讓這更容易嗎?

回答

0

我找不到攔截瀏覽器攔截401狀態代碼的方法,但我解決了這個問題。這是我爲了解決這個問題而採取的措施。這隻有在您需要驗證時才能控制服務器返回的內容時纔有效。

首先我需要服務器在需要身份驗證時返回400狀態碼。我使用的Apache四郎,所以這只是參與創建BasicHttpAuthenticationFilter的子類,覆蓋sendChallenge()像這樣:

protected boolean sendChallenge(ServletRequest request, ServletResponse response) { 
    HttpServletResponse httpResponse = WebUtils.toHttp(response); 
    httpResponse.setStatus(HttpServletResponse.SC_BAD_REQUEST); 
    String authcHeader = getAuthcScheme() + " realm=\"" + getApplicationName() + "\""; 
    httpResponse.setHeader(AUTHENTICATE_HEADER, authcHeader); 
    return false; 
} 

在我來說,我不想註銷重定向到一個JSP頁面,所以我子類四郎的LogoutFilter preHandle()方法,像這樣:

protected boolean preHandle(ServletRequest request, ServletResponse response) throws Exception { 
    Subject subject = getSubject(request, response); 
    try { 
    subject.logout(); 
    } 
    catch (SessionException ise) { 
    // Log exception 
    } 
    return false; 
} 

我加入過濾器,以我的shiro.ini文件:

[main] 
myAuth = com.example.filters.MyBasicAuthFilter 
noRedirectLogout = com.example.filters.NoRedirectLogoutFilter 

[urls] 
/protected/** = myAuth 
/logout = noRedirectLogout 

您可以使用不同的狀態碼,只是讓一定要檢查客戶端上的同一個。

接下來,我創建了一個LoginController中處理的登錄和註銷:

define([], function() { 
    var string = {};  
    string.getBytes = function(str) { 
    console.log("string.getBytes:str", str); 
    var bytes = []; 
    for (var i = 0; i < str.length; ++i) { 
     bytes.push(str.charCodeAt(i)); 
    } 
    return bytes; 
    }; 
    return string; 
}); 

... 

_authorize: function(url, username, password) { 
    var namepw = new String(username + ":" + password); 
    var authstr = "Basic " + base64.encode(utilString.getBytes(namepw)); 

    var def = new Deferred(); 
    request.get(url, { 
    handleAs: "json", 
    headers : { 
     Authorization: authstr 
    } 
    }).then(
    function(data) { 
     def.resolve(data); 
    }, 
    function(err) { 
     if (err.response.status == 400) { 
     def.progress(); 
     } 
     else { 
     def.reject(err); 
     } 
    }); 
    return def; 
}, 

login: function(url, user, passwd) { 
    return this._authorize(url, user, passwd); 
}, 

logout: function(url) { 
    return this._authorize(url, "#fakeuser#", "#fakepw#"); 
}; 

使用控制器登錄回來一個延遲,並且可以做適當的事情代碼:

var auth = this.controller.login(creds); 
Deferred.when(auth, 
    function(data) { 
    if (data != null) { 
     // Successful login 
    } 
    else { 
     // Non-authentication error 
    } 
    }, 
    function(err) { 
    // Non-authentication error 
    }, 
    function(updt) { 
    // Invalid username or password 
    } 
); 

調用註銷的代碼也得到一個延期:

controller.logout("/logout").then(function(val) { 
    // Successful logut 
}, function(err) { 
    // Error attempting to logout 
}); 

l ogout通過使註銷過濾器返回成功(狀態== 200)而工作,而不考慮用戶名密碼,並傳遞瀏覽器將捕獲的無效用戶名和密碼。希望這一切都能幫助別人。