Everything you need to know about MembershipProvider

by Pawel Bres

Members are crucial part of most of the websites nowadays. Everywhere where you need to give users of your website possibility to log in and store some personal information, membership enters the game.

Let's then take a closer look at Membership in Umbraco. Out of the box we got a great solution that would cover most of scenarios in web projects. There are custom member types with customizable properties and member groups, which can be used to set permissions at the node level. All of that is explained very well in the official Umbraco Members documentation by showing how to create and edit members in Backoffice.

Last year Lee wrote great article about "Dealing With Members Using The MemberService & MembershipHelper". It's a very good place to start your journey and get to know how to query, register and update members straight from the code using MemberService and MembershipHelper. But let's look a little bit deeper and check what's going on under the hood.

As you may already know, one of the greatest parts of Umbraco is the possibility to extend or replace almost all built-in features. One of them is the Membership Provider which we will going to explore today.

Below you can find small agenda of this post:

Simple Log in form

Extending default provider by Two-factor authentication

Replacing default MembershipProvider

Replacing default RoleProvider

Summary

Simple Log in form

Ok, so we have members created in Backoffice or in the code but it would be nice to let them actually log in and get access to "Members only area". To do this we need one surface controller and one view.

Now members can log in and log out from our website. That's cool but not cool enough to open champagne.Let's see what we can do to make it little bit more complicated :)

Extending default provider by Two-factor authentication

If you take a look at MemberController in Umbraco sources, you can find that during login process it's calling ValidateUser method of current MembershipProvider. This means if we create our MembershipProvider inherited from original one we can override the ValidateUser method and add some custom code there. Don't be scared, it's really simple and I hope the comments put some light there.

Ok, but let's just sum up what's going on above. We've overridden the ValidateUser method to hold Member validation until the correct PIN is provided. PIN is stored in Session object to keep this example simple. For the same reason, the generated PIN is outputted to UmbracoTraceLog instead of SMS, Email or any other way.

One final step to make it work is replacing MembersMembershipProvider by ExtendedMembershipProvider in web.config.

Now when you try to log in you will be asked for PIN number and you can find it in App_Data\Logs\UmbracoTraceLog.txt

PIN numer in UmbracoTraceLog

Voilà! We've just created (very simple) two-factor authentication.

Second step of Log in process

Replacing default MembershipProvider

This is not the only thing we can do with MembershipProvider in Umbraco. Sometimes there are situations where Members are stored in another table, database or even in some remote service. Even in scenarios like this we can still use Umbraco Backoffice to handle website members just by replacing MembershipProvider. Let's take a look. This time we need to create CustomMembershipProvider inherited straight from MembershipProvider class. Otherwise Umbraco will recognize it as extension to original provider and won't let you take total control over members.

public class CustomMembershipProvider : MembershipProvider
{
}

Custom Membership Provider definition

MembershipProvider is an abstract class so by itself it will force you to override a bunch of methods. We will focus only on those that let us display members in the member tree and pass the validation process.

Script for creating CustomMembers table as well as whole working example you can find in Github repo which will be listed at the end of this post.

Before all let's just make simple MembersRepository using PetaPoco to grab members from our custom table.

Pretty much code, but seriously nothing very complicated when you look at it closer. We are just using created MembersRepository to get members from database with different conditions. You can also see ValidateUser method there. Similar to previous example, this method will be hit every time member is trying to log in. Other point of interest could be ConvertToMembershipUser method which returns new instance of MembershipUser based on given CustomMember object.

To make it work, we need to just replace MembershipProvider declaration in web.config.

That's all, no need to make any changes in log in method or in backoffice views.

Table with Custom Members

Replacing default RoleProvider

Last topic I would like to address is RoleProvider. For now it's not possible to combine default Umbraco MembersRoleProvider with totally custom MembershipProvider, so we need to create also custom RoleProvider. But don't worry, it's very easy, as you will see, very flexible. Again, I won't list here all methods that needs to be overridden but only those that are crucial for this example.

It's very, very simple. Roles are defined by static strings array and we are using IsBackendDev and IsFrondendDev fields, that you may noticed before, to determine member roles. In your further experiments you can query another table in database or some external web service to get member roles but for now let's stay with static values.

Let's see what just happened. Now we have our new roles listed in Umbraco Backoffice under Member Groups node. Also Member roles are representing what we actually have in database.

See that in db and in Backoffice Marcin is marked as both Frontend and Backend dev.

Custom Roles

But it's not all. Also "Public access" option is working great with our new roles.

Custom Roles in Public Access management

Amazing, isn't it ?

Summary

With few simple steps (and lots of simple code :)) we manage to, firstly, extend default Umbraco MembershipProvider and next totally replace it with a custom one. It's not rocket science but I believe it can be useful for people looking for some extra Membership features. It also proves that Umbraco is very flexible and even when working with custom members data, it's still possible to take advantage of awesome Backoffice without creating custom sections.

Further steps? I encourage you to play a little bit with solution you can find on Github and finish unfinished methods for Creating and Updating Members and Roles. Together with exploring Umbraco sources it could be a great excercise for testing possibilities of our favourite CMS :)

If you have any questions please feel free to ask, I will be very happy to answer all of them.