Dea*_*ing 69 asp.net forms-authentication
我有一个使用ASP.NET Forms身份验证的应用程序.在大多数情况下,它工作得很好,但我试图通过.ashx文件添加对简单API的支持.我希望ashx文件具有可选的身份验证(即,如果您不提供身份验证标头,那么它只是匿名工作).但是,根据您的操作,我希望在某些条件下要求身份验证.
如果没有提供所需的身份验证,我认为用状态代码401进行响应将是一件简单的事情,但似乎Forms Authentcation模块正在拦截它并通过重定向到登录页面进行响应.我的意思是,如果我的ProcessRequest方法看起来像这样:
public void ProcessRequest(HttpContext context)
{
Response.StatusCode = 401;
Response.StatusDescription = "Authentication required";
}
Run Code Online (Sandbox Code Playgroud)
然后,而不是像我期望的那样在客户端上获得401错误代码,我实际上正在获得302重定向到登录页面.
对于nornal HTTP流量,我可以看到它是如何有用的,但是对于我的API页面,我希望401经过不加修改,以便客户端调用者可以以编程方式响应它.
有没有办法做到这一点?
zac*_*ydl 74
ASP.NET 4.5添加了Boolean HttpResponse.SuppressFormsAuthenticationRedirect属性.
public void ProcessRequest(HttpContext context)
{
Response.StatusCode = 401;
Response.StatusDescription = "Authentication required";
Response.SuppressFormsAuthenticationRedirect = true;
}
Run Code Online (Sandbox Code Playgroud)
Dea*_*ing 35
经过一些调查后,看起来FormsAuthenticationModule为HttpApplicationContext.EndRequest事件添加了一个处理程序.在它的处理程序中,它检查401状态代码,并基本上做了一个Response.Redirect(loginUrl).据我所知,如果想要使用,就没有办法覆盖这种行为FormsAuthenticationModule.
我最终绕过它的方式是FormsAuthenticationModule在web.config中禁用如下:
<authentication mode="None" />
Run Code Online (Sandbox Code Playgroud)
然后实现Application_AuthenticateEvent自己:
void Application_AuthenticateRequest(object sender, EventArgs e)
{
if (Context.User == null)
{
var oldTicket = ExtractTicketFromCookie(Context, FormsAuthentication.FormsCookieName);
if (oldTicket != null && !oldTicket.Expired)
{
var ticket = oldTicket;
if (FormsAuthentication.SlidingExpiration)
{
ticket = FormsAuthentication.RenewTicketIfOld(oldTicket);
if (ticket == null)
return;
}
Context.User = new GenericPrincipal(new FormsIdentity(ticket), new string[0]);
if (ticket != oldTicket)
{
// update the cookie since we've refreshed the ticket
string cookieValue = FormsAuthentication.Encrypt(ticket);
var cookie = Context.Request.Cookies[FormsAuthentication.FormsCookieName] ??
new HttpCookie(FormsAuthentication.FormsCookieName, cookieValue) { Path = ticket.CookiePath };
if (ticket.IsPersistent)
cookie.Expires = ticket.Expiration;
cookie.Value = cookieValue;
cookie.Secure = FormsAuthentication.RequireSSL;
cookie.HttpOnly = true;
if (FormsAuthentication.CookieDomain != null)
cookie.Domain = FormsAuthentication.CookieDomain;
Context.Response.Cookies.Remove(cookie.Name);
Context.Response.Cookies.Add(cookie);
}
}
}
}
private static FormsAuthenticationTicket ExtractTicketFromCookie(HttpContext context, string name)
{
FormsAuthenticationTicket ticket = null;
string encryptedTicket = null;
var cookie = context.Request.Cookies[name];
if (cookie != null)
{
encryptedTicket = cookie.Value;
}
if (!string.IsNullOrEmpty(encryptedTicket))
{
try
{
ticket = FormsAuthentication.Decrypt(encryptedTicket);
}
catch
{
context.Request.Cookies.Remove(name);
}
if (ticket != null && !ticket.Expired)
{
return ticket;
}
// if the ticket is expired then remove it
context.Request.Cookies.Remove(name);
return null;
}
}
Run Code Online (Sandbox Code Playgroud)
它实际上稍微复杂一点,但我基本上通过查看FormsAuthenticationModule反射器的实现来获得代码.我的实现与内置的不同之处FormsAuthenticationModule在于,如果您使用401响应它不会执行任何操作 - 根本不会重定向到登录页面.我想如果这成为一个要求,我可以在上下文中放置一个项目来禁用自动重定向或其他东西.
Luk*_*son 11
我不确定这是否适用于所有人,但在IIS7中,您可以在设置状态代码和描述后调用Response.End().这样,#&$ ^#@*!FormsAuthenticationModule不会执行重定向.
public void ProcessRequest(HttpContext context) {
Response.StatusCode = 401;
Response.StatusDescription = "Authentication required";
Response.End();
}
Run Code Online (Sandbox Code Playgroud)
为了稍微建立zacharydl的答案,我用它来解决我的困境.在每个请求,在开始时,如果它是AJAX,立即抑制行为.
protected void Application_BeginRequest()
{
HttpRequestBase request = new HttpRequestWrapper(Context.Request);
if (request.IsAjaxRequest())
{
Context.Response.SuppressFormsAuthenticationRedirect = true;
}
}
Run Code Online (Sandbox Code Playgroud)
小智 5
我不知道Response.End()是如何为你工作的.我毫不高兴地尝试了它,然后查看了MSDN的Response.End():'停止执行页面,并引发EndRequest事件'.
对于我的黑客的价值是:
_response.StatusCode = 401;
_context.Items["401Override"] = true;
_response.End();
Run Code Online (Sandbox Code Playgroud)
然后在Global.cs中添加一个EndRequest处理程序(将在Authentication HTTPModule之后调用):
protected void Application_EndRequest(object sender, EventArgs e)
{
if (HttpContext.Current.Items["401Override"] != null)
{
HttpContext.Current.Response.Clear();
HttpContext.Current.Response.StatusCode = 401;
}
}
Run Code Online (Sandbox Code Playgroud)
我知道已经有了回答,但在尝试解决类似的问题时,我发现了这个问题(http://blog.inedo.com/2010/10/12/http-418-im-a-teapot-finally-a- %e2%80%9clegitimate%e2%80%9d-use /)作为替代方案.
基本上,您在代码中返回自己的HTTP状态代码(例如418).在我的例子中是一个WCF数据服务.
throw new DataServiceException(418, "401 Unauthorized");
Run Code Online (Sandbox Code Playgroud)
然后使用HTTP模块在EndRequest事件处理它以将代码重写回401.
HttpApplication app = (HttpApplication)sender;
if (app.Context.Response.StatusCode == 418)
{
app.Context.Response.StatusCode = 401;
}
Run Code Online (Sandbox Code Playgroud)
浏览器/客户端将收到正确的内容和状态代码,它对我很有用:)
如果您有兴趣了解有关HTTP状态代码418的更多信息,请参阅此问题和答案.
| 归档时间: |
|
| 查看次数: |
42968 次 |
| 最近记录: |