Creating a Basic Authorization Pipeline with MediatR and ASP.NET Core

Austin Davies
4 min readJan 20, 2020

--

I must admit that I see a lot of discussion about this topic around the usual places of the internet that developers look to for help. Here is the problem that I see. I can’t freakin’ copy and paste any implementations — these people are literally trying to make me do work here.

Photo by JJ Ying on Unsplash

Get your Fingers Ready

Lets start by defining a basic interface that our pipeline will utilize.

I’m going to name this interface “IAuthorizer” and this interface really is the star of the show here. This interface will not only be used by our pipeline but will also be used later on when we setup dependency injection for our implementations.

Next is the “AuthorizationResult” which is the concrete type that is returned from the “IAuthorizer.AuthorizeAsync” method. This result contains just bare-bones information like whether the authorization check failed or succeeded and why it failed, that is, if the check failed in the first place. As well as a couple convenient factory methods to ease construction of this class.

Finally, before we can implement our MediatR behavior, we need a custom exception type that will better serve our outer layers. Don’t worry if you don’t know what I mean by this; I will cover this later on in this article.

Pretty simple so far, eh? Prepare yourself…

Next in line we have the pipeline behavior itself. This thing is actually pretty simple in nature; don’t let the generic arguments fool or scare you. This behavior will be provided — through dependency injection — an IEnumerable of IAuthorizer<TRequest> where TRequest is a non-abstract class that implements MediatR’s IRequest<> generic interface type.

Let’s unpack this a bit. Since we constrain TRequest to be of type MediatR.IRequest<TResponse> we ensure that we are working with a specific MediatR request object come time our behavior Handle() method is invoked. This opens us up to be as autonomous as possible with how our behavior runs.

Did I lose you? Let’s clear things up by checking out how we’ll register our dependencies with our dependency injection container.

You Know How to Whistle, Don’t You, Steve? You Just Put Your Lips Together and Blow.

Let’s start with the “Startup” class:

Pretty simple here except for the “AddAuthorizersFromAssembly()” method. Here is that extension method for you:

This extension method is doing the heavy lifting for us by automatically registering all our concrete types that implement our IAuthorizer<> type but only those that are contained inside a specific assembly. So you can replace that “SomeTypeInYourAssembly” in the Startup.cs class with a type that is actually contained in a project where all your Authorizers hopefully will reside. And without further ado, I leave you with bragging rights:

Time to Tie All This Whole Thing Together

This is where the magic happens. Let’s say I have a GetCourseVideosQuery class that implements MediatRs IRequest<> type:

Pretty standard MediatR stuff so far, eh? The premise of this request is that I want to get details about a specific video for a course. However, all that information is considered privileged and we only want users with a subscription to that course to have access to the information about the video.

With our authorization pipeline behavior setup and working, let’s create our first authorizer class. I will name mine “GetCourseVideoDetailAuthorizer”:

Here we just inject two dependencies: a DbContext, and an ICurrentUserService which holds information about the currently authenticated user. Now, come time the AuthorizeAsync() method is called, we simply attempt to find a subscription for the current user for the course id specified in the request. If we find one, we return a call to Succeed() from the factory method for our AuthorizationResult class. If we don’t find a record, then we return the Fail() call which will be picked up in our RequestAuthorizationBehavior pipeline and will stop execution by throwing our UnauthorizedException type.

One Last Thing

I will leave you with a tip here: In our “GetCourseVideoDetailAuthorizer” class we created logic inside the AuthorizeAsync method to check if the user was authorized or not. Obviously, this is not reusable. A better option in my opinion would be to leverage MediatR instead. You can create a RequestHandler named something like “MustHaveCourseSubscription” where the request takes in a CourseId and a UserId and the handler performs the same logic as in the example above. Then, our “GetCourseVideoDetailAuthorizer” then would just take in an IMediator dependency — instead of the DbContext and ICurrentUserServer — and simply create and send a new request with the aforementioned CourseId and UserId.

Wait, What about that Custom Exception Type?

That custom exception type we implemented earlier that I named “UnauthorizedException” will come in handy for you. You can setup a custom “ExceptionFilterAttribute” that overrides the “OnException” method and that is globally registered inside your startup class. The idea is that method will check the type of exception that is thrown from the context and if the aforementioned type is our custom “UnauthorizedException” type then you will set the response appropriately from there e.g., HTTP status code 401 etc… For more information on Filters look here: https://docs.microsoft.com/en-us/aspnet/core/mvc/controllers/filters?view=aspnetcore-3.1

Conclusion

I hope you enjoyed reading this post and it serves you well whether on the job or in your personal work.

Also, are you curious about that ICurrentUserService dependency? Follow me and keep a look out for my next post where I talk about that as well as the woes of Microsoft’s Authorization and how to properly handle authorization in a Clean Architecture setup.

— Hope you enjoyed this and see you next time!

--

--