views:

38

answers:

2

I have an MVC 2 application that every page requires authorization on (except currently for /Account/Logon), but I would prefer that instead of it forwarding to "/Account/LogOn?ReturnUrl=/SomePage" to authenticate the user, that it would just show the login form instead on the page the user requested so the URL doesn't change

I already have a BaseController that almost every other controller inherits that I use for other purposes where I am already putting my AuthorizeAttribute (changed for brevity):

[Authorize(Roles = "Role1, Role2")]
public class BaseController : Controller
{

}

My initial thought for a slick solution would be to override the AuthorizeAttribute class in a fashion that would look something like this:

public class AuthorizeWithLoginAttribute : AuthorizeAttribute
{
    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        //This doesn't work obviously
        filterContext.Result = View("Logon");
    }
}

Then I could simply change my above controller to:

[AuthorizeWithLogin(Roles = "Role1, Role2")]
public class BaseController : Controller
{

}

Is there a way to actually make this work? (This is my first post fyi)

A: 

Could you do something in a base controller like

if(!User.Identity.IsInRole("Role1", "Role2")
{ 
    return View("Logon")
}
return;
Simon Hazelton
Well that totally works for half the battle! That's was deadly obvious, thank you. However now I have to figure out how to handle the form post from that page. I'll update again in a little bit after I experiment some
Chris
Chris
A: 

I'm not sure if I am supposed to answer my own question, but I wanted to post the solution that Simon Hazelton inspired.

My BaseController Class (Modified again for Brevity):

[Authorize(Roles = "Role1, Role2")]
public class BaseController : Controller
{
    protected override void OnAuthorization(AuthorizationContext filterContext)
    {
        if (!User.IsInRole("Role1") && !User.IsInRole("Role2"))
        {
            filterContext.Result = View("LogonView");
        }

        base.OnAuthorization(filterContext);
    }
}

And the form in the view /Views/Shared/LogonView.aspx:
(this is copied from the default /Views/Accounts/LogOn.aspx, with the Html.BeingForm() modified)

<% using (Html.BeginForm(new { action = "LogOn", controller = "Account", area = "", returnUrl = Request.Url.PathAndQuery }))
    <%: Html.ValidationSummary(true, "Login was unsuccessful. Please correct the errors and try again.") %>
    <div>
        <fieldset>
            <legend>Account Information</legend>

            <div class="editor-label">
                <%: Html.LabelFor(m => m.UserName) %>
            </div>
            <div class="editor-field">
                <%: Html.TextBoxFor(m => m.UserName) %>
                <%: Html.ValidationMessageFor(m => m.UserName) %>
            </div>

            <div class="editor-label">
                <%: Html.LabelFor(m => m.Password) %>
            </div>
            <div class="editor-field">
                <%: Html.PasswordFor(m => m.Password) %>
                <%: Html.ValidationMessageFor(m => m.Password) %>
            </div>

            <div class="editor-label">
                <%: Html.CheckBoxFor(m => m.RememberMe) %>
                <%: Html.LabelFor(m => m.RememberMe) %>
            </div>

            <p>
                <input type="submit" value="Log On" />
            </p>
        </fieldset>
    </div>
<% } %>

The only thing I would like it to do better is not do the original redirect situation upon unsuccessful login (since this is really just posting to the normal method)

Chris