我找不到阻止浏览器拦截 401 状态代码的方法,但我解决了这个问题。这是我在其他人遇到这个问题时所做的。仅当您可以控制需要身份验证时服务器返回的内容时,这才有效。
首先,当需要身份验证时,我让服务器返回 400 状态码。我正在使用 Apache Shiro,所以这只涉及创建 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 页面,因此我将 Shiro 的 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#");
};
使用控制器登录的代码会返回一个 Deferred,并且可以做相应的事情:
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
}
);
调用注销的代码也会返回一个 Deferred:
controller.logout("/logout").then(function(val) {
// Successful logut
}, function(err) {
// Error attempting to logout
});
注销通过让注销过滤器返回成功(状态 == 200)而不管用户名密码,并传递浏览器将捕获的无效用户名和密码。希望这一切对某人有所帮助。