This post is part of a series on ASP.NET Core 2.0 Authentication and I am going to talk about authorization policies, something different from what we’ve seen so far in the series, as most of posts are focusing in authorization.
I will show how to secure certain resources based on specific criteria on user’s claims.
Application is based on previous post, ASP.NET Core 2.0 Authentication with local logins – Implementing claims transformation, with a few additions.
This time, I am going to demonstrate how to enforce authorization policies on pages, on Razor MVC views, and finally mixing authorization policies in order to decide if user should have access to the resource or not.
Aside from the familiar home, login and profile pages, I have added a few more. Namely, I have added a page that has an age requirement, so in order to have access to this page, a user must be older than the minimum age requirement. This example, demonstrates simply how to utilize a single authorization policy and enforce it to a specific page.
To be able to demonstrate how to use authorization policies in a Razor MVC View, I have also added a new page, which is going to be visible in the navbar only when the user meets its requirements.
Finally, I have also added a couple more pages to support a more complex example of using and mixing authorization policies. If you are familiar with meetups, you already know that a meetup is a user group which contains various members and some of its members are special, as they are founders or co-founders of the group, meaning they spend time to organize talks, foods, events and many other stuff.
In order for someone to be able to have access to a meetup, he should be a member, like I mentioned earlier. If that user is not a member, then he is denied access to that meetup. To make it a little more complex, user should be rsvp’d for that meetup as well, in order to view the attendee list.
In this application, I have added a new page, which lists all meetups. If the user tries to access a meetup, the authorization policy will kick in, and based on user’s role and his rsvp status, it will either grant or deny access.
You can find the code outlined in this article on Github.
Authorization is a step that comes after authentication. I usually think about those terms in the following way:
- Authentication is the process that wants me to verify who I am.
- Who are you?
- Authorization is the process that wants me to verify if I am qualified to access a certain resource based on predefined policies.
- Are you allowed to perform this action?
Usually we perform authorization based on user’s claims. These claims might be in a cookie or in a JWT token or in a SAML token, it doesn’t really matter what the transport/store type is, all these have something in common and that is that they carry a specified amount of claims associated with a user.
Based on those claims now, we as developers, have the ability to create features which are very precise and solve much more complex authorization requirements. In ASP.NET Core, this ability is granted by authorization policies.
An authorization policy comprises of three components:
- The requirement
- The handler
- The configured policy
A requirement defines the business logic behind an authorization policy. It can be used by one or more policies and in reality it is just a plain class object which implements the empty
IAuthorizationRequirement interface. You can define your own parameters, properties and data for that requirement, which will be used directly by a handler.
A requirement can have multiple handlers.
A handler evaluates the requirement’s properties/business logic against its context to determine if access is allowed or not, so it can delegate the process to another handler or terminate it on the spot. You can use a handler to work with a specific requirement, and that handler should inherit from
AuthorizationHandler<TRequirement> abstract class. You’ll need to override the
HandleRequirementAsync method, which has the following definition:
Makes a decision if authorization is allowed based on a specific requirement.
From this we can understand that a handler plays a crucial role in deciding to provide access or not to a user. This method, except of the
AuthorizationHandlerContext context that is passed, it takes a generic
TRequirement, which is the requirement provided in the
AuthorizationHandler generic parameter.
A handler can have two states
success state means after validating against the requirement, user’s claims were valid, thus, access is granted, based on that policy. In order to fulfill a requirement, a simple call to the
AuthorizationHandlerContext.Succeed method must commence, passing the requirement as a parameter. More on this in code coming next.
failed state is more complicated. As mentioned earlier, a call to the
Succeed method is enough to fulfill a given requirement, but doing nothing essentially means the requirement failed. Though, if we look at the
Fail method exists. Well, even if it exists it should be used with caution and I will explain why shortly.
Imagine this, fairly often we have several handlers responsible to verify a requirement. As long as one of them calls the
Succeed method, access is approved.
But, if any of them fails, thus calling the
Fail method, access is denied, no matter how may of the other handlers succeeded. If nobody calls the
Succeed method, then the requirement is going to be fail, but this won’t stop the process from moving to the next handler for that requirement.
That said, we can understand that leaving out the call to the
Fail method, gives us the ability to introduce additional handlers in the future, without needing to alter any existing handler code.
Fail method should only be used if there is some form of absolute blocker that would render the rest of the handlers and essentially rest of the policy useless, so use this method with caution.
Configuring a policy
To setup an authorization policy, you just need to use the authorization middleware, which can be registered in the pipeline by the
AddAuthorization method in
ConfigureServices. You can register as many policies as you like, but remember to map them to the appropriate authentication scheme if needed.
If you have already set the
DefaultPolicy to have one default authentication scheme, then all the other policies will derive from it.
AddPolicy method to add new policies by name, which can be either delegates or classes (OOP approach).
Then you can use that name with the
Authorize attribute, for instance, to provide sophisticated security over a resource.
Let’s start off with the implementation, first we need to add the authorization middleware into the pipeline, so in
ConfigureServices call the
AddAuthorization method. I will provide the default authentication scheme to be used for all policies to be
This sets up a default authorization policy, which requires the user to be authenticated. The default authorization scheme for this policy and for the next to come is
"cookie", for cookie authorization.
I want to create a new page where people under 18 would be denied access. Let’s first create and secure this page. In HomeController I’m adding the following action.
I’ve decorated this action with the
Authorize attribute, defining a policy. Now, when a user navigates to
/protected route, authentication will kick in first, to determine if that user is indeed authenticated and if that is true, the authorization policy will run to determine if access should be granted. If user is denied access, the default access denied screen will show, else resource will be presented to the user.
Policies.AgeRestriction is just a constant with the value
Configuration is fetched from
appsettings.json file, following is some part of that config file
Now that we have everything in place, it’s time to add that policy to the list of authorization policies. To do that, I need to get back the
Startup.cs class to
AddAuthorization method we saw earlier, I will use the
AuthorizationOptions parameter to call the
AddPolicy method and register a new policy.
I mentioned earlier, that in order to make a new policy you need three things, a requirement, a handler and to configure the policy. I’ve done the latter, now I need the requirement and its handler.
I could do them separately, but I have the ability to combine them in one class, by inhering from
AuthorizationRequirement<TRequirement> and implementing the
That said, I created a single class and I named it
AgeRestrictionHandler, and got to inherit and implement from the aforementioned objects.
Based on the above, we have a handler that itself is the requirement, passing the actual requirement in the constructor, which is the minimum age.
HandleRequirementAsync, I am testing against that requirement, by first fetching the date of birth claim. Notice that if the
dateOfBirth is non-existent (
null), the method returns, which means the policy has failed, but this is a soft fail, compared to a hard by calling the
Fail method. If the test against the age is successful, then a call to the
Succeed method commences. Notice that you need to pass the requirement along with this method.
View based authorization
There are sometimes that you want to hide specific UI elements. You might want these elements to be visible to certain users, ones that have the appropriate claims or fulfill a certain authorization policy. Of course, this is not a way to secure an application, rather its a way to provide a better UX for your users.
In order to hide and show elements in Razor based on authorization policies, you need an instance of the
IAuthorizationService in your views. You can either inject that service in your view or inject it
_ViewImports.cshtml to make it globally accessible. In this demo, I’ve injected it in _ViewImports
Now, I want to show/hide a menu item in
_Layout.cshtml, based on a policy. I will use that IAuthorizationService and call its
AuthorizeAsync method. This will tell me if the authorization is successful or failed for that user. If it is successful, then I will be able to show the menu item, else it stays hidden.
Checks if a user meets a specific authorization policy against the specified resource.
Returns a flag indicating whether policy evaluation has succeeded or failed. This value is true when the user fulfills the policy, otherwise false.
This method is asynchronous, so be sure to
await it. The returned value is of type
AuthorizationResult, which has two public properties
- Succeeded, which is a
- Failure, which is of type AuthorizationFailure.
It requires a
ClaimsPrincipal user object and has various overloads for the rest of its parameters, though in my case, I prefer the overload that contains a policy name string as a third parameter. This overload validates the user against the specified policy.
Next step is to create that policy, so firstly, I will add that authorization policy in
Policies.DomainRestriction is a constant with a value of
I also fetch some configuration data from
Policies:Domains section in
This lists the allowed domains which are passed as constructor argument for the requirement.
Like in the previous example, I created a class which is both a handler and a requirement.
This requirement allows access only to users with email addresses which are in a specific domain, for example, this email address myemail@customDomain.com is not valid as the domain is not in the list of the allowed domains we saw earlier.
This handler succeeds only when user’s email address domain is listed in the allowed domains.
Complex authorization policies
Finally, I will talk about setting up complex authorization policies. You might want to use multiple handlers on a requirement, like in this example, I want to be able to allow or deny access to a user based on his role (Member, Founder, Co-founder) and his RSVP status. I would like to evaluate role requirements in an OR basis, whereas the RSVP status in an AND basis. If the user is not RSVP’ed, then the policy fails.
I’d like to start from setting the requirements first, then I will go to handlers and finally, I will show the configuration.
I start first by defining a
MeetupAccessRequirement, which is an empty marker class that implements the
IAuthorizationRequirement. Reason behind that is that I want to add a single requirement and have multiple handlers use that requirement, but I am not interested particularly in specific data or.
Now, I will create a handler for each role (Member, Founder, Co-founder), in order to have independent business logic for each one. That is the recommended best practice, it is better to have handlers that conform with the single responsibility principle, doing one thing, like in this case different handlers for each role and for RSVP status.
Then comes the handler for the founder
And finally, the handler for the co-founder role
All these are pretty much similar and simple handlers, they just verify if the user is in a role.
Next up, is the RSVP handler, which checks if a user is RSVP’ed to the meetup. This is a more complex handler.
I inject a service in this handler in order to be able to communicate with the data store.
HandleRequirementAsync method, that I cast the
Resource property of
AuthorizationHandlerContext to an
AuthorizationFilterContext. The MVC framework populates this property with an instance of
AuthorizationFilterContext, which automatically gives us access to all MVC items, like
It’s proven very useful for me, because I want the
id route data, which is the meetup Id.
In order to verify if the user is RSVP’ed, I call the
FindAttendeeInMeetupAsync, passing the meetup Id and user’s username. If user has indeed RSVP’ed, the policy is successful, otherwise, the policy fails hard, preventing further handlers from executing for this requirement.
For more info on services, repositories and database items, please look at the source code on Github.
Final piece in this puzzle, is the authorization policy configuration in
ConfigureServices. I have to add that requirement in authorization options, but I also have to register all the
Meetup* handlers in DI container, as an
Securing actions remains the same as with previous examples, just use the Authorize attribute and specify the policy name to match the one registered.
In this post, we’ve gone through authorization policies in ASP.NET Core. We’ve seen what a requirement is, the handler’s role and how to stitch them all together.
We’ve gone through some examples, starting from defining a simple requirement, to view based authorization and finally to applying complex authorization policies.
Next up, I will talk about social logins.
This post is part of the ASP.NET Core 2.0 Authentication series.
- ASP.NET Core 2.0 Cookie Authentication – Local logins
- ASP.NET Core 2.0 Authentication with local logins – Implementing claims transformation
- ASP.NET Core 2.0 Authentication with local logins – Responding to backend changes
- ASP.NET Core 2.0 Authentication with local logins – Implementing custom authorization policies
- ASP.NET Core 2.1 Authentication with social logins
- ASP.NET Core 2.0 Authentication with social logins – Implementing a profile store
- ASP.NET Core 2.0 Authentication with Azure Active Directory
- ASP.NET Core 2.0 Authentication with Azure Active Directory B2C
- ASP.NET Core 2.0 Authentication, IdentityServer4 and Angular