Introduction
In this article we will look into ASP.NET Simple Membership Provider which comes as the default authentication and authorization mechanism with ASP.NET MVC 4 internet application
template. We will try to understand the simple membership provider and compare it with the ASP.NET roles and membership provider API.
Background
Let us start the discussion by looking at what authentication and authorization is. Authentication means validating users. In this step, we verify user credentials to check
whether the person tying to log in is the right one or not. Authorization on the other hand is keeping track of what the current user is allowed to see and what should be hidden
from him. It is more like keeping a register to what to show and what not to show to the user.
Whenever a user logs in, he will have to authenticate himself with his credentials. Once he is authenticated, he will be authorized to see resources/pages of the website.
Mostly these two concepts go together.
With the release of ASP.NET 2.0, came the Roles and membership APIs in ASP.NET framework
which provided all the required boilerplate code and database schema that is needed to address the issue of authentication and authorization. Implementing authentication and authorization
was just a matter of pluging in the ASP.NET membership API and the membership provider gave us the authentication and authorization functionality out of the box. To know more on this please refer: Understanding ASP.NET Roles and Membership - A Beginner's Tutorial[^]
In ASP.NET membership provider API
The information in the user and role table was predefined and it cannot be customized. User profile information is also stored in the same database. It was not very
easy and straight forward to take full control of the database using ASP.NET membership provider. and this some applications still found themselves a need to implement their
mechanism of authentication and authorization using their own database for tracking users and their roles.
Some reasons for having such a requirements could be:
-
We have an existing database and we are trying to implement an application using that.
-
The Roles and Membership functionality is overkill for our application.
-
The Roles and Membership functionality is not sufficient for our applications and we need custom data.
It was possible to using the custom authentication and authorization mechanism with ASP.NET. This technique was known as custom forms authentication mechanism.
To know more on custom forms authentication, please refer:
With ASP.NET MVC 4 the simple membership provider API has been provided by Microsoft. Compared to the ASP.NET membership provider, the major benefit of the simple membership API is more simple,
mature and relatively straight forward to take full control of. Another major benefit of the simple membership provider is that is persistence ignorant. Meaning it provides us
a set of models to work with to achieve the authentication and authorization and uses the code first approach. It is up to the application developers to decide where and how these models should
get persisted. (supported by Entity framework code first).
Using the code
Let us try to create a simple ASP.NET MVC4 internet application and observe the simple membership provider in action. When we create the ASP.NET MVC 4 internet application template,
the project structure will look like:
The template gives a Model for UserProfile
and a UsersContext
class to work with this model. (Models/AccountModels.cs)
public class UsersContext : DbContext
{
public UsersContext()
: base("DefaultConnection")
{
}
public DbSet<userprofile> UserProfiles { get; set; }
}
[Table("UserProfile")]
public class UserProfile
{
[Key]
[DatabaseGeneratedAttribute(DatabaseGeneratedOption.Identity)]
public int UserId { get; set; }
public string UserName { get; set; }
}
</userprofile>
This user model comes with only one field which is username but we can add any number of fields we want for the user profile in this model.
The next important thing is to look at the InitializeSimpleMembershipAttribute
attribute (Filters/InitializeSimpleMembershipAttribute.cs).
[AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = false, Inherited = true)]
public sealed class InitializeSimpleMembershipAttribute : ActionFilterAttribute
{
private static SimpleMembershipInitializer _initializer;
private static object _initializerLock = new object();
private static bool _isInitialized;
public override void OnActionExecuting(ActionExecutingContext filterContext)
{
LazyInitializer.EnsureInitialized(ref _initializer, ref _isInitialized, ref _initializerLock);
}
private class SimpleMembershipInitializer
{
public SimpleMembershipInitializer()
{
Database.SetInitializer<UsersContext>(null);
try
{
using (var context = new UsersContext())
{
if (!context.Database.Exists())
{
((IObjectContextAdapter)context).ObjectContext.CreateDatabase();
}
}
WebSecurity.InitializeDatabaseConnection("DefaultConnection", "UserProfile", "UserId", "UserName", autoCreateTables: true);
}
catch (Exception ex)
{
throw new InvalidOperationException("The ASP.NET Simple Membership database could not be initialized. For more information, please see http://go.microsoft.com/fwlink/?LinkId=256588", ex);
}
}
}
}
What this attribute does is that it takes care of initializing the simple membership provider, specify the context class that should be used to perform the DB operations
i.e. UsersContext. The WebSecurity.InitializeDatabaseConnection
method will be used to specify the database using the connection string("DefaultConnection"
in this case), the model
which should be used to take the user profile information("UserProfile
" in this case), the filed that should be used for login("UserName
" in this case).
Now what this attribute will do is that it will create the membership database in the location specified in the connection string. It will create the table for our UserProfile
model
with all the columns for the properties specified in our UserProfile
class. It will use the UserId
field to maintain the foreign key relationship with the auto generated tables. and will use
the UserName
field as the field required for login. It will then create some of the tables needed for the authentication and authorization.
The next thing to notice is the AccountController
. I will not be discussing the complete class here but this class contains all the CRUD operations on our user profile in such a way
that it is wrapped in form of "Register", "Login", "Manage" functions. The important thing to notice is the InitializeSimpleMembership
associated with the controller. So whenever user tries
to login/register, the simple membership will get initialize automatically.
[InitializeSimpleMembership]
public class AccountController : Controller
{
}
Also, this class contains some code for external login, I will explain that some time. First let us try to see the database created by the simple membership provider.
To see the tables, let us modify the connection string to point to the App_data
folder and create a sample database.
< add name="DefaultConnection" connectionString="data source=.\SQLEXPRESS;attachdbfilename=|DataDirectory|\sampleDb.mdf;integrated security=True;user instance=True;multipleactiveresultsets=True;" providerName="System.Data.SqlClient" />
Now let us run the application and click on "register". This will call the AccountController
, which will in turn call the InitializeSimpleMembership
constructor and will create the simple membership database
along with the UserProfile
table that we needed for our UserProfile
model. Lets look at the created tables now.
Now in this picture, we can see the UserProfile
table created for our model. The Simple membership provider created a table too.
-
webpages_Membership
: This table will keep track of the user's login credentials' hashes, salts and recovery information.
-
webpages_Roles
: This table will keep track of the all the roles in the system.
-
webpages_UserInRoles
: this table will maintain the many to many relationship between our user profile table and roles table.
-
webpages_OAuthMemebrship
: If any user chooses to use Open authentication then the application will not have any information on the login credentials but rather we only have the information about the open authentication provider and the user id. this table will keep track of the user using the open authentication to login to the application.
The default template also comes with the view that let us perform basic login, registration and user management. Now with this simple membership provider, if we need to
have custom fields in the user profile then is is just a matter of adding them in our user profile model. The authentication and authorization related tables are separate from the
user profile table.
The only limitation, compared to ASP.NET membership API is that we cannot user the WSAT
tool to work with the simple membership provider roles and user-roles functionality
but this can easily be done by creating a simple page to manage roles and user-role assignments.
Point of interest
The simple membership provider makes it easy to implement authentication and authorization for the applications who found themselves in the need to develop custom forms authentication.
This was more of a theoretical article but I am sure the the developers who are doing custom forms authentication will find simple membership provider very useful. I hope this has been informative.
History
-
29 November 2013: First version