George Kosmidis

Microsoft MVP | Speaks of Azure, AI & .NET | Founder of Munich .NET
Building tomorrow @
slalom
slalom

ASP.NET MVC 5: Custom AuthorizeAttribute for custom authentication

by George Kosmidis / Published 10 years and 5 months ago, modified 3 years ago

In a previous post I wrote about how you can should protect your web app from human errors by enforcing authentication by default.

In this, lets check how to write your very own custom AuthorizeAttribute!

Since adding the AuthorizeAttribute to every action involves global filters, we can use that to add our own custom authentication, by inheriting AuthorizeAttributeand overriding the AuthorizeCore and HandleUnauthorizeRequest methods.

We ‘ll start by adding a new .cs file (I also add a folder Attributes for all custom attributes) with the following code (read the comments for explanation):

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Web.Mvc;
using System.Web.Routing;

namespace MyNewProject.Attributes {

    [AttributeUsageAttribute( AttributeTargets.Class | AttributeTargets.Method, Inherited = true, AllowMultiple = true )]
    public class MyAuthorizeAttribute : AuthorizeAttribute {
        
        //Custom named parameters for annotation
        public string ResourceKey { get; set; }
        public string OperationKey { get; set; }

        //Called when access is denied
        protected override void HandleUnauthorizedRequest( AuthorizationContext filterContext ) {
            //User isn't logged in
            if ( !filterContext.HttpContext.User.Identity.IsAuthenticated ) {
                filterContext.Result = new RedirectToRouteResult(
                        new RouteValueDictionary( new { controller = "Account", action = "Login" } )
                );
            }
            //User is logged in but has no access
            else {
                filterContext.Result = new RedirectToRouteResult(
                        new RouteValueDictionary( new { controller = "Account", action = "NotAuthorized" } )
                );
            }
        }

        //Core authentication, called before each action
        protected override bool AuthorizeCore( HttpContextBase httpContext ) {
            var b = myMembership.Instance.Member().IsLoggedIn;
            //Is user logged in?
            if ( b )
                //If user is logged in and we need a custom check:
                if ( ResourceKey != null && OperationKey != null )
                    return ecMembership.Instance.Member().ActivePermissions.Where( x => x.operation == OperationKey && x.resource == ResourceKey ).Count() > 0;
            //Returns true or false, meaning allow or deny. False will call HandleUnauthorizedRequest above
            return b;
        }
    }
}

And then you can just use it from your controller like this:

  //No Annotation, user must be logged in
  public ActionResult DoSomething( [DataSourceRequest]DataSourceRequest request ) 

  //Custom authentication request
  [myAuthorizeAttribute(ResourceKey="SomeResource",OperationKey="SomeAction")]
  public ActionResult DoSomething( [DataSourceRequest]DataSourceRequest request ) 

  //No Authentication at all
  [AllowAnonymous]
  public ActionResult DoSomething( [DataSourceRequest]DataSourceRequest request ) 

* You should also read “ASP.NET MVC 5: “Authorization” by default for your web app” to understand the commend //No Annotation, user must be logged in!

This page is open source. Noticed a typo? Or something unclear?
Edit Page Create Issue Discuss
Microsoft MVP - George Kosmidis
Azure Architecture Icons - SVGs, PNGs and draw.io libraries