是否有可能注销用户从一个网站,如果他是使用基本身份验证?
杀死会话是不够的,因为一旦用户通过身份验证,每个请求都包含登录信息,因此用户下次使用相同的凭据访问站点时将自动登录。
目前唯一的解决方案是关闭浏览器,但从可用性的角度来看,这是不可接受的。
是否有可能注销用户从一个网站,如果他是使用基本身份验证?
杀死会话是不够的,因为一旦用户通过身份验证,每个请求都包含登录信息,因此用户下次使用相同的凭据访问站点时将自动登录。
目前唯一的解决方案是关闭浏览器,但从可用性的角度来看,这是不可接受的。
当前回答
对于使用Windows身份验证(也称为协商、Kerberos或NTLM身份验证)的任何人,我使用ASP。NET Core和Angular。
我找到了一种有效的方式来改变用户!
我修改我的登录方法在javascript方面,就像这样:
protected login(changeUser: boolean = false): Observable<AuthInfo> {
let params = new HttpParams();
if(changeUser) {
let dateNow = this.datePipe.transform(new Date(), 'yyyy-MM-dd HH:mm:ss');
params = params.set('changeUser', dateNow!);
}
const url: string = `${environment.yourAppsApiUrl}/Auth/login`;
return this.http.get<AuthInfo>(url, { params: params });
}
下面是我在后台的方法:
[Route("api/[controller]")]
[ApiController]
[Produces("application/json")]
[Authorize(AuthenticationSchemes = NegotiateDefaults.AuthenticationScheme)]
public class AuthController : Controller
{
[HttpGet("login")]
public async Task<IActionResult> Login(DateTime? changeUser = null)
{
if (changeUser > DateTime.Now.AddSeconds(-3))
return Unauthorized();
...
... (login process)
...
return Ok(await _authService.GetToken());
}
}
return Unauthorized()返回401代码,导致浏览器识别弹出窗口出现,以下是过程:
如果我想更改用户,我现在将日期作为参数传输。 如果从那一刻起不超过3秒,我就返回401代码。 我完成了我的凭证,并将具有相同参数的相同请求发送到后端。 由于已经过去了3秒多,我继续登录过程,但这次使用的是新的凭据!
其他回答
以下功能在Firefox 40、Chrome 44、Opera 31和IE 11上均已确认有效。 Bowser用于浏览器检测,也使用jQuery。 —“secUrl”为密码保护区域的url,用户可以从该url退出。 —“redirUrl”为非密码保护区域的url(注销成功页面)。 你可能想增加重定向计时器(目前是200ms)。
function logout(secUrl, redirUrl) { if (bowser.msie) { document.execCommand('ClearAuthenticationCache', 'false'); } else if (bowser.gecko) { $.ajax({ async: false, url: secUrl, type: 'GET', username: 'logout' }); } else if (bowser.webkit) { var xmlhttp = new XMLHttpRequest(); xmlhttp.open("GET", secUrl, true); xmlhttp.setRequestHeader("Authorization", "Basic logout"); xmlhttp.send(); } else { alert("Logging out automatically is unsupported for " + bowser.name + "\nYou must close the browser to log out."); } setTimeout(function () { window.location.href = redirUrl; }, 200); }
这在基本身份验证中是不可能直接实现的。
在HTTP规范中,服务器没有机制告诉浏览器停止发送用户已经提供的凭据。
有一些“黑客”(参见其他答案)通常涉及使用XMLHttpRequest发送带有错误凭据的HTTP请求,以覆盖最初提供的凭据。
实际上,我认为基本身份验证的目的是用于静态页面,而不是用于任何复杂的会话管理或CGI页面。
因此,当需要会话管理时,你应该设计一个经典的“登录表单”来查询用户和密码(可能也是第二个因素)。 CGI表单处理程序应该将成功的身份验证转换为服务器上记住的会话(ID)(在cookie中或作为URI的一部分)。
然后,通过使服务器(和客户端)“忘记”会话。 另一个优点是(即使加密后)用户和密码不会随每个请求一起发送到服务器(而是发送会话ID)。
如果服务器上的会话ID与执行的“最后一个动作”的时间戳相结合,则会话超时可以通过比较该时间戳与当前时间来实现: 如果时间跨度太大,则通过忘记会话ID来“超时”会话。
对无效会话的任何请求都将导致重定向到登录页面(或者如果您想让它更舒服,您可以使用“重新验证表单”再次请求密码)。
作为概念的证明,我实现了一个完全无cookie的会话管理,它完全基于URI(会话ID始终是URI的一部分)。 然而,完整的代码对于这个答案来说太长了。
当希望处理数千个并发会话时,必须特别注意性能。
这适用于IE/Netscape/Chrome浏览器:
function ClearAuthentication(LogOffPage)
{
var IsInternetExplorer = false;
try
{
var agt=navigator.userAgent.toLowerCase();
if (agt.indexOf("msie") != -1) { IsInternetExplorer = true; }
}
catch(e)
{
IsInternetExplorer = false;
};
if (IsInternetExplorer)
{
// Logoff Internet Explorer
document.execCommand("ClearAuthenticationCache");
window.location = LogOffPage;
}
else
{
// Logoff every other browsers
$.ajax({
username: 'unknown',
password: 'WrongPassword',
url: './cgi-bin/PrimoCgi',
type: 'GET',
beforeSend: function(xhr)
{
xhr.setRequestHeader("Authorization", "Basic AAAAAAAAAAAAAAAAAAA=");
},
error: function(err)
{
window.location = LogOffPage;
}
});
}
}
$(document).ready(function ()
{
$('#Btn1').click(function ()
{
// Call Clear Authentication
ClearAuthentication("force_logout.html");
});
});
function logout(url){
var str = url.replace("http://", "http://" + new Date().getTime() + "@");
var xmlhttp;
if (window.XMLHttpRequest) xmlhttp=new XMLHttpRequest();
else xmlhttp=new ActiveXObject("Microsoft.XMLHTTP");
xmlhttp.onreadystatechange=function()
{
if (xmlhttp.readyState==4) location.reload();
}
xmlhttp.open("GET",str,true);
xmlhttp.setRequestHeader("Authorization","Basic xxxxxxxxxx")
xmlhttp.send();
return false;
}