4

In a migration from WebForms to MVC, some .aspx pages remain. Authentication for these is currently file-based and happens through Web.config. MVC authentication happens by adding an AuthorizeAttribute to GlobalFilters.Filters and to the controllers/actions as needed.

The Web.config authentication currently looks like this:

<authentication mode="Forms">
  <forms loginUrl="~/SignIn.aspx" protection="All" path="/" timeout="10080" />
</authentication>
<authorization>
  <deny users="?" />
  <allow users="*" />
</authorization>

<location path="SomePage.aspx">
<system.web>
  <authorization>
    <allow roles="Administrator, BasicUser" />
    <deny users="*" />
  </authorization>
</system.web>
</location>

I would however like to move the WebForms authentication away from Web.config and into an MVC filter that performs a check using a method call. I have been unable to find a single example of this. Is this even possible, and are there any undesired implications of doing it?

I am aware that .aspx files are not handled by the MVC hooks by default.

I am looking for a way to grab all .aspx files regardless of what their code-behind's base class is.

7
  • It depends what kind of authentication your web.config is performing. What ever it performs can be replicated in code within an AuthorizeAttribute. If you move to using ASP.NET Identity, you needn't worry about having to implement these attributes manually, just add the AuthorizeAttribute globally and go! Commented Oct 9, 2015 at 11:39
  • I've added the kind of authentication my Web.config is performing. My current MVC authentication is OWIN-based and I've adapted the old pages to use Claims rather than its existing Custom Principal/Identity. But there is no denial of access or redirection to login when accessing the .aspx pages directly. I'll look at the link you gave me, thanks. Commented Oct 9, 2015 at 12:02
  • If your authentication is OWIN based, then you're using ASP.NET Identity already by the sounds of it? Setting the redirect path is straightforward and if you add the attribute [Authorize] to an controller or action and the user is not logged in, it will redirect to the login path specified in your Startup Class LoginPath = new PathString("/Account/Login"), see this Commented Oct 9, 2015 at 12:09
  • I don't have "Microsoft ASP.NET Identity Owin" installed, only "Microsoft.Owin", "Microsoft.Owin.Security", "Microsoft.Owin.Security.Cookies" and "Microsoft.Owin.Host.SystemWeb". Question is: What code must I add where in order to automatically check for authentication on .aspx pages? For MVC, the trick was a GlobalFilter. The most relevant tutorial among the link collection you gave me was Adding ASP.NET Identity to an Empty or Existing Web Forms Project and it isn't auto. Commented Oct 9, 2015 at 12:15
  • Hmmm sorry if I'm side tracking a little bit, but if you're migrating from webforms to MVC why are you using .ASPX pages? MVC doesn't use .ASPX pages generally... it has .cshtml views and you apply authorisation to Controllers or Actions on the controllers. Commented Oct 9, 2015 at 12:16

1 Answer 1

1

In Global.asax.cs,

protected void Application_AuthenticateRequest(object sender, EventArgs e)
{
    // Since MVC does not handle authentication for .aspx pages, do this here.
    AuthController.AuthenticateAspxPage(this.Context);
}

and in AuthController, for some type UserRole,

public const string ErrorRedirectUrl = "~/Auth/Error";

private static readonly IDictionary<string, UserRole[]> _aspxAccessRoles =
    new Dictionary<string, UserRole[]>()
    {
        { "~/SomePage.aspx", new UserRole[] { UserRole.Administrator,
                                              UserRole.BasicUser } },
          ...
    };

and then,

[NonAction]
public static void AuthenticateAspxPage(HttpContext context)
{
    string ext = context.Request.CurrentExecutionFilePathExtension;
    string aspxPage = context.Request.AppRelativeCurrentExecutionFilePath;
    ClaimsPrincipal principal = context.User as ClaimsPrincipal;

    if ((ext == ".aspx" || ext == ".ashx") && !HasAspxAccess(aspxPage, principal))
    {
        context.Response.Redirect(ErrorRedirectUrl);
    }
}

[NonAction]
public static bool HasAspxAccess(string aspxPage, ClaimsPrincipal principal)
{
    if (principal == null || principal.Claims == null)
    {
        return false;
    }

    string[] userRoles = principal.Claims
        .Where(claim => claim.Type == ClaimTypes.Role)
        .Select(claim => claim.Value)
        .ToArray();

    UserRole[] accessRoles;

    return _aspxAccessRoles.TryGetValue(aspxPage, out accessRoles)
        && accessRoles.Any(role => userRoles.Contains(role.ToString()));
}
Sign up to request clarification or add additional context in comments.

3 Comments

Shouldn't unauthenticated requests rather throw 401 so that Forms module makes 302 out of it?
Yes, but I don't know how. It seems complicated.
Also, this is more like AuthorizeRequest than AuthenticateRequest. As for 401, just set the response status code. Forms module picks it up at the end of the req lifecycle and makes 302 to the login page.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.