Click here to Skip to main content
13,863,642 members
Click here to Skip to main content
Add your own
alternative version

Stats

3.4K views
8 bookmarked
Posted 3 Feb 2019
Licenced CPOL

Typed claims in ASP.Net Core 2.1

, 3 Feb 2019
Rate this:
Please Sign up or sign in to vote.
Hello and Welcome 🙂 Today I want to discuss about how we can use claims following a typed approach, this topic came about from a bug that was encountered during a code review for an application.

Hello and Welcome 🙂

Today I want to discuss about how we can use claims following a typed approach, this topic came about from a bug that was encountered during a code review for an application.

As such I wanted to find a way of mitigating such issues in the future by using concrete classes and the rarely used functionalities of implicit casting.

But first off, let’s look at what Claims are and how they are used.

The github repository for the examples in this post can be found here.

Table of contents:

What are claims?

If we look at the common definition for a claim in the context of authorization or identity, then a claim is a statement that about a user or a role that is made by an application.

The common example for a claim, as seen in the wikipedia article, states that you can imagine your system as being a night club bouncer, and your user has a driver license, which has been released by an authorized third party, that driver states a few claims about our user such as their date of birth, which then the bouncer can verify that their date of birth meets the criteria (be over 18 years old) and that the license has been emitted by the authorizing party.

Based on the analogy previously described, a claim can be issued by other trusted systems, and they serve as meta-data for a specific user, or in some cases for a specific role. This makes claims a lot more composable than a user just having roles to describe their permissions than just using role-based approaches.

In short, a claim is a piece of meta-data or attributes of a user that claims something about the user and that claim is issued by some party, it’s up to the system to determine if that party is trusted or not.

How to create claims in ASP.Net Core 2.1

Now we’re going to look at how to manipulate claims for both users and roles.

If you’re building an ASP.Net Core application then you most likely will be using the Identity services provided by the library, which is a wrapper that adds several classes to the dependency injection container (Service provider). The class we are most interested in is UserManager<T>. Where T represents our user entity type respectively.

For us to use the UserManager we will need to inject into the classes we want to use them into (several topics on this subject can be found in previous posts). Once we have our instance of the UserManager we can manipulate the claims by adding, removing, replacing claims as per documentation.

To create a claim we will need to create an instance new Claim("ClaimType", "ClaimValue"). Afterward using this instance we can add it to users, or update existing claims.

More information about all the constructor overloads for claims can be found here. But as we can see the claim type and the claim values are string based, which brings us to our current topic.

Our custom claim

So for this example, I created a class called UserCurrentDateTimeClaim that would represent a concrete claim I want to work within the example application. The class definition is as follows:

using System;

namespace TypedClaims.Controllers
{
    class UserCurrentDateTimeClaim
    {
        private readonly DateTime _dateTimeValue;

        public UserCurrentDateTimeClaim(DateTime dateTimeValue)
        {
            _dateTimeValue = dateTimeValue;
        }
    }
}

The point to illustrate here is the fact that our custom claim can only receive a DateTime instance, of course we could create claims as complex or as simple as required.

Now we need to have this class be able to pass off as a claim so that we can add it to a user without creating adaptors and other complex conversion mechanisms. So we will add an additional method that will implicitly cast out custom claim to a system claim.

using System;
using System.Security.Claims;

namespace TypedClaims.Controllers
{
    class UserCurrentDateTimeClaim
    {
        private readonly DateTime _dateTimeValue;

        public UserCurrentDateTimeClaim(DateTime dateTimeValue)
        {
            _dateTimeValue = dateTimeValue;
        }

        public static implicit operator Claim(UserCurrentDateTimeClaim userCurrentDateTimeClaim)
        {
            return new Claim(nameof(UserCurrentDateTimeClaim), userCurrentDateTimeClaim._dateTimeValue.ToString());
        }
    }
}

The implicit operator will let our system know how to convert our custom class into a Claim type. So now we can add this claim to a user like this await userManager.AddClaimAsync(currentUser, new UserCurrentDateTimeClaim(DateTime.Now));.

The benefit of this approach is that we have a consistent way of adding a specific claim to a user that will respect the type of the data we want to store, the name of the ClaimType and any other additional claim information we’re interested in like issuers.

Of course if our claim has a bit more validation logic in it, or methods that work with the underlying stored type, we might also want to convert it back from a claim to out custom type, so we will add another conversion method that will the the reverse.

using System;
using System.Security.Claims;

namespace TypedClaims.Controllers
{
    class UserCurrentDateTimeClaim
    {
        private readonly DateTime _dateTimeValue;

        public UserCurrentDateTimeClaim(DateTime dateTimeValue)
        {
            _dateTimeValue = dateTimeValue;
        }

        public static implicit operator Claim(UserCurrentDateTimeClaim userCurrentDateTimeClaim)
        {
            return new Claim(nameof(UserCurrentDateTimeClaim), userCurrentDateTimeClaim._dateTimeValue.ToString());
        }

        public static implicit operator UserCurrentDateTimeClaim(Claim claim)
        {
            return new UserCurrentDateTimeClaim(DateTime.Parse(claim.Value));
        }
    }
}

This way, once we have the claim we’re looking for (and we will see an example of that) we can convert it back to our own custom type and act upon it.

Example

With the custom claim class wrote before, I created a Post action in the example application that makes use of out custom claim.

public async Task AddUpdateDateClaim([FromServices]UserManager userManager)
        {
            var currentUser = await userManager.GetUserAsync(HttpContext.User);
            //tried it and we cannot convert directly into our own type on this line so first we need to retrieve the stored claim then switch it to our own implementation
            Claim updatedClaim = (await userManager.GetClaimsAsync(currentUser)).FirstOrDefault(claim => claim.Type == nameof(UserCurrentDateTimeClaim)); 
            if (updatedClaim is null)
            {
                await userManager.AddClaimAsync(currentUser, new UserCurrentDateTimeClaim(DateTime.Now));
            }
            else
            {
                UserCurrentDateTimeClaim exampleOfConvertingToCustomType = updatedClaim; // here we have the stored claim converted back to our own type
                await userManager.ReplaceClaimAsync(currentUser, exampleOfConvertingToCustomType,
                    new UserCurrentDateTimeClaim(DateTime.Now));
            }
            return RedirectToAction("Index");
        }

Conclusion

I hope you enjoyed my approach to using typed claims for eliminating the issues created by having claims stored as strings both for type and value.

With this approach you could even save object in JSON or binary format and just serialize and deserialize them, and as long as the system is configured properly (thinking of json serialization options) and the stored value has not been tampered by other means, then you should have a consistent way of switching to and from your own claim classes.

As stated at the start, the

Thank you and see you next time 😀


License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

Share

About the Author

Vlad Neculai Vizitiu
Software Developer
Romania Romania
When asked, I always see myself as a .Net Developer because of my affinity for the Microsoft platform, though I do pride myself by constantly learning new languages, paradigms, methodologies, and topics. I try to learn as much as I can from a wide breadth of topics from automation to mobile platforms, from gaming technologies to application security.

If there is one thing I wish to impart, that that is this "Always respect your craft, your tests and your QA"

You may also be interested in...

Comments and Discussions

 
-- There are no messages in this forum --
Permalink | Advertise | Privacy | Cookies | Terms of Use | Mobile
Web02 | 2.8.190214.1 | Last Updated 3 Feb 2019
Article Copyright 2019 by Vlad Neculai Vizitiu
Everything else Copyright © CodeProject, 1999-2019
Layout: fixed | fluid