Выход пользователя из системы при использовании базовой аутентификации HTTP
Я хочу, чтобы пользователи могли входить в систему через обычные режимы аутентификации HTTP.
Проблема в том, что я также хочу, чтобы они могли снова выходить из системы - странные браузеры просто не поддерживают это.
Это считается риском для хакерских атак: пользователь оставляет свой компьютер разблокированным, а браузер - открытым, и кто-то другой может легко зайти на сайт. Обратите внимание, что простого закрытия вкладки браузера недостаточно для сброса токена, поэтому пользователям может быть легко пропустить это.
Итак, я нашел обходной путь, но это полный клочок:
1) Перенаправить их на страницу выхода
2) На этой странице запустите скрипт, чтобы ajax загрузить другую страницу с фиктивными учетными данными:
$j.ajax({
url: '<%:Url.Action("LogOff401", new { id = random })%>',
type: 'POST',
username: '<%:random%>',
password: '<%:random%>',
success: function () { alert('logged off'); }
});
3) Это всегда должно возвращать 401 в первый раз (для принудительной передачи новых учетных данных), а затем принимать только фиктивные учетные данные:
[AcceptVerbs(HttpVerbs.Post)]
public ActionResult LogOff401(string id)
{
// if we've been passed HTTP authorisation
string httpAuth = this.Request.Headers["Authorization"];
if (!string.IsNullOrEmpty(httpAuth) &&
httpAuth.StartsWith("basic", StringComparison.OrdinalIgnoreCase))
{
// build the string we expect - don't allow regular users to pass
byte[] enc = Encoding.UTF8.GetBytes(id + ':' + id);
string expected = "basic " + Convert.ToBase64String(enc);
if (string.Equals(httpAuth, expected, StringComparison.OrdinalIgnoreCase))
{
return Content("You are logged out.");
}
}
// return a request for an HTTP basic auth token, this will cause XmlHttp to pass the new header
this.Response.StatusCode = 401;
this.Response.StatusDescription = "Unauthorized";
this.Response.AppendHeader("WWW-Authenticate", "basic realm=\"My Realm\"");
return Content("Force AJAX component to sent header");
}
4) Теперь учетные данные случайной строки были приняты и кэшированы браузером. Когда они посещают другую страницу, она пытается их использовать, терпит неудачу, а затем запрашивает правильные.
Обратите внимание, что в моих примерах кода используются jQuery и ASP.Net MVC, но то же самое должно быть возможно с любым технологическим стеком.
Есть еще один способ сделать это в IE6 и выше:
document.execCommand("ClearAuthenticationCache");
Однако это очищает всю аутентификацию - они выходят из моего сайта, и они также выходят из своей электронной почты. Так что это вышло.
Есть ли лучший способ сделать это?
Я видел другие вопросы по этому вопросу, но им уже 2 года - есть ли лучший способ в IE9, FX4, Chrome и т. Д.?
Если нет лучшего способа сделать это, можно ли положиться на этот клочок? Есть ли способ сделать его более надежным?
1 ответ
Короткий ответ:
Не существует надежной процедуры для выхода из системы с использованием HTTP Basic или дайджест-аутентификации, учитывая текущие реализации базовой аутентификации.
Такая аутентификация работает, когда клиент добавляет заголовок авторизации к запросу.
Если для определенного ресурса сервер не удовлетворен предоставленными учетными данными (например, если их нет), он ответит кодом состояния "401 Unauthorized" и запросит аутентификацию. Для этого он предоставит ответ WWW-Authenticate с ответом.
Клиенту не нужно ждать, пока сервер запросит аутентификацию. Он может просто предоставить заголовок авторизации, основанный на некоторых локальных предположениях (например, кэшированная информация из последней успешной попытки).
Хотя ваш изложенный подход к "очистке" информации об аутентификации имеет хорошие шансы работать с широким кругом клиентов (а именно с широко распространенными браузерами), нет абсолютно никакой гарантии, что другой клиент может быть "умнее" и просто различать правильные данные аутентификации для ваша страница "выхода" и любые другие страницы целевого сайта.
Вы обнаружите похожую "проблему" при использовании аутентификации на основе сертификатов на стороне клиента. Пока нет явной поддержки со стороны клиентов, вы можете сражаться на потерянной земле.
Так что, если "выход из системы" является проблемой, перейдите к любой сеансовой аутентификации.
Если у вас есть доступ к реализации аутентификации на стороне сервера, вы можете реализовать функцию, которая игнорирует информацию аутентификации, представленную с заголовком авторизации (если она все еще идентична той, что была представлена во время текущего "сеанса) по запросу вашего кода уровня приложения. (или предоставьте некоторый "тайм-аут", после которого любые учетные данные будут повторно запрашиваться), чтобы клиент запросил у пользователя "новые" учетные данные (выполняя новый вход в систему).