jwa*_*zko 4 asp.net-mvc jquery session-cookies wif asp.net-mvc-3
我的项目我正在使用WIF (但这对于这个问题的上下文并不重要.你可以使用替代框架处理你的身份验证.问题是在执行ajax请求时处理身份验证失败).然而,在我的情况下,我编写了自定义服务器逻辑,它继承自ClaimsAuthenticationManager并处理身份验证:
public override IClaimsPrincipal Authenticate(string resourceName, IClaimsPrincipal incomingPrincipal)
{
if (incomingPrincipal != null && incomingPrincipal.Identity.IsAuthenticated)
{
// add some custom claims
}
return incomingPrincipal;
}
Run Code Online (Sandbox Code Playgroud)
现在,在我删除所有会话Cookie后,再次输入任何页面,我被重定向到WIF服务的登录页面,我被要求再次登录.一切都按预期工作.
但是如果我做了一个ajax请求,我就会收到一个错误,这个错误被拦截了:
$(document).ready(function () {
$.ajaxSetup({
error: function (XMLHttpRequest, textStatus, errorThrown) {
// do something
}
});
});
Run Code Online (Sandbox Code Playgroud)
不幸的是,XMLHttpRequest对象没有返回任何有意义的消息,基于此我可以像其他人一样以任何其他方式处理这种错误.在这种特殊情况下,我只希望应用程序重定向到登录页面 - 正常请求就是这样.

在执行ajax调用时,将调用方法Authenticatefrom ClaimsAuthenticationManager.Identity.IsAuthenticated返回false,方法结束,一切都完成.即使是OnAuthorization方法from BaseController也没有被调用,所以我无法将任何状态传递给ajax结果对象.
protected override void OnAuthorization(AuthorizationContext filterContext)
{
if (filterContext.HttpContext.Request.IsAjaxRequest() && !User.Identity.IsAuthenticated)
{
//do something, for example pass custom result to filterContext
}
base.OnAuthorization(filterContext);
}
Run Code Online (Sandbox Code Playgroud)
如何解决这个难题?
我找到了一些关于此的资源(参见答案的底部),并与以下解决方案混淆:
在执行ajax请求时,我指定我想要json:
$.ajax({
url: action,
type: 'POST',
dataType: 'json',
data: jsonString,
contentType: 'application/json; charset=utf-8',
success:
function (result, textStatus, xhr) {
}
});
Run Code Online (Sandbox Code Playgroud)
因为我的框架处理身份验证,所以当令牌过期时,它会将http状态302置于响应中.因为我不希望我的浏览器透明地处理302响应,所以我在Global.asax中捕获它,并将状态更改为200 OK.另外,我添加了标题,指示我以特殊方式处理此类响应:
protected void Application_EndRequest()
{
if (Context.Response.StatusCode == 302
&& (new HttpContextWrapper(Context)).Request.IsAjaxRequest())
{
Context.Response.StatusCode = 200;
Context.Response.AddHeader("REQUIRES_AUTH", "1");
}
}
Run Code Online (Sandbox Code Playgroud)
响应内容未正确序列化为json,这会导致解析错误.调用错误事件,在其中执行重定向:
$(document).ready(function () {
$.ajaxSetup({
error: function (XMLHttpRequest, textStatus, errorThrown) {
if (XMLHttpRequest.getResponseHeader('REQUIRES_AUTH') === '1') {
// redirect to logon page
window.location = XMLHttpRequest.getResponseHeader('location');
}
// do sth else
}
});
});
Run Code Online (Sandbox Code Playgroud)
请参阅如何在jQuery Ajax调用之后管理重定向请求,以及此处如何处理用户会话到期时的AJAX请求,或者请求在302中终止以获得更多解释.
更新:
同时,我想出了新的解决方案,在我看来更好,因为可以应用于开箱即用的所有ajax请求(如果他们没有明确重新定义发送事件):
$.ajaxSetup({
beforeSend: checkPulse,
error: function (XMLHttpRequest, textStatus, errorThrown) {
document.open();
document.write(XMLHttpRequest.responseText);
document.close();
}
});
function checkPulse(XMLHttpRequest) {
var location = window.location.href;
$.ajax({
url: "/Controller/CheckPulse",
type: 'GET',
async: false,
beforeSend: null,
success:
function (result, textStatus, xhr) {
if (xhr.getResponseHeader('REQUIRES_AUTH') === '1') {
XMLHttpRequest.abort(); // terminate further ajax execution
window.location = location;
}
}
});
}
Run Code Online (Sandbox Code Playgroud)
控制器方法可以是最简单的:
[Authorize]
public virtual void CheckPulse() {}
Run Code Online (Sandbox Code Playgroud)
在Application_EndRequest()住宿和以前一样.
| 归档时间: |
|
| 查看次数: |
4202 次 |
| 最近记录: |