Introduction
This tutorial aims to fill in the gap on how to use ASP.NET Identity using Azure Storage Table, which is a better option for many than using the default SQL Server LocalDB and EntityFramework.
Background
Using the Code
The downloadable project uses the Single Page Application template, and all these steps have been done. Prior to using it, the connection string for the AzureStore must be configured. I also deleted all the NuGet packages so that the size of the file was below 10MB, Visual Studio should restore them upon building the solution.
- Create a ASP.NET (4.5 or greater tested) Web Application, and use the MVC, Web API or Single Page Application template, leaving the default Individual User Accounts authentication.
- From NuGet:
- Install the package
WindowsAzure.Storage
- Delete these packages:
Microsoft.AspNet.Identity.EntityFramework
EntityFramework
- [Optional] In the Package Manager Console, run
Update-Package
so that everything is updated
- In the Models folder, create a class that will match your Azure Storage Table user data - here named
AzureTableUser
- The class must inherit from
TableEntity
and from IUser
.
- Implement the
IUser
interface (using Right-Click > Implement Interface)
- In my case, the ID variable is not used, so I made it return the
UserName
- I made the
UserName
variable an auto-implemented property as that is enough in my case
- Add these properties:
public string Password { get; set; }
public string Email { get; set; }
public int FailedLogIns { get; set; }
public DateTimeOffset LockOutEndDate { get; set; }
- If you are going to use
Roles
, add public IList<string> Roles { get; set; }
- If you are going to use
Claims
, add public IList<string> Claims { get; set; }
- In the helpers folder, create a class that will work with your Storage Table - here named
AzureStore
- Add the
using
statement for your Model namespace if needed
- The class must inherit from at least 4 of the interfaces in the
Microsoft.AspNet.Identity
namespace, these are:
IUserStore<
AzureTableUser>
IUserPasswordStore<AzureTableUser>
IUserLockoutStore<AzureTableUser, TKey>
IUserTwoFactorStore<AzureTableUser, TKey>
- I used
string
as the TKey
for the Lockout
and TwoFactor
stores as that allows to implement the GetUserById
/GetUserByName
using a string
- Implement all the interfaces. I recommend separating the implementations using
#region
directives.
- Add a
private readonly
CloudTable cloudTable
field that will take care of executing the commands on your Storage Table.
- Create a constructor, and do the following to get the reference to the table:
StorageUri storageUri = new StorageUri(new Uri("https://yourstorageaccountname.table.core.windows.net/"));
CloudStorageAccount csa = CloudStorageAccount.Parse("connectionString");
cloudTable =
csa.CreateClouldTableClient().GetTableReference("yourTableName");
- Open the main Web.config file, and delete the
EntityFramework
sections.
- Open
Startup.Auth
(from App_Start
)
- Remove unnecessary
using
directives
- Under
ConfigureAuth
, remove the first CreatePerOwinContext
call, since we will not use the database that was created as part of the template
- Comment the lines that assign
OnValidateIdentity
in the new CookieAuthenticationOptions
- this doesn't work unless implemented in AzureTableUser
- From the Models folder, delete the file IdentityModels.cs since it won't be used
- Open
IdentityConfig
(from App_Start
)
- Remove unnecessary
using
directives
- Unless you will implement custom Email and/or SMS Two-Factor Authentication, delete the classes
EmailService
and SmsService
- Also delete the calls to new
EmailService
and new SmsService
in the create
function of the ApplicationUserManager
class
- For each call to the default
ApplicationUser
class, change it to AzureTableUser
- In the call to new
ApplicationuserManager
under Create
, pass as parameter a new instance of the AzureStore
class created in step 7
- In the
ApplicationSignInManager
class, delete the override to CreateUserIdentityAsync
- Open the
AccountController
- Change the calls to the default
ApplicationUser
to AzureTableUser
- Remove the calls that assign Hometown to the class above, unless you implemented it
- Open the
ManageController
- Change the calls to
user.PasswordHash
for user.Password
- If you implemented a phone number property in the AzureTableUser class, change the call to
user.PhoneNumber
to that property.
- Otherwise, delete all the views and methods related to the phone number.
- Open the
MeController
- Remove unnecessary
using
directives
- Remove the call to
user.Hometown
in the Get
method unless you implemented it
Points of Interest
While doing this for the first time, I found out that creating the AzureStore
class can be quite challenging. Even if you are not going to lock out accounts or use Two-Factor Authentication, the store must implement those interfaces and cannot throw an exception, so at least a dummy/hard-coded implementation must be done.
History