ElJ*_*ste 6 javascript ajax caching nginx basic-authentication
语境
我有一个朋友,他的名字叫鲍勃。
Bob 有一个服务器,其中的应用程序正在运行并且只能在本地访问。为了从外部世界访问此应用程序,Bob使用 nginx 和模块auth_basic安装并配置了反向代理。
每个请求都经过反向代理的身份验证过程。两种情况:
直到这里一切都正常。这就像基本身份验证规范所期望的那样。
问题
Bob 不喜欢浏览器的默认对话框,并且想要一个带有表单的漂亮 html 页面。他将 nginx 服务器配置为拥有自己的 html 表单。
问题在于,默认情况下,表单的 HTML 提交过程不会发送Authorization标头参数。Bob 需要使用XMLHttpRequest。他实现了它,并在凭据良好时从服务器收到良好的200 HTTP 响应。
与默认表单行为不同,使用 XMLHttpRequest 时,浏览器不会在成功时自动缓存凭据。因此每个子请求都会再次显示登录表单:'(
Bob 无法更改本地应用程序的前端代码以自行发送每个请求中的凭据(与 SPA 一样)。事实上,他无权访问该应用程序。他只能访问 nginx conf 和他自己的 html 登录表单。所以存储在这里是没有用的。
问题
bob 是否可以在收到 XHR 响应后让浏览器缓存凭据?
(目标是即使使用 XMLHttpRequest 也能表现得像默认行为)
编辑 :
进一步说明
本地应用程序正在本地主机上运行。鲍勃没有开发这个应用程序,他无法编辑它。这个应用程序不提供身份验证,Bob 使用 nginx 的 basic_auth 模块作为反向代理来对人员进行身份验证。
它运行良好,但使用实现基本身份验证规范的浏览器的默认行为。此行为会显示丑陋的表单并在成功时缓存凭据。如果 Bob 提供他自己的表单,则行为继续,这是正常的,因为基本身份验证规范需要HTML 表单无法提供的特定标头参数(授权:基本...) 。Bob需要使用XHR来提供这个参数。
问题是,如何使用 XHR 恢复浏览器的良好行为?
我们只能在login.html上使用JS,而不能在本地应用程序上使用JS。这是工作流程:
我还精确地指出,解决方案是用真正的后端应用程序和另一个身份验证系统(例如自动发送的 cookie)替换 nginx 基本身份验证反向代理,该系统将作为反向代理工作,但这不是提出的问题。
编辑2:
为什么 Bob 不能使用存储解决方案?
在 ulgy 表单场景中,他没有 HTML 登录文件。当浏览器客户端向服务器发出请求时,服务器仅响应带有WWW-Authenticate标头但不包含 HTML 内容的 HTTP 响应。让这个标题参数显示一个表单的简单事实。只需输入正确的凭据就会发回 200 HTTP 响应,浏览器将缓存凭据并在每个带有 HTTP 标头Authorization: Basic的请求中发送它。
在 login.html 场景中,成功登录后,我们需要在每个请求中发回 HTTP 标头Authorization: Basic(不是 cookie,因为这是 Basic Auth 规范的工作方式,而 Bob 没有任何后端,只有 nginx模块)。可以从 login.html 发送此标头,因为我们可以在其上附加 JS。但是,服务器响应的下一个页面将是来自本地应用程序的 HTML 文件,Bob 无权访问其 HTML,也无法在其上附加 JS 来为下一个请求提供标头Authorization: Basic。可以从 login.html 文件中存储 cookie,但需要从其他页面检索此 cookie 并用于发送标头Authorization: Basic,这是不可能的,因为 Bob 无权访问这些页面的 JS。
先感谢您。
由于您已经在使用 ajax,因此只需设置 javascript 并读取 cookie:
(我在这里使用 jQuery,为了简单起见,如果您不使用 jQuery,请用适当的语法替换 ajax 调用):
function getCookie(cookiename) {
/* a function to find a cookie based on its name */
var r = document.cookie.match('\\b' + cookiename + "=([^;]*)\\b");
// document.cookie returns all cookies for this url
return r ? r[1] : undefined;
// return the regex capture if it has content, otherwise return undefined
}
function getData(auth_basic) {
$.ajax({
url: 'url_of_nginx...',
headers: {
'Authorization': 'Basic ' + auth_basic
} // send auth header on xmlhttprequest GET
}).next(function ajaxSuccess(data) {
// data from the nginx
document.cookie = '_auth_cookie=' + auth_basic;
// store my auth in a cookie
}, function ajaxFailed(jqXHR) {
// do something on failure, like
showLoginForm()
});
}
function showLoginForm() {
/* function to render your form */
// attach an event handler to form submission
$('#submit_button_id').click(function form_submitted(login_evt) {
// I clicked login
login_evt.preventDefault(); // don't really submit the form
// get my field form values
username = $('#username_input_field').val();
password = $('#password_input_field').val();
// I base64 the auth string
var auth_basic = btoa(username + ':' + password);
// try to auth
getData(auth_basic);
});
}
var auth_cookie = getCookie('_auth_cookie');
if (auth_cookie === undefined) {
// I have no cookie
showLoginForm()
} else {
getData(auth_cookie)
}
Run Code Online (Sandbox Code Playgroud)