开发者

IIS 7 with URL Rewrite Module 2.0 - setting 401 status codes and the ReturnUrl

I have a website hosted on IIS 7 with the URL Rewrite module 2.0 installed. It is run by a content management system that looks at the URL and returns a 401 error if the current user does not have permission to view the page. This gets picked up by the ASP.NET URL authorization module which then kicks the page over to the loginUrl page as specified in the web.config file (forms authentication).

This works perfectly on my local machine - which is IIS 7 and Windows 7.

If the URL is, say, /612/some-string the user gets directed to the login page at /66/login?ReturnUrl=/612/some-string.

The URL rewriting looks at the first part of the URL for the document ID. The real URL would be this: index.aspx?documentId=612

Unfortunately, when I deployed this to our staging server, the ReturnUrl isn't the rewritten URL, it's the original URL. This causes all sorts of problems.

The staging server is also IIS 7 with the URL Rewrite Module 2.0 installed. It's Windows 2008 server SP2. Both are running ASP.NET 3.5.

My only guess is that the machine.config file orders the default httpModules differently, and the .NET forms authentication module is jumping in before the URL has been rewritten.

I'll review that soon, but in the meantime, what is experience with this problem and can it be solved?

Update

I also tried changing

Response.StatusCode = 401; 

to

FormsAuthentication.RedirectToLoginPage();

Which gets me a bit ahead开发者_开发技巧, but still directs the user back to the URL that hasn't been rewritten.

I can also do this instead of setting the 401:

string currentPage = HttpUtility.UrlEncode(Request.RawUrl);
string loginUrl = FormsAuthentication.LoginUrl + "?ReturnUrl=" + currentPage;
Response.Redirect(loginUrl);

But this seems ugly.


In chapter 2 of the book Developing More=Secure Microsoft ASP.NET 2.0 Applications by Dominick Baier there is a ShowPipeline.ashx which shows the complete pipeline ordering on the server using an HttpHandler:

    <%@ WebHandler Class='ShowPipeline' Language='c#' %>

    using System;
    using System.Web;
    using System.Reflection;
    using System.ComponentModel;

    // shows which modules have registered for which event
    // add a ?asm=true query string parameter to also show the assemblies
    public class ShowPipeline : IHttpHandler

    {
        static bool _showAssemblies = false;

        // names of the pipeline events
    static string[] _handlerNames = {
        "BeginRequest",
        "AuthenticateRequest",
        "DefaultAuthentication",
        "PostAuthenticateRequest",
        "AuthorizeRequest",
        "PostAuthorizeRequest",
        "ResolveRequestCache",
        "PostResolveRequestCache",
        "AcquireRequestState",
        "PostAcquireRequestState",
        "PreRequestHandlerExecute",
        "PostRequestHandlerExecute",
        "ReleaseRequestState",
        "UpdateRequestCache",
        "PostUpdateRequestCache",
        "EndRequest"
    };

    public void ProcessRequest(HttpContext ctx)
    {
        if (ctx.Request.QueryString["asm"] == "true")
            _showAssemblies = true;

        ctx.Response.Write("<hr>");

        foreach (string s in _handlerNames)
        {
            _showHandlers(s);
        }

        ctx.Response.Write("<hr>");
    }

    public void _showHandlers(string handlerName)
    {
        HttpResponse r = HttpContext.Current.Response;
        object key = _getPrivateAppField("Event" + handlerName);
        EventHandlerList ehl = (EventHandlerList)_getPrivateAppField("_events");
        MulticastDelegate md = (MulticastDelegate)ehl[key];
        if (null != md)
        {
            r.Output.WriteLine("<h2>{0}</h2>", handlerName);
            foreach (Delegate d in md.GetInvocationList())
            {
                Type tt = d.Target.GetType();
                string asm = "";
                if (_showAssemblies)
                {
                    asm = string.Format("<font color='red'>[{0}]</font>", tt.Assembly.GetName());
                }
                r.Output.WriteLine("{0}{1}.<font color='blue'>{2}</font><br>", asm, tt, d.Method.Name);
            }
        }
    }
    object _getPrivateAppField(string fieldName)
    {
        return _getPrivateField(typeof(HttpApplication), fieldName, HttpContext.Current.ApplicationInstance);
    }

    object _getPrivateField(Type t, string fieldName, object o)
    {
        return t.GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic).GetValue(o);
    }

    object _getPrivateField(string fieldName, object o)
    {
        return o.GetType().GetField(fieldName, BindingFlags.Instance | BindingFlags.Static | BindingFlags.NonPublic).GetValue(o);
    }

    public bool IsReusable { get { return true; } }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜