Recently I was going through some controllers and noticed a lot of code that was reading claims from
ClaimsPrinciple. If you ever worked with claims in ASP.NET Core then code like
User.FindFirst(...) might be familiar. All that the method does is that it will find the first claim that matches the type you want. You might have also noticed that, if you wanted to unit test some method in the controller that uses claims, it actually requires a quite a few extra lines of code to achieve that. You have to create
Claims and then set everything on the
HttpContext of your
I stopped for a second and said to myself: "It would be nice if I could just get the required claim as a method parameter". And then I realized that it might not be that hard to actually achieve that! Let's see what we have to do to implement a custom
Representing our source of data for binding
We will start by creating a
BindingSource for our source of data. This is needed when we want to bind our claim to the parameter of our controller action method.
We will use the
BindingSource that we have created in the following steps.
Creating the value provider
The next very important step is to create the value provider. The value provider is the class where the actual claims will be read from the
ClaimsPricinpal. We will base our new
ClaimValueProvider on the
BindingSourceValueProvider since we want to bind our claims to parameters in our controller action methods.
ClaimValueProvider we will need a
BindingSource which will be the one we created for claims and a
ClaimsPrincipal from which we will read the required claim.
ContainsPrefix(...) method, we will check whether the required claim is available.
GetValue(...) method, we will return the first claim that matches the required claim type.
This is all we need to do in the value provider. As you can see, you can easily unit test this class, since it does only a couple of small things.
Creating the value provider factory
Now when we have implemented the
ClaimValueProvider, we will need something that will create it with correct
ClaimsPrincipal. This will be done by implementing a new
IValueProviderFactory which we will call
We will pass our claim-specific
BindingSource and also pass the
ClaimsPrincipal from the
HttpContext that is available in the
ValueProviderFactoryContext which we get.
Once you have your provider created, you have to also add it into the available value providers in the
The last step is to hook up our
ClaimValueProviderFactory into available value provider factories which ASP.NET Core uses. You can do that in the
AddControllers[WithViews](...) method in
The last but not the least, our custom
So far we have implemented all the logic that will extract the claim from the
ClaimsPrincipal and hooked up everything in ASP.NET Core. What is missing is our
[FromClaim] attribute itself.
Our attribute will implement two interfaces:
IBindingSourceMetadata- this will specify which binding source will be used for binding
IModelNameProvider- this will specify the model name, this is the
keythat we will get in the value provider as a parameter
We will also add a constructor which receives a claim type, so we have to specify the claim type when we use it in our controller action method, e.g.
Using our new attribute in controller action method
Now when we have everything implemented, we can easily use our new attribute in the controller action method.