Overriding AuthorizeAttribute in MVC 4

2019-01-22 21:42发布

问题:

In my application, I want to redirect the authorized user to update their profile page until they have provided required information. If they update profile, then the IsProfileCompleted is set to 'true' in the database.

So, I knows that this can be done by putting check condition in required action of controller. But I want to do this by customizing the AuthorizeAttribute.

I Googled and 'StackOverflowed' for information, but got confused. Please guide me.

回答1:

public class MyAuthorizeAttribute: AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized)
        {
            // The user is not authorized => no need to go any further
            return false;
        }

        // We have an authenticated user, let's get his username
        string authenticatedUser = httpContext.User.Identity.Name;

        // and check if he has completed his profile
        if (!this.IsProfileCompleted(authenticatedUser))
        {
            // we store some key into the current HttpContext so that 
            // the HandleUnauthorizedRequest method would know whether it
            // should redirect to the Login or CompleteProfile page
            httpContext.Items["redirectToCompleteProfile"] = true;
            return false;
        }

        return true;
    }

    protected override void HandleUnauthorizedRequest(AuthorizationContext filterContext)
    {
        if (filterContext.HttpContext.Items.Contains("redirectToCompleteProfile"))
        {
            var routeValues = new RouteValueDictionary(new
            {
                controller = "someController",
                action = "someAction",
            });
            filterContext.Result = new RedirectToRouteResult(routeValues);
        }
        else
        {
            base.HandleUnauthorizedRequest(filterContext);
        }
    }

    private bool IsProfileCompleted(string user)
    {
        // You know what to do here => go hit your database to verify if the
        // current user has already completed his profile by checking
        // the corresponding field
        throw new NotImplementedException();
    }
}

and then you could decorate your controller actions with this custom attribute:

[MyAuthorize]
public ActionResult FooBar()
{
    ...
}


回答2:

I've taken this code and added some of my own changes, namely to check if the currently logged in user has a session state on the server, they're not as expensive as they used to be!

public class CustomAuthorizeAttribute : AuthorizeAttribute
{
    protected override bool AuthorizeCore(HttpContextBase httpContext)
    {
        var authorized = base.AuthorizeCore(httpContext);
        if (!authorized && !Membership.isAuthenticated())
        {
            // The user is not authorized => no need to go any further
            return false;
        }

        return true;
    }
}
public class Membership
{
    public static SystemUserDTO GetCurrentUser()
    {
        // create a system user instance
        SystemUserDTO user = null;

        try
        {
            user = (SystemUserDTO)HttpContext.Current.Session["CurrentUser"];
        }
        catch (Exception ex)
        {
            // stores message into an event log
            Utilities.Log(ex.Message, System.Diagnostics.EventLogEntryType.Warning);

        }
        return user;
    }

    public static bool isAuthenticated()
    {
        bool loggedIn = HttpContext.Current.User.Identity.IsAuthenticated;
        bool hasSession = (GetCurrentUser() != null);
        return (loggedIn && hasSession);
    }
}