Quantcast
Channel: TYPE CAST EXCEPTION - ASP.Net
Viewing all 34 articles
Browse latest View live

ASP.NET MVC: Keep Private Settings Out of Source Control

$
0
0

Locked240It is just too easy to accidentally push confidential information up to a publicly hosted source repository such as Github. Also, when managing a project with multiple developers, it can become messy managing multiple configuration files between team members.

How often do you pull the latest changes down from source control, and then need to reset a database connection string after someone else accidentally pushed their own modified App.config or Web.config file up?

Even when the settings or connection strings are not critically private, this can be a pain.

Image by Rina Pitucci  |  Some Rights Reserved

Consider a typical Web.config file from an ASP.NET MVC web application (non-relevant content removed for clarity):

ASP.NET Web.config File Example:
<?xml version="1.0" encoding="utf-8"?>
<!--
  A bunch of ASP.NET MVC web config stuff goes here . . . 
  -->
<configuration>
<connectionStrings>
<addname="DefaultConnection"value="YourConnectionStringAndPassword"/>
</connectionStrings>
<appSettingsfile="PrivateSettings.config">
<addkey="owin:AppStartup"value="AspNetIdentity2ExtendingApplicationUser.Startup,AspNetIdentity2ExtendingApplicationUser"/>
<addkey="webpages:Version"value="3.0.0.0"/>
<addkey="webpages:Enabled"value="false"/>
<addkey="ClientValidationEnabled"value="true"/>
<addkey="UnobtrusiveJavaScriptEnabled"value="true"/>
<addkey="EMAIL_PASSWORD"value="YourEmailPassword"/>
</appSettings>
</configuration>

 

In the above, there is a database connection string we likely don't want to push to a public repo, and/or which may differ from developer to developer on a team, even internally if they are working against different or individual development versions of the application database.

Also, there is an email password, likely used to send email from within the application, which also may differ amongst team members during development, and which also should not be published publicly.

At the same time, there is a bunch of other stuff which is global to the application, so keeping the entire Web.config file out of source control is not an attractive option, either.

Fortunately, the .NET ConfigurationManager affords us a couple of handy ways to deal with this.

Use configSource Attribute to move an Entire Configuration Section to Its Own File

We can use the configSource attribute to move an entire Configuration Section to an external file. For example, database connection strings are one of the most common items we need to keep in our App.config or Web.config files, but which we also (usually) don't want to publish to a publicly hosted source control repository.

We can add a separate configuration file named (for example) connectionStrings.config, and then use the configSource attribute within our Web.config file to refer to it. To do so, add a new Web Configuration file, name it ConnectionStrings.config, and then put only the following in the new file (no xml header, nothing but the <connectionStrings> section tags, and the <add> element(s):

ConnectionStrings.config File Example:
<connectionStrings>
<addname="DefaultConnection"value="YourConnectionStringAndPassword"/>
</connectionStrings>

 

Then, we can modify our original Web.config file, removing the <add> element from the <connectionStrings> section, and instead, using the configSource attribute to refer to the new ConnectionStrings.config file:

Modified Web.config File Using configSource:
<connectionStringsconfigSource="ConnectionStrings.config">
</connectionStrings>

 

Now, we can still access our connection string the same as always:

Accessing Connection String By Name:
var conn = ConfigurationManager.ConnectionStrings["DefaultConnection"];
string connString = conn.ConnectionString;
// Etc...

 

In the above, accessing the connection string by name like that returns a ConnectionStringSettings object.

When we use the configSource attribute, the Configuration Section to which it is applied can contain no actual elements. The entire section will be referred to from the external file. Note that the configSource attribute can be used in this manner with any Configuration Section.

Use the File Attribute to Move Select Application Settings to an External File

You may have a case, such as our example We.config file above, in which most of the values in the <appSettings> Configuration Section are global to the project, but also include a handful of settings which should remain private, and kept out of source control.

In these cases, there is a special file attribute available specifically to the <appSettings> section which essentially allows us to extend <appSettings> to an external file. In other words, ConfigurationManager will recognize the contents in both locations when referring to <appSettings> and make all transparently available within the application.

In our example case, we have an email password we would like to keep private. We might add another Web Configuration file named PrivateSettings.config. Once again, there should be no XML header. The only thing this file should contain  will be a set of <appSettings> elements, and within those, the special settings we wish to define privately.

Special PrivateSettings.config File Extends AppSettings Section:
<appSettings>
<addkey="MAIL_PASSWORD"value="xspbqmurkjadteck"/>
</appSettings>

 

No, we remove the email password element from Web.config, and add the file attribute to the <appSettings> section element, pointing to the new PrivateSettings.config file:

Add File Attribute to Web.config AppSettings:
<appSettingsfile="PrivateSettings.config">
<addkey="owin:AppStartup"value="AspNetIdentity2ExtendingApplicationUser.Startup,AspNetIdentity2ExtendingApplicationUser"/>
<addkey="webpages:Version"value="3.0.0.0"/>
<addkey="webpages:Enabled"value="false"/>
<addkey="ClientValidationEnabled"value="true"/>
<addkey="UnobtrusiveJavaScriptEnabled"value="true"/>
</appSettings>

 

Again, as before we can access any of our settings in the standard manner - externalizing the email password setting to a separate file is transparent to client code:

Accessing Settings:
var pwd = ConfigurationManager.AppSettings["MAIL_PASSWORD"];

 

Add Special Files to .gitignore

Now we can add our Web.config file to source and commit, and add the two special files, ConnectionStrings.config and PrivateSettings.config to our .gitignore file, and commit away. When it's time to push to a shared repo, our private information will stay private.

Documentation is Key

Of course, when we take this type of approach, it will be helpful to other developers if our documentation clearly indicates what is going on here. We might do this in our project README file, and/or add some XML comments at each point in our modified Web.config informing others that they will need to add the proper files to their local version of the project, and what those files should contain.

Additional Resources and Items of Interest


ASP.NET MVC and Identity 2.0: Understanding the Basics

$
0
0

Kryha-crypto-machineOn March 20, 2014, the ASP.NET team released the RTM version 2.0 of the new Identity framework. The new release brings with it some long-awaited new features, and marks a substantial expansion of the security and authorization capabilities available to ASP.NET applications of all types.

The ASP.NET Identity framework was originally introduced in 2013 as the follow-on to the ASP.NET Membership system, a staple of MVC applications for several years, but which was beginning to show its age. Originally, ASP.NET Identity presented a useful, if somewhat minimal API for managing security and authorization in the context of a public-facing web application built using ASP.NET. The Identity framework introduced modern features such as social network log-in integration, and easily extensible user model definitions.

Image by Ryan Somma  |  Some Rights Reserved

The new RTM release introduces the following features, among others:

  • Extended User Account Definition, including Email and contact information
  • Two-Factor Authentication via email or SMS messaging, functionally similar to that used by Google, Microsoft, and others
  • Account Confirmation via email
  • Administrative management of Users and Roles
  • Account Lock-Out in response to invalid log-in attempts
  • Security Token Provider to regenerate a user's security token in response to changes in security settings.
  • Improved support for Social log-ins
  • Easy Integration of Claims-Based Authorization

Identity 2.0 represents a substantial revision from the original version introduced last year. With the numerous new features, comes some added complexity. If, like myself, you had just recently found your way through the first iteration of the Identity framework, be ready. While you won't be starting over from scratch with version 2.0, there is a lot to learn.

In this article, we're going to take a look around, get familiar with the major components of the system, and in general familiarize ourselves with the new features, and where they fit in the overall scheme of things. We won't go into too much detail yet. Think of this as a familiarization tour.

If you are looking for more detailed how-to's, I will be adding posts over the next few weeks examining specific implementation concerns here:

While we will be looking at a decent amount of code, it's not necessary yet to understand the details of what it all does - just get familiar with the general concepts, where the major components are located, and how things are structured.

Identity 2.0 Introduces Breaking Changes

Identity 2.0 does not slide smoothly into place for applications written using version 1. The additional capabilities appear to have required significant changes to the architecture, and the manner in which the Identity API is consumed from within the application. Upgrading an existing ASP.NET application from Identity 1.0 to the 2.0 version will require some new code, and is beyond the scope of this article. Be aware, though, that moving from Identity 1.0 to the 2.0 version is not a simple "plug-it-in-and-go" affair.

Getting Started - Get the Examples from Nuget

As of this writing, there is not a directly available ASP.NET MVC project template using Identity 2.0. In order to take Identity for a spin, you need to pull the example project libraries into an empty ASP.NET MVC project. First, Create a new ASP.NET project, and select the Empty Project template from the template options dialog:

Select the Empty ASP.NET Project Template:

select-empty-asp-net-project-template

Once you have create the new Empty project, you can get the Identity 2.0 sample project from Nuget by typing the following into the Package Manager Console:

Install the Sample Project from Nuget:
PM> Install-Package Microsoft.AspNet.Identity.Samples -Pre

 

Once Nuget has done its thing, you should see a folder structure in the Solutions Explorer that looks quite like a standard MVC project. Nuget has basically added everything needed to compose a complete ASP.NET MVC project, including Models, Views, Controllers, and various components required for this basic application to run.

While at first glance the project components look fairly similar, a closer look will reveal some significant changes, and some added complexity.

Identity 2.0 Configuration - Not So Simple Anymore

In my mind, one of the strengths of the original Identity framework was also its primary weakness (strange how THAT works in software, isn't it?). The simplicity of the Identity version 1.0 made it extraordinarily easy to use, and relatively intuitive to figure out. On the other hand, the utter simplicity also meant that the feature set available "out-of-the-box" was limited, and to some, insufficient.

Just to get an idea, we'll take a quick look at some of the configuration that runs when our application starts, and compare it to the comparable code in an application which used Identity Version 1.0.

In both flavors of project, we find a class file named Startup.cs at the root level of the project. In this file a class named Startup is defined, and makes a single call to the method ConfigureAuth(). What we DON'T see anywhere in this file is an actual method named ConfigureAuth(). This is because the rest of the code for the Startup class is defined in a partial class tucked away in the App_Start folder. The code file is named Startup.Auth.cs, but if we open that, we find a standard partial class definition, which contains the ConfigureAuth() method. In a project using the original version 1.0 of the Identity Framework, the standard code for ConfigureAuth() looks like this:

Standard ConfigureAuth() Method Using Identity 1.0:
public partial class Startup
{
publicvoid ConfigureAuth(IAppBuilder app)
    {
// Enable the application to use a cookie to 
// store information for the signed in user
        app.UseCookieAuthentication(new CookieAuthenticationOptions
        {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login")
        });
// Use a cookie to temporarily store information about a 
// user logging in with a third party login provider
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Uncomment the following lines to enable logging 
// in with third party login providers
//app.UseMicrosoftAccountAuthentication(
//    clientId: "",
//    clientSecret: "");
//app.UseTwitterAuthentication(
//   consumerKey: "",
//   consumerSecret: "");
//app.UseFacebookAuthentication(
//   appId: "",
//   appSecret: "");
//app.UseGoogleAuthentication();
    }
}

 

In the above, we see some boilerplate code for configuring cookies, and some commented out code which can be uncommented, and then called to enable third-party logins from various social media providers.

In contrast, when we look at the ConfigureAuth() method in our project using Identity 2.0, we see a bit more code has been added:

ConfigureAuth() Method from Project Using Identity 2.0:
public partial class Startup {
publicvoid ConfigureAuth(IAppBuilder app) {
// Configure the db context, user manager and role 
// manager to use a single instance per request
        app.CreatePerOwinContext(ApplicationDbContext.Create);
        app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
        app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
// Enable the application to use a cookie to store information for the 
// signed in user and to use a cookie to temporarily store information 
// about a user logging in with a third party login provider 
// Configure the sign in cookie
        app.UseCookieAuthentication(new CookieAuthenticationOptions {
            AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
            LoginPath = new PathString("/Account/Login"),
            Provider = new CookieAuthenticationProvider {
// Enables the application to validate the security stamp when the user 
// logs in. This is a security feature which is used when you 
// change a password or add an external login to your account.  
                OnValidateIdentity = SecurityStampValidator
                    .OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                    validateInterval: TimeSpan.FromMinutes(30),
                    regenerateIdentity: (manager, user) 
                    => user.GenerateUserIdentityAsync(manager))
            }
        });
        app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Enables the application to temporarily store user information when 
// they are verifying the second factor in the two-factor authentication process.
        app.UseTwoFactorSignInCookie(
            DefaultAuthenticationTypes.TwoFactorCookie, 
            TimeSpan.FromMinutes(5));
// Enables the application to remember the second login verification factor such 
// as phone or email. Once you check this option, your second step of 
// verification during the login process will be remembered on the device where 
// you logged in from. This is similar to the RememberMe option when you log in.
        app.UseTwoFactorRememberBrowserCookie(
            DefaultAuthenticationTypes.TwoFactorRememberBrowserCookie);
// Uncomment the following lines to enable logging in 
// with third party login providers
//app.UseMicrosoftAccountAuthentication(
//    clientId: "",
//    clientSecret: "");
//app.UseTwitterAuthentication(
//   consumerKey: "",
//   consumerSecret: "");
//app.UseFacebookAuthentication(
//   appId: "",
//   appSecret: "");
//app.UseGoogleAuthentication();
    }
}

 

Above, the first thing we notice are several calls to app.CreatePerOwinContext, wherein we register callbacks to be invoked to create instances of the type specified by the type arguments. Type instances created are then available using the context.Get() method.

What this tells us is that, at least for the purpose of the example project supplied by the Identity 2.0 team, Owin is now part of our application, and Identity 2.0 relies upon it to deliver the goods. I am not clear on whether Owin is REQUIRED in general for identity 2.0 to work, but for the purpose of our example project, it is.

We can also see some other new calls in the ConfigureAuth method body setting up Two-Factor Authentication, and some additional cookie authentication configuration code not present in the previous version. 

For our purposes here, we can assume that most of this stuff has been configured optimally for our basic use, and short of adding social media logins (which we're not going to look at in this article), we can leave this code alone. But bear in mind that this is where a lot of the Identity behavior in your application is set at runtime, based on the configuration components and helpers defined in another file in the App_Start folder, IdentityConfig.cs.

Before we go seeing what's up in IdentityConfig.cs, though, it will help us understand what's going on there is we first take a look at the ApplicationUser class, defined for us in the Models folder.

The New ApplicationUser Class in Identity 2.0

If you have built out an application using the previous version of Identity framework, you may have run into the situation where you found the core IdentityUser class rather limiting. Previously, Identity used a very simple IdentityUser implementation which represented a very minimal user profile:

The Original IdentityUser Class From Identity Version 1.0:
publicclass IdentityUser : IUser
{
public IdentityUser();
public IdentityUser(string userName);
publicvirtualstring Id { get; set; }
publicvirtualstring UserName { get; set; }
publicvirtual ICollection<IdentityUserRole> Roles { get; }
publicvirtual ICollection<IdentityUserClaim> Claims { get; }
publicvirtual ICollection<IdentityUserLogin> Logins { get; }
publicvirtualstring PasswordHash { get; set; }
publicvirtualstring SecurityStamp { get; set; }
}

 

Of the properties available in the above, only the first three, Id, UserName, and Roles were of much use from the business perspective of our application. The other items are mainly used by the security logic, which, while important, does not help us maintain useful information about users.

In a previous article, we examined how to extend Identity Accounts and implement Role-Based Authentication under Identity 1.0 to add more useful data, such as a user email address and/or other information which might be needed by our application.

With the advent of Identity 2.0, the need to create such work-arounds is diminished somewhat. While it is still possible to extend the Identity 2.0 ApplicationUser class in a similar manner, the Identity team has taken care of some of the more common use-cases for us.

What we find is that the example project already contains a subclass ApplicationUser, which is derived from a more complex default IdentityUser implementation.

We find the definition for ApplicationUser in the Models folder, in a file named IdentityModels.cs. We can see that the class definition itself is as simple as can be:

The ApplicationUser Class in Identity 2.0:
publicclass ApplicationUser : IdentityUser {
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        UserManager<ApplicationUser> manager) {
// Note the authenticationType must match the one 
// defined in CookieAuthenticationOptions.AuthenticationType
        var userIdentity = 
            await manager.CreateIdentityAsync(this, 
                DefaultAuthenticationTypes.ApplicationCookie);
// Add custom user claims here
return userIdentity;
    }
}

 

We see here that ApplicationUser is, as stated previously, a sub-class of IdentityUser. However, if we find the definition for IdentityUser (using VS Go to definition context menu item) we see that IdentityUser, as defined under the Identity 2.0 framework, is itself a sub-class of IdentityUser<TKey, TLogin, TRole, TClaim> . When we look at the definition of THAT, we find a significantly different animal from the version 1.0 implementation:

IdentityUser Implementation from Identity 2.0:
publicclass IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
    where TLogin : Microsoft.AspNet.Identity.EntityFramework.IdentityUserLogin<TKey>
    where TRole : Microsoft.AspNet.Identity.EntityFramework.IdentityUserRole<TKey>
    where TClaim : Microsoft.AspNet.Identity.EntityFramework.IdentityUserClaim<TKey>
{
public IdentityUser();
// Used to record failures for the purposes of lockout
publicvirtualint AccessFailedCount { get; set; }
// Navigation property for user claims
publicvirtual ICollection<TClaim> Claims { get; }
// Email
publicvirtualstring Email { get; set; }
// True if the email is confirmed, default is false
publicvirtualbool EmailConfirmed { get; set; }
// User ID (Primary Key)
publicvirtual TKey Id { get; set; }
// Is lockout enabled for this user
publicvirtualbool LockoutEnabled { get; set; }
// DateTime in UTC when lockout ends, any 
// time in the past is considered not locked out.
publicvirtual DateTime? LockoutEndDateUtc { get; set; }
// Navigation property for user logins
publicvirtual ICollection<TLogin> Logins { get; }
// The salted/hashed form of the user password
publicvirtualstring PasswordHash { get; set; }
// PhoneNumber for the user
publicvirtualstring PhoneNumber { get; set; }
// True if the phone number is confirmed, default is false
publicvirtualbool PhoneNumberConfirmed { get; set; }
// Navigation property for user roles
publicvirtual ICollection<TRole> Roles { get; }
// A random value that should change whenever a users 
// credentials have changed (password changed, login removed)
publicvirtualstring SecurityStamp { get; set; }
// Is two factor enabled for the user
publicvirtualbool TwoFactorEnabled { get; set; }
// User name
publicvirtualstring UserName { get; set; }
}

 

Note in the above, a whole lot of those properties are again related to authorization and security, and not to our business needs for user data. However, the Email and PhoneNumber fields definitely go a long way towards minimizing the need for additional customization of the ApplicationUser class.

But, what's with the weird generic type arguments in the class declaration?

The new version of IdentityUser implements generic type arguments to allow for additional flexibility. As an example, recall that in Identity Version 1.0, the Id property was a string. Here, the generic type argument TKey allows us to specify the type of the Id field. We can see in the above, the Id property declaration returns the type specified by TKey:

The Id Property Declaration:
publicvirtual TKey Id { get; set; }

 

Also of particular note, the Roles property, defined as follows:

The Roles Property:
publicvirtual ICollection<TRole> Roles { get; }

 

We can see the the Type TRole is left open at compile time, and in fact is specified in the generic declaration of the IdentityUser class. If we look at the type constraints in that declaration, we see the TRole is constrained to the type IdentityUserRole<TKey> which is not terribly different from the version 1.0 implementation. What IS different, and which represents a breaking change, is the definition of IdentityUserRole itself.

Previously, in version 1.0 of the Identity Framework, IdentityUserRole was defined as follows:

The IdentityUserRole Class from Identity 1.0:
publicclass IdentityUserRole 
{
public IdentityUserRole();
publicvirtual IdentityRole Role { get; set; }
publicvirtualstring RoleId { get; set; }
publicvirtual IdentityUser User { get; set; }
publicvirtualstring UserId { get; set; }
}

 

Compare with the Identity 2.0 Implementation:

The IdentityUserRole Class from Identity 2.0:
publicclass IdentityUserRole<TKey> 
{
public IdentityUserRole();
publicvirtual TKey RoleId { get; set; }
publicvirtual TKey UserId { get; set; }
}

 

See what happened there? The former contained references to an IdentityRole object, and an IdentityUser object. The version 2.0 implementation contains only Id values. If you had done any customization under the previous version, such as we discussed in Implementing Group-Based Permissions, this will break things.

We will take a closer look at the new flexibility created with the new, extended IdentityUser class in a subsequent post. For now, realize that while the basic user class definition has become more complex, it has also become significantly more flexible.

Since ApplicationUser sub-classes IdentityUser, all of the above properties are available to ApplicationUser, which is the basic implementation used in the example application.

Now that we have taken a quick look at the new ApplicationUser implementation, the configuration components and helpers we are about to look at will make more sense.

Identity 2.0 Configuration Components and Helpers

While the ConfigAuth() method of the Startup class is where the runtime configuration for Identity happens during startup, we actually use the components defined in the IdentityConfig.cs file to configure how most of the Identity 2.0 features behave in our application.

If we examine the content of the IdentityConfig.cs file, we find that there are a number of individual classes defined therein. We could split each one out into its own code file, but for now, we will just examine each class independently, despite the fact that they all share the same file location in our project. Not that all of these classes are enclosed in the ApplicationName.Models namespace.

Application User Manager and Application Role Manager

The first things we run into in the IdentityConfig.cs file are two helper classes, ApplicationUserManager and ApplicationRoleManager. Be ready - large blobs of code with generic types ahead!

The Identity 2.0 Application User Manager Class:
publicclass ApplicationUserManager : UserManager<ApplicationUser>
{
public ApplicationUserManager(IUserStore<ApplicationUser> store)
        : base(store)
    {
    }
publicstatic ApplicationUserManager Create(
        IdentityFactoryOptions<ApplicationUserManager> options, 
        IOwinContext context)
    {
        var manager = new ApplicationUserManager(
new UserStore<ApplicationUser>(
                context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
        manager.UserValidator = 
new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
// Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6, 
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
// Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application uses 
// Phone and Emails as a step of receiving a code for verifying 
// the user You can write your own provider and plug in here.
        manager.RegisterTwoFactorProvider("PhoneCode", 
new PhoneNumberTokenProvider<ApplicationUser>
        {
            MessageFormat = "Your security code is: {0}"
        });
        manager.RegisterTwoFactorProvider("EmailCode", 
new EmailTokenProvider<ApplicationUser>
        {
            Subject = "SecurityCode",
            BodyFormat = "Your security code is {0}"
        });
        manager.EmailService = new EmailService();
        manager.SmsService = new SmsService();
        var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = 
new DataProtectorTokenProvider<ApplicationUser>(
                    dataProtectionProvider.Create("ASP.NET Identity"));
        }
return manager;
    }
publicvirtual async Task<IdentityResult> AddUserToRolesAsync(
string userId, IList<string> roles)
    {
        var userRoleStore = (IUserRoleStore<ApplicationUser, string>)Store;
        var user = await FindByIdAsync(userId).ConfigureAwait(false);
if (user == null)
        {
thrownew InvalidOperationException("Invalid user Id");
        }
        var userRoles = await userRoleStore
            .GetRolesAsync(user)
            .ConfigureAwait(false);
// Add user to each role using UserRoleStore
foreach (var role in roles.Where(role => !userRoles.Contains(role)))
        {
            await userRoleStore.AddToRoleAsync(user, role).ConfigureAwait(false);
        }
// Call update once when all roles are added
return await UpdateAsync(user).ConfigureAwait(false);
    }
publicvirtual async Task<IdentityResult> RemoveUserFromRolesAsync(
string userId, IList<string> roles)
    {
        var userRoleStore = (IUserRoleStore<ApplicationUser, string>) Store;
        var user = await FindByIdAsync(userId).ConfigureAwait(false);
if (user == null)
        {
thrownew InvalidOperationException("Invalid user Id");
        }
        var userRoles = await userRoleStore
            .GetRolesAsync(user)
            .ConfigureAwait(false);
// Remove user to each role using UserRoleStore
foreach (var role in roles.Where(userRoles.Contains))
        {
            await userRoleStore
                .RemoveFromRoleAsync(user, role)
                .ConfigureAwait(false);
        }
// Call update once when all roles are removed
return await UpdateAsync(user).ConfigureAwait(false);
    }
}

 

For what appears to be a large chunk of code, ApplicationUserManager actually only provides a handful of very important functions - Adding new Users, Adding Users to Roles, and Removing Users from Roles. However, ApplicationUserManager is derived from the UserManager<ApplicationUser> class, so all the functionality provided by UserManager is also available to ApplicationUserManager. Other than that, there is a static Create() method defined which returns an instance of ApplicationUserManager itself. It is in this method that much of your user configuration settings and default are set up.

Of particular note in the Create() method is the call to context.Get<ApplicationDBContext>(). Remember earlier, when we looked at the ConfigAuth() method with those calls to CreatePerOwinContext and we passed in a callback method? The call to context.Get<ApplicationDbContext>() executes that call back, in this case, the static method ApplicationDbContext.Create() . We'll see more of this shortly.

If you look closely, you can see that user authorization, authentication, and management settings and defaults are set up in the Create() method, before returning a new ApplicationUserManager instance to the caller. Also, this is where two-factor auth services are set up. We can see that most of the settings are fairly self-explanatory. However, the two services bear a closer look. We'll come back to that in a moment. First, a quick look at  the ApplicationRoleManager class:

The Application Role Manager Class:
publicclass ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole,string> roleStore)
        : base(roleStore)
    {
    }
publicstatic ApplicationRoleManager Create(
        IdentityFactoryOptions<ApplicationRoleManager> options, 
        IOwinContext context)
    {
        var manager = new ApplicationRoleManager(
new RoleStore<IdentityRole>(
                context.Get<ApplicationDbContext>()));
return manager;
    }
}

 

As with ApplicationUserManager, we can see that ApplicationRoleManager is derived from RoleManager<IdentityRole> and thus brings with it all of the functionality offered by that class as well. Once again, we see a static Create() method returning an instance of the class itself.

Email Service and SMS Service for Account Validation and Two-Factor Auth

Also in the IdentityConfig.cs file are two service classes, EmailService and SmsService. Out of the box, these two classes are basically empty wrappers, providing an abstraction within which you can implement Email and/or SMS services required for two-factor authentication and account validation.

The ASP.NET Identity Email Service Class:
publicclass EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
    {
// Plug in your email service here to send an email.
return Task.FromResult(0);
    }
}

 

The ASP.NET Identity SmsService Class:
publicclass SmsService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
    {
// Plug in your sms service here to send a text message.
return Task.FromResult(0);
    }
}

 

Note that both of these classes implement a common interface, IIdentityMessageService. Also recall in the ApplicationUserManager.Create() method, the following lines:

Setting Up the Email Service and the SMS Service in the ApplicationUserManager Create Method:
// Register two factor authentication providers. This application uses 
// Phone and Emails as a step of receiving a code for verifying 
// the user You can write your own provider and plug in here.
manager.RegisterTwoFactorProvider("PhoneCode", 
new PhoneNumberTokenProvider<ApplicationUser>
{
    MessageFormat = "Your security code is: {0}"
});
manager.RegisterTwoFactorProvider("EmailCode", 
new EmailTokenProvider<ApplicationUser>
{
    Subject = "SecurityCode",
    BodyFormat = "Your security code is {0}"
});
manager.EmailService = new EmailService();
manager.SmsService = new SmsService();

 

We can see that during the course of the Create() method new instances of both EmailService and SmsService are initialized, and referenced by corresponding properties on the new ApplicationUserManager instance.

Sign-In Helper - The Basic Identity 2.0 Sign-In API

In creating the Identity Sample project, the Identity team has added a handy helper class, also found in the IdentityConfig.cs file, which wraps commonly needed calls for sign-in and authentication into an efficient and easy to use API. We can see how these methods are consumed by examining the AccountController in the Controllers folder. First, though, let's take a look at the SignInHelper class itself.

As with the previous examples, we're not going to go into much detail here, other than familiarizing ourselves with the basic structure of the class, the methods available, and get a rough idea how we might use the methods in SignInHelper from within our application.

The Sign-In Helper Class:
publicclass SignInHelper
{
public SignInHelper(
        ApplicationUserManager userManager, 
        IAuthenticationManager authManager)
    {
        UserManager = userManager;
        AuthenticationManager = authManager;
    }
public ApplicationUserManager UserManager { get; privateset; }
public IAuthenticationManager AuthenticationManager { get; privateset; }
public async Task SignInAsync(
        ApplicationUser user, 
bool isPersistent, 
bool rememberBrowser)
    {
// Clear any partial cookies from external or two factor partial sign ins
        AuthenticationManager.SignOut(
            DefaultAuthenticationTypes.ExternalCookie, 
            DefaultAuthenticationTypes.TwoFactorCookie);
        var userIdentity = await user.GenerateUserIdentityAsync(UserManager);
if (rememberBrowser)
        {
            var rememberBrowserIdentity = 
                AuthenticationManager.CreateTwoFactorRememberBrowserIdentity(user.Id);
            AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = isPersistent }, 
                userIdentity, 
                rememberBrowserIdentity);
        }
else
        {
            AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = isPersistent }, 
                userIdentity);
        }
    }
public async Task<bool> SendTwoFactorCode(string provider)
    {
        var userId = await GetVerifiedUserIdAsync();
if (userId == null)
        {
returnfalse;
        }
        var token = await UserManager.GenerateTwoFactorTokenAsync(userId, provider);
// See IdentityConfig.cs to plug in Email/SMS services to actually send the code
        await UserManager.NotifyTwoFactorTokenAsync(userId, provider, token);
returntrue;
    }
public async Task<string> GetVerifiedUserIdAsync()
    {
        var result = await AuthenticationManager.AuthenticateAsync(
            DefaultAuthenticationTypes.TwoFactorCookie);
if (result != null&& result.Identity != null
&& !String.IsNullOrEmpty(result.Identity.GetUserId()))
        {
return result.Identity.GetUserId();
        }
returnnull;
    }
public async Task<bool> HasBeenVerified()
    {
return await GetVerifiedUserIdAsync() != null;
    }
public async Task<SignInStatus> TwoFactorSignIn(
string provider, 
string code, 
bool isPersistent, 
bool rememberBrowser)
    {
        var userId = await GetVerifiedUserIdAsync();
if (userId == null)
        {
return SignInStatus.Failure;
        }
        var user = await UserManager.FindByIdAsync(userId);
if (user == null)
        {
return SignInStatus.Failure;
        }
if (await UserManager.IsLockedOutAsync(user.Id))
        {
return SignInStatus.LockedOut;
        }
if (await UserManager.VerifyTwoFactorTokenAsync(user.Id, provider, code))
        {
// When token is verified correctly, clear the access failed 
// count used for lockout
            await UserManager.ResetAccessFailedCountAsync(user.Id);
            await SignInAsync(user, isPersistent, rememberBrowser);
return SignInStatus.Success;
        }
// If the token is incorrect, record the failure which 
// also may cause the user to be locked out
        await UserManager.AccessFailedAsync(user.Id);
return SignInStatus.Failure;
    }
public async Task<SignInStatus> ExternalSignIn(
        ExternalLoginInfo loginInfo, 
bool isPersistent)
    {
        var user = await UserManager.FindAsync(loginInfo.Login);
if (user == null)
        {
return SignInStatus.Failure;
        }
if (await UserManager.IsLockedOutAsync(user.Id))
        {
return SignInStatus.LockedOut;
        }
return await SignInOrTwoFactor(user, isPersistent);
    }
private async Task<SignInStatus> SignInOrTwoFactor(
        ApplicationUser user, 
bool isPersistent)
    {
if (await UserManager.GetTwoFactorEnabledAsync(user.Id) &&
            !await AuthenticationManager.TwoFactorBrowserRememberedAsync(user.Id))
        {
            var identity = new ClaimsIdentity(DefaultAuthenticationTypes.TwoFactorCookie);
            identity.AddClaim(new Claim(ClaimTypes.NameIdentifier, user.Id));
            AuthenticationManager.SignIn(identity);
return SignInStatus.RequiresTwoFactorAuthentication;
        }
        await SignInAsync(user, isPersistent, false);
return SignInStatus.Success;
    }
public async Task<SignInStatus> PasswordSignIn(
string userName, 
string password, 
bool isPersistent, 
bool shouldLockout)
    {
        var user = await UserManager.FindByNameAsync(userName);
if (user == null)
        {
return SignInStatus.Failure;
        }
if (await UserManager.IsLockedOutAsync(user.Id))
        {
return SignInStatus.LockedOut;
        }
if (await UserManager.CheckPasswordAsync(user, password))
        {
return await SignInOrTwoFactor(user, isPersistent);
        }
if (shouldLockout)
        {
// If lockout is requested, increment access failed 
// count which might lock out the user
            await UserManager.AccessFailedAsync(user.Id);
if (await UserManager.IsLockedOutAsync(user.Id))
            {
return SignInStatus.LockedOut;
            }
        }
return SignInStatus.Failure;
    }
}

 

That's a lot of code to wade through, and like I said, we're not going to look too closely right now. We are mainly here to find our way around, get oriented. We can see that the methods in this class all appear to be related to sign-in and authorization responsibilities.

The methods available in the SignInHelper class all represent some of the new features introduces in Identity 2.0. We see a familiar SignInAsync() method, of course, but then we see a host of new methods related to two-factor authorization and external log-in. Further, there appears to be a lot more going on here in order to sign in than previously.

We can look at the Login method on AccountController in the example project for an example of how authentication is handled in Identity 2.0:

The Login Method on Account Controller Using Identity 2.0:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (!ModelState.IsValid)
    {
return View(model);
    }
// This doen't count login failures towards lockout only two factor authentication
// To enable password failures to trigger lockout, change to shouldLockout: true
    var result = await SignInHelper.PasswordSignIn(
        model.Email, 
        model.Password, 
        model.RememberMe, 
        shouldLockout: false);
switch (result)
    {
case SignInStatus.Success:
return RedirectToLocal(returnUrl);
case SignInStatus.LockedOut:
return View("Lockout");
case SignInStatus.RequiresTwoFactorAuthentication:
return RedirectToAction("SendCode", new { ReturnUrl = returnUrl });
case SignInStatus.Failure:
default:
            ModelState.AddModelError("", "Invalid login attempt.");
return View(model);
    }
}

 

Signing in: Compare to Identity 1.0

If we take a quick look at how the log-in task was handled in an MVC project using Identity 1.0, we can go straight to the AccountController.Login method, and we find the following bit of code:

The Login Method on Account Controller Using Identity 1.0:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Login(LoginViewModel model, string returnUrl)
{
if (ModelState.IsValid)
    {
        var user = await UserManager.FindAsync(model.UserName, model.Password);
if (user != null)
        {
            await SignInAsync(user, model.RememberMe);
return RedirectToLocal(returnUrl);
        }
else
        {
            ModelState.AddModelError("", "Invalid username or password.");
        }
    }
// If we got this far, something failed, redisplay form
return View(model);
}

 

Within the method above, we call into a UserManager class, similar to the code we saw for the SignInHelper. We also call the SignInAsync method, also defined directly in AccountController:

The SignInAsync Method on Account Controller Using Identity 1.0:
private async Task SignInAsync(ApplicationUser user, bool isPersistent)
{
    AuthenticationManager.SignOut(
        DefaultAuthenticationTypes.ExternalCookie);
    var identity = await UserManager.CreateIdentityAsync(
        user, DefaultAuthenticationTypes.ApplicationCookie);
    AuthenticationManager.SignIn(
new AuthenticationProperties() { IsPersistent = isPersistent }, identity);
}

 

Obviously, with the added features related to security, authentication, and authorization comes additional complexity, even at the basic log-in level.

The Heart of it All - ApplicationDbContext

If you have spent any time at all working with ASP.NET MVC in general, and Identity in particular, you are likely familiar with the ApplicationDbContext. This is the default Entity Framework implementation class by which your application accesses and stores Identity-related data.

In the example project, the team has set this up a little differently than in the standard ASP.NET project using Identity 1.0. First, if we take a look in the IdentityModels.cs file, we find the ApplicationDbContext class defined thusly:

The ApplicationDbContext Class from Identity 2.0 Example Project:
publicclass ApplicationDbContext : IdentityDbContext<ApplicationUser> {
public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false) {
    }
static ApplicationDbContext() {
// Set the database intializer which is run once during application start
// This seeds the database with admin user credentials and admin role
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
publicstatic ApplicationDbContext Create() {
returnnew ApplicationDbContext();
    }
}

 

The code above sets up two static methods, Create() , and another, ApplicationDbContext(), which sets a database initializer. This latter method is called during startup, and performs whatever database initialization is established in the ApplicationDbInitializer class.

If we go back to the IdentityConfig.cs file, we find the ApplicationDbInitializer defined like so:

The ApplicationDbInitializer Class from the IdentityConfig.cs File:
publicclass ApplicationDbInitializer 
    : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{
protectedoverridevoid Seed(ApplicationDbContext context) 
    {
        InitializeIdentityForEF(context);
base.Seed(context);
    }
publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db) 
    {
        var userManager = HttpContext
            .Current.GetOwinContext()
            .GetUserManager<ApplicationUserManager>();
        var roleManager = HttpContext.Current
            .GetOwinContext()
            .Get<ApplicationRoleManager>();
conststring name = "admin@admin.com";
conststring password = "Admin@123456";
conststring roleName = "Admin";
//Create Role Admin if it does not exist
        var role = roleManager.FindByName(roleName);
if (role == null) 
        {
            role = new IdentityRole(roleName);
            var roleresult = roleManager.Create(role);
        }
        var user = userManager.FindByName(name);
if (user == null) 
        {
            user = new ApplicationUser { UserName = name, Email = name };
            var result = userManager.Create(user, password);
            result = userManager.SetLockoutEnabled(user.Id, false);
        }
// Add user admin to Role Admin if not already added
        var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name)) 
        {
            var result = userManager.AddToRole(user.Id, role.Name);
        }
    }
}

 

As it is currently configured, this initializer will drop and re-create the database is the model schema (as defined by our code-first model objects) has changed. Otherwise, it will continue using the existing database.

If we want to drop and re-create the database every time our application is run we could change the base class from which it inherits to DropCreateDatabaseAlways<ApplicationDbContext>. We might want to do this during development if we wanted to start with an empty (or nearly so) data set every time for testing, for example.

Also, take note of the InitializeIdentityForEF() method. This method performs a function similar to that of the Seed() method when we use EF Migrations, allowing us to initialize the database with some data. In this case, the example project is set up with a pre-defined admin user, password, and role.

Ok John, That's All Great. Now What?

In this article we have looked broadly at where some of the new features and configuration items live in an ASP.NET MVC project using the Identity 2.0 framework. There is a lot more to it, and we will look at specifics in several upcoming posts.

For now, explore and run the example project, and get more familiar with how things work.

Additional Resources and Items of Interest

The Following Focus on Using the Identity 1.0 Framework:

 

ASP.NET Identity 2.0: Setting Up Account Validation and Two-Factor Authorization

$
0
0

4097092685_cd75ff7679_zWith the release of the Identity 2.0 framework in March of 2014, the Identity team has added a significant set of new features to the previously simple, but somewhat minimal ASP.NET Identity system. Some of the most visible, and in-demand features introduced with the new release are account validation and two-factor authorization.

The Identity team has created a terrific sample project/template which can effectively serve as the starting point for just about any ASP.NET MVC project you wish to build out with Identity 2.0 features. In this post, we will look at implementing email account validation as part of the account creation process, and two-factor authorization.

Image by Lucas | Some Rights Reserved

Previously, we took a very high-level tour of some of the new features available in Identity 2.0, and how key areas differ from the previous version 1.0 release. In this article, we'll take a close look at implementing Email Account Validation, and Two-Factor Authentication.

Getting Started: Create the Sample Project Using Nuget

To get started and follow along, create an empty ASP.NET project in Visual Studio (not an MVC project, use the Empty project template when creating a new project). Then, open the Package Manager Console and type:

Install the Sample Project from Nuget:
PM> Install-Package Microsoft.AspNet.Identity.Samples -Pre

 

Once Nuget has done its thing, you should see a familiar ASP.NET MVC project structure in the Solution Explorer:

ASP.NET Identity 2.0 Sample Project in Solution Explorer:installed-project-in-solution-explorer

 

This structure should look mostly familiar if you have worked with a standard ASP.NET MVC project before. There are, however, a few new items in there, if you look closely. For our purposes in this article, we are primarily concerned with the IdentityConfig.cs file, located in the App_Start folder.

If we open the IdentityConfig.cs file and scroll through, we find two services classes defined, EmailService and SmsService:

The Email Service and SMS Service Classes:
publicclass EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
    {
// Plug in your email service here to send an email.
return Task.FromResult(0);
    }
}
publicclass SmsService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
    {
// Plug in your sms service here to send a text message.
return Task.FromResult(0);
    }
}

 

Notice the both EmailService and SmsService implement the common interface, IIdentityMessageService. We can use IIdentityMessageService to create any number of Mail, SMS, or other messaging implementations. We'll se how this works momentarily.

Set Up A Default Admin Account

Before you go too much further, we need to set up a default Admin account that will be deployed when the site runs. The example project is set up so that the database is initialized when the project is run, and/or anytime the Code-First model schema changes. We need a default Admin user so that once the site runs, you can log in and do admin-type things, and you can't do THAT until you have a registered admin account.

As with the previous version of Identity, the default user account created during on-line registration has no admin privileges. Unlike the previous version, the first user created when the site is run is NOT an admin user. We need to seed the database during initialization.

Take a look at ApplicationDbInitializer class, also defined in IdentityConfig.cs:

The Application Db Initializer Class:
publicclass ApplicationDbInitializer 
    : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{
protected override void Seed(ApplicationDbContext context) {
        InitializeIdentityForEF(context);
        base.Seed(context);
    }
    //Create User=Admin@Admin.com with password=Admin@123456 in the Admin role        
publicstatic void InitializeIdentityForEF(ApplicationDbContext db) 
    {
        var userManager = 
            HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var roleManager = 
            HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
conststring name = "admin@admin.com";
conststring password = "Admin@123456";
conststring roleName = "Admin";
        //Create Role Admin if it does not exist
        var role = roleManager.FindByName(roleName);
if (role == null) {
            role = new IdentityRole(roleName);
            var roleresult = roleManager.Create(role);
        }
        var user = userManager.FindByName(name);
if (user == null) {
            user = new ApplicationUser { UserName = name, Email = name };
            var result = userManager.Create(user, password);
            result = userManager.SetLockoutEnabled(user.Id, false);
        }
        // Add user admin to Role Admin ifnot already added
        var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name)) {
            var result = userManager.AddToRole(user.Id, role.Name);
        }
    }
}

 

The lines highlighted in yellow define the default admin user that will be created when the application is run for the first time. Before we proceed, change these to suit your own needs, and ideally, include a live, working email address.

Account Validation: How it works

You are no doubt familiar with email-based account validation. You create an account at some website, and a confirmation email is sent to your email address with a link you need to follow in order to confirm your email address and validate your account.

If we look at the AccountController in the example project, we find the Register method:

The Register Method on Account Controller:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
    {
        var user = new ApplicationUser { UserName = model.Email, Email = model.Email };
        var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
        {
            var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
            var callbackUrl = Url.Action(
"ConfirmEmail", 
"Account", 
new { userId = user.Id, code = code }, 
                protocol: Request.Url.Scheme);
            await UserManager.SendEmailAsync(
                user.Id, 
"Confirm your account", 
"Please confirm your account by clicking this link: <a href=\"" 
                + callbackUrl + "\">link</a>");
            ViewBag.Link = callbackUrl;
return View("DisplayEmail");
        }
        AddErrors(result);
    }
// If we got this far, something failed, redisplay form
return View(model);
}

 

Looking close at the above, we see a call to UserManager.SendEmailAsync where we pass in some arguments. Within AccountController, UserManager is a property which returns an instance of type ApplicationUserManager. If we take a look in the IdentityConfig.cs file in the App_Start folder, we find the definition for ApplicationUserManager. On this class, the static Create() method initializes and returns a new instance of ApplicationUserManager, and this is where our messaging services are configured:

The Create() Method Defined on the ApplicationUserManager Class:
publicstatic ApplicationUserManager Create(
    IdentityFactoryOptions<ApplicationUserManager> options, 
    IOwinContext context)
{
    var manager = new ApplicationUserManager(
new UserStore<ApplicationUser>(
            context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
    manager.UserValidator = new UserValidator<ApplicationUser>(manager)
    {
        AllowOnlyAlphanumericUserNames = false,
        RequireUniqueEmail = true
    };
// Configure validation logic for passwords
    manager.PasswordValidator = new PasswordValidator
    {
        RequiredLength = 6, 
        RequireNonLetterOrDigit = true,
        RequireDigit = true,
        RequireLowercase = true,
        RequireUppercase = true,
    };
// Configure user lockout defaults
    manager.UserLockoutEnabledByDefault = true;
    manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
    manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. This application 
// uses Phone and Emails as a step of receiving a code for verifying the user
// You can write your own provider and plug in here.
    manager.RegisterTwoFactorProvider(
"PhoneCode", 
new PhoneNumberTokenProvider<ApplicationUser>
    {
        MessageFormat = "Your security code is: {0}"
    });
    manager.RegisterTwoFactorProvider(
"EmailCode", 
new EmailTokenProvider<ApplicationUser>
    {
        Subject = "SecurityCode",
        BodyFormat = "Your security code is {0}"
    });
    manager.EmailService = new EmailService();
    manager.SmsService = new SmsService();
    var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
    {
        manager.UserTokenProvider = 
new DataProtectorTokenProvider<ApplicationUser>(
                dataProtectionProvider.Create("ASP.NET Identity"));
    }
return manager;
}

 

The lines highlighted in yellow show where we set the Email and SMS services on the ApplicationUserManager instance. Just above the highlighted lines, we see how we register two-factor providers for Email and SMS messages.

From the above, we can see that the Register() method of AccountController calls the SendEmailAsync method of ApplicationUserManager, which has been configured with an Email and SMS service at the time it is created.

Email validation of new user accounts, two-factor authentication via email, and two-factor authentication via SMS Text all depend upon working implementations for the EmailService and SmsService classes.

Implementing the Email Service Using Your Own Mail Account

Setting up the email service for our application is a relatively simple task. You can use your own email account, or a mail service such as Sendgrid to create and send account validation or two-factor sign-in email. For example, if I wanted to use an Outlook.com email account to send confirmation email, I might configure my Email Service like so:

The Mail Service Configured to Use an Outlook.com Host:
publicclass EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
    {
// Credentials:
        var credentialUserName = "yourAccount@outlook.com";
        var sentFrom = "yourAccount@outlook.com";
        var pwd = "yourApssword";
// Configure the client:
        System.Net.Mail.SmtpClient client = 
new System.Net.Mail.SmtpClient("smtp-mail.outlook.com");
        client.Port = 587;
        client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
        client.UseDefaultCredentials = false;
// Creatte the credentials:
        System.Net.NetworkCredential credentials = 
new System.Net.NetworkCredential(credentialUserName, pwd);
        client.EnableSsl = true;
        client.Credentials = credentials;
// Create the message:
        var mail = 
new System.Net.Mail.MailMessage(sentFrom, message.Destination);
        mail.Subject = message.Subject;
        mail.Body = message.Body;
// Send:
return client.SendMailAsync(mail);
    }
}

 

The precise details for your SMTP host may differ, but you  should be able to find documentation. As a general rule, though, the above is a good starting point.

Implementing the Email Service Using Sendgrid

There are numerous email services available, but Sendgrid is a popular choice in the .NET community. Sendgrid offers API support for multiple languages as well as an HTTP-based Web API. Additionally, Sendgrid offers direct integration with Windows Azure.

If you have a standard Sendgrid account (you can set up a free developer account at the Sendgrid site), setting up the Email Service is only slightly different than in the previous example. First off, your network credentials will simply use your Sendgrid user name and password. Note that in this case, your user name is different than the email address you are sending from. in fact, you can use any address as your sent from address.

The EmailService Configured to Use Sendgrid:
publicclass EmailService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
    {
// Credentials:
        var sendGridUserName = "yourSendGridUserName";
        var sentFrom = "whateverEmailAdressYouWant";
        var sendGridPassword = "YourSendGridPassword";
// Configure the client:
        var client = 
new System.Net.Mail.SmtpClient("smtp.sendgrid.net", Convert.ToInt32(587));
        client.Port = 587;
        client.DeliveryMethod = System.Net.Mail.SmtpDeliveryMethod.Network;
        client.UseDefaultCredentials = false;
// Creatte the credentials:
        System.Net.NetworkCredential credentials = 
new System.Net.NetworkCredential(credentialUserName, pwd);
        client.EnableSsl = true;
        client.Credentials = credentials;
// Create the message:
        var mail = 
new System.Net.Mail.MailMessage(sentFrom, message.Destination);
        mail.Subject = message.Subject;
        mail.Body = message.Body;
// Send:
return client.SendMailAsync(mail);
    }
}

 

In the above, we see all we really had to change were our credentials, and the SMTP host string.

With that done, we can give our email service a quick trial run.

Testing Account Confirmation Using the Email Service

First, let's run our application, and attempt to register a new user. User a working email address to which you have access. If all goes well you will be redirected to a view resembling the following:

Redirect to Confirmation Sent View:

redirect-to-confirmation-view

As you can see, there is some language there indicating that you can click the link in the view to confirm account creation for the purpose of the demo. However, an actual confirmation email should have been sent to the address you specified when creating the account, and following the confirmation link will, in fact, confirm the account and allow you to log in.

Once we have our site working properly, we will obviously want to do away with the demo link, and also change the text on this view. We'll look at that shortly.

Implementing the SMS Service

To use two-factor authentication with SMS/Text, you will need an SMS host provider, such as Twilio. Like Sendgrid, Twilio is quite popular in the .NET community, and offers a comprehensive C# API. You can sign up for a free account at the Twilio Site.

When you create a Twilio account, you will be issued an SMS phone number, an account SID, and an Auth Token. You can find your Twilio SMS phone number by logging into your account, and navigating to the Numbers tab:

Locate Twilio SMS Number:

twilio-sms-number

Likewise, you can find your SID and Auth Token on the Dashboard Tab:

Locate Twilio SID and Auth Token:

twilio-sid-and-auth-token

In the above, see the little padlock icon next to the Auth Token? If you click that, your token will be visible, and can be copied for pasting into your code.

Once you have created an account, in order to use Twilio from within your application, you will need to get the Twilio Nuget package:

Add the Twilio Nuget Package Using Package Manager Console:
PM> Install-Package Twilio

 

That done, we can add Twilio to the using statements at the top of our IdentityConfig.cs file, and then implement the SMS service as follows:

The SMS Service Using Twilio:
publicclass SmsService : IIdentityMessageService
{
public Task SendAsync(IdentityMessage message)
    {
string AccountSid = "YourTwilioAccountSID";
string AuthToken = "YourTwilioAuthToken";
string twilioPhoneNumber = "YourTwilioPhoneNumber";
        var twilio = new TwilioRestClient(AccountSid, AuthToken);
        twilio.SendSmsMessage(twilioPhoneNumber, message.Destination, message.Body); 
// Twilio does not return an async Task, so we need this:
return Task.FromResult(0);
    }
}

 

Now that we have both an email service and an SMS service configured, we can see if our two-factor authentication works as expected.

Testing Two-Factor Authentication

The example project is set up so that two-factor authentication is an "opt-in" feature per user. To see if everything is working properly, log in using either your default admin account, or the account you created previously when testing out the email validation feature. Once logged in, navigate to the user account area by clicking on the user name displayed top right in the browser view. You should see something like this:

The Manage User Account View:

enable-two-factor-auth

In the above window, you will want to enable two-factor authentication, and add your phone number. When you go to add your phone number, you will be sent an SMS message to confirm. If we have done everything correctly so far, this should only take a few seconds (sometimes it can be more than a few seconds, but in general, if 30 or more seconds goes by, something is probably wrong . . .).

Once two-factor auth is enabled, you can log out, and try logging in again. You will be offered a choice, via a drop-down menu, where you can choose to receive your two-factor code via email or SMS:

Select Two-Factor Authentication Method:

two-factor-choose-medium

Once you make your selection above, the two-factor code will be sent to your selected provider, and you can complete the login process.

Remove the Demo Shortcuts

As mentioned previously, the example project comes with some shortcuts built-in so that, for development and testing purposes, it is not necessary to actually send or retreive the two-factor code (or follow the account validation link from an actual email) from an email or SMS account.

Once we are ready to deploy, we will want to remove these shortcuts from the corresponding views, and also the code which passes the links/codes to the ViewBag. For example, if we take another look at the Register() method on AccountController, we can see the following code in the middle of the method:

if (result.Succeeded)
{
    var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
    var callbackUrl = 
        Url.Action("ConfirmEmail", "Account", 
new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
    await UserManager.SendEmailAsync(user.Id, "Confirm your account", 
"Please confirm your account by clicking this link: <a href=\"" + callbackUrl + "\">link</a>");
// This should not be deployed in production:
    ViewBag.Link = callbackUrl;
return View("DisplayEmail");
}
AddErrors(result);

 

The highlighted lines should be commented out or deleted in production.

Likewise, the View that is returned by the Register() method, DisplayEmail.cshtml, will need some adjustment as well:

The DisplayEmail View:
@{
    ViewBag.Title = "DEMO purpose Email Link";
}
<h2>@ViewBag.Title.</h2>
<p class="text-info">
    Please check your email and confirm your email address.
</p>
<p class="text-danger">
    For DEMO only: You can click this link to confirm the email: <a href="@ViewBag.Link">link</a>
    Please change this code to register an email service in IdentityConfig to send an email.
</p>

 

In a similar manner, the controller method VerifyCode() also pushes the two-factor code out into the view for ease of use during development, but we absolutely don't want this behavior in production:

The Verify Code Method on AccountController:
[AllowAnonymous]
public async Task<ActionResult> VerifyCode(string provider, string returnUrl)
{
// Require that the user has already logged in via username/password or external login
if (!await SignInHelper.HasBeenVerified())
    {
return View("Error");
    }
    var user = 
        await UserManager.FindByIdAsync(await SignInHelper.GetVerifiedUserIdAsync());
if (user != null)
    {
        ViewBag.Status = 
"For DEMO purposes the current " 
            + provider 
            + " code is: " 
            + await UserManager.GenerateTwoFactorTokenAsync(user.Id, provider);
    }
return View(new VerifyCodeViewModel { Provider = provider, ReturnUrl = returnUrl });
}

 

Also, as with the Register() method, we want to make suitable adjustments to the VerifyCode.cshtml View:

The VerifyCode.cshtml View:
@model IdentitySample.Models.VerifyCodeViewModel
@{
    ViewBag.Title = "Enter Verification Code";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("VerifyCode", "Account", new { ReturnUrl = Model.ReturnUrl }, FormMethod.Post, new { @class = "form-horizontal", role = "form" })) {
    @Html.AntiForgeryToken()
    @Html.ValidationSummary("", new { @class = "text-danger" })
    @Html.Hidden("provider", @Model.Provider)
<h4>@ViewBag.Status</h4>
<hr />
<div class="form-group">
        @Html.LabelFor(m => m.Code, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.Code, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<div class="checkbox">
                @Html.CheckBoxFor(m => m.RememberBrowser)
                @Html.LabelFor(m => m.RememberBrowser)
</div>
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Submit" />
</div>
</div>
}

 

Again, the highlighted line could prove troublesome, and should be removed.

Keep Mail and SMS Account Settings Secure

The examples in this article have account user names and passwords, Auth tokes, and such hard-coded into the methods in which they are used. It is unlikely we would want to deploy this way, and equally unlikely we would even want to push our code into source control with these things exposed in such a manner (ESPECIALLY to Github!!).

Far better to put any private settings in a secure location. See Keep Private Settings Out of Source Control for more information.

The Tip of the Iceberg

ASP.NET Identity 2.0 has introduced a number of exciting new features previously not available as "out-of-the-box" features available to ASP.NET developers. Email account validation and two-factor authentication are but two of the most visible, and easily implemented (at least, within the framework of the example project provided by the Identity team!).

New features such as these have added greatly to the security arsenal available to the average developer, but have also added complexity to development of sites which utilize Identity 2.0. The Identity 2.0 team has provided some powerful security tools, but it may be easier to introduce new and harder to find security holes if we are not careful.

Additional Resources and Items of Interest

The Following Focus on Identity 1.0:

 

ASP.NET Identity 2.0: Customizing Users and Roles

$
0
0

3321550181_49277672cf_z-640x480The ASP.NET Identity team released the Identity 2.0 framework RTM back in march. The new release contained significant additions to the functionality found in the original 1.0 release, and introduced some breaking changes as well.

In a previous post, we took a high-level look at how Identity 2.0 works by digging in to the Identity Samples application (which was, and still is, in beta, so things may continue to change). We also took a detailed look at implementing Email Account Confirmation and Two Factor Authentication, which represent a couple of the sexier features of the Identity 2.0 RTM release.

Image By Herry Lawford  | Some Rights Reserved

We have previously explored explored Extending Identity Accounts and Implementing Role-Based Authentication under Identity 1.0, as well as Extending and Modifying Roles. However, things have changed since then. If you are using Identity 1.0, those posts are still applicable, and you should refer to them now. If you are looking to dig in to Identity 2.0, keep reading!

Many of the customizations we previously needed to add on our own under Identity Version 1.0 have now been incorporated into the Version 2.0 RTM. Specifically, Role administration, and the assignment of users to one or more roles is implemented out of the box in the Identity Samples project. Extending the basic IdentityUser and Role classes is a more flexible proposition, but is more complex than previously.

In this post we will dig in and see what we need to do to extend the basic ApplicationUser and ApplicationRole types by adding some custom properties to each.

We will walk through things step-by step here, so you can follow along. However, I have created a Github repo containing the source for the finished project. If you run into trouble, I strongly recommend cloning the source to get a closer look.

Bear in mind, the code here is minimal, in that we don't attempt to make any UI improvements, excess validations, or other things which may seem obvious from an application design standpoint. Instead, we try to keep things simple, so that we can focus on the topic at hand.

We'll look at all that in a minute. First, we are going to start by installing the Identity Samples project.

Installing the Identity 2.0 Sample Project

The Identity team has created a sample project which can be installed into an empty ASP.NET Web Project. Note that as of this writing this is an alpha release, so some things may change. However, most of the basic functionality is implemented, and in fact the sample project is a strong starting point for using Identity 2.0 in your own site.

The Identity Samples project is available on Nuget. First, create an empty ASP.NET Web Project (It is important that you use the "Empty" template here, not MVC, not Webforms, EMPTY). Then open the Package Manager console and type:

PM> Install-Package Microsoft.AspNet.Identity.Samples -Pre

 

This may take a minute or two to run. When complete, your will see a basic ASP.NET MVC project in the VS Solution Explorer. Take a good look around the Identity 2.0 Samples project, and become familiar with what things are and where they are at.

Re-Engineering the Identity Samples Project Using Custom Types

The Identity Samples project provides a solid platform to use as the basis for incorporating the Identity 2.0 framework into a new ASP.NET MVC project. However, the project itself assumes you will be using the default string keys (which translates into string-based primary keys in our database), and also assumes you will be using the default types included with Identity Samples out of the box.

As we will see, Identity 2.0 provides a great deal of flexibility for implementing custom types derived from the interfaces and generic base classes that form the Identity framework core. However, building a project similar to Identity Samples from scratch would be a large undertaking. We’re going to take advantage of the work done by the Identity team in creating the ample project, and instead of starting from scratch, we will tweak this excellent foundation to implement our own customizations.

Core Identity 2.0 Objects are Generic

The basic types implemented by the Identity team in the Identity Samples project represent an abstraction layer on top of a more flexible set of base classes which use generic type arguments. For example, if we look at the IdentityModels.cs code file, we can see the ApplicationUser is derived from IdentityUser:

Application User as Implemented in the Identity Samples Project:
publicclass ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager.CreateIdentityAsync(
this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
    }
}

 

IdentityUser in this case, belongs to the namespace Microsoft.AspNet.Identity.EntityFramework. We can use the VS “Go to Definition” function or a source decompiler (such as Just Decompile by Telerik or Reflector by Redgate) to take a closer look at IdentityUser:

The Identity User Class:
publicclass IdentityUser : 
    IdentityUser<string, IdentityUserLogin, IdentityUserRole, 
    IdentityUserClaim>, IUser, IUser<string>
{
public IdentityUser()
    {
this.Id = Guid.NewGuid().ToString();
    }
public IdentityUser(string userName) : this()
    {
this.UserName = userName;
    }
}

 

Here, we see that IdentityUser inherits from another base class, IdentityUser<TKey, TLogin, TRole, TClaim> as well as a couple interfaces. In this case the concrete IdentityUser passes specific type arguments to the generic base class. And this is where things begin to get interesting.

As it turns out, all of the basic types required to use Identity 2.0 begin life as generic base types, with similar type arguments allowing us to define custom implementations. Looking at the definitions for the core Identity components used to build up the Identity Samples project, we find the following classes, shown here in terms of the concrete type arguments used in the default Identity constructs:

Default Identity 2.0 Class Signatures with Default Type Arguments:
publicclass IdentityUserRole 
    : IdentityUserRole<string>
publicclass IdentityRole 
    : IdentityRole<string, IdentityUserRole>
publicclass IdentityUserClaim 
    : IdentityUserClaim<string>
publicclass IdentityUserLogin 
    : IdentityUserLogin<string>
publicclass IdentityUser 
    : IdentityUser<string, IdentityUserLogin, 
        IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
publicclass IdentityDbContext 
    : IdentityDbContext<IdentityUser, IdentityRole, string, 
        IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
publicclass UserStore<TUser> 
    : UserStore<TUser, IdentityRole, string, IdentityUserLogin, 
        IdentityUserRole, IdentityUserClaim>, 
        IUserStore<TUser>, IUserStore<TUser, string>, IDisposable
    where TUser : IdentityUser
publicclass RoleStore<TRole> 
    : RoleStore<TRole, string, IdentityUserRole>, IQueryableRoleStore<TRole>, 
        IQueryableRoleStore<TRole, string>, IRoleStore<TRole, string>, IDisposable
    where TRole : IdentityRole, new()

 

In the above, we can see there is a progression of interdependency among the types. IdentityUserRole is derived from IdentityUserRole<TKey> with a string as the single required type argument. IdentityRole is derived from IdentityRole<TKey, TIdentityUserRole> with the concrete types of string and the default implementation of IdentityUserRole (which, as we’ve seen, specifies a string as the key type), respectively, and so on. As we move down the list, the interdependency between concrete type implementations increases.

We will see how this impacts our ability to customize the User and Role types in a bit. First, we can see that adding simple properties to the ApplicationUser implementation provided with the Identity Samples project is about as easy as it can get.

Extending Identity User - The Easy Part

If all we want to do is add some additional properties to the default ApplicationUser class defined in the Identity Samples project, life is simple enough - the Identity Samples team has set the project up with a sensible default implementation which can be extended with very little effort.

Recall from earlier the ApplicationUser class. Say we want to add some address properties as follows:

Extending the Default ApplicationUser Class:
publicclass ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> 
        GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager
            .CreateIdentityAsync(this, 
                DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
    }
publicstring Address { get; set; }
publicstring City { get; set; }
publicstring State { get; set; }
// Use a sensible display name for views:
    [Display(Name = "Postal Code")]
publicstring PostalCode { get; set; }
// Concatenate the address info for display in tables and such:
publicstring DisplayAddress
    {
get
        {
string dspAddress = 
string.IsNullOrWhiteSpace(this.Address) ? "" : this.Address;
string dspCity = 
string.IsNullOrWhiteSpace(this.City) ? "" : this.City;
string dspState = 
string.IsNullOrWhiteSpace(this.State) ? "" : this.State;
string dspPostalCode = 
string.IsNullOrWhiteSpace(this.PostalCode) ? "" : this.PostalCode;
returnstring
                .Format("{0} {1} {2} {3}", dspAddress, dspCity, dspState, dspPostalCode);
        }
    }
}

 

From here, in this limited case, all we need to do is update the various ViewModels, Views, and Controllers to incorporate our new properties. We will add functionality for the new properties to our RegisterViewModel, the Register.cshtml View itself, and the Register method of the AccountsController.

We will also do the same for the UsersAdminController and associated ViewModels and Views.

Update the Register ViewModel to Include Address Information

The RegisterViewModel is defined in the AccountViewModels.cs file. We need to add our new properties to this VeiwModel in order that the Register view, by which new users can sign up, affords them the opportunity to input their address information:

Update the RegisterViewModel to Include Address Info:
publicclass RegisterViewModel
{
    [Required]
    [EmailAddress]
    [Display(Name = "Email")]
publicstring Email { get; set; }
    [Required]
    [StringLength(100, ErrorMessage = 
"The {0} must be at least {2} characters long.", MinimumLength = 6)]
    [DataType(DataType.Password)]
    [Display(Name = "Password")]
publicstring Password { get; set; }
    [DataType(DataType.Password)]
    [Display(Name = "Confirm password")]
    [Compare("Password", ErrorMessage = 
"The password and confirmation password do not match.")]
publicstring ConfirmPassword { get; set; }
// Add the new address properties:
publicstring Address { get; set; }
publicstring City { get; set; }
publicstring State { get; set; }
// Use a sensible display name for views:
    [Display(Name = "Postal Code")]
publicstring PostalCode { get; set; }
}

 

Update the Register View to Include Address Information

Obviously, we want users to be able to input address information when they sign up. The Register.cshtml View is located in the Views => Accounts folder in the Solution Explorer. Update as follows:

Update the Register View with Address Information:
@model IdentitySample.Models.RegisterViewModel
@{
    ViewBag.Title = "Register";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("Register", "Account", FormMethod.Post, 
new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
    @Html.ValidationSummary("", new { @class = "text-danger" })
<div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.Address, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.Address, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.City, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.City, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.State, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.State, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.PostalCode, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.PostalCode, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Register" />
</div>
</div>
}
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

We can see in the yellow highlighted area above where we have added the appropriate fields to our view template.

Update the Register Method on AccountController

Now we need to make sure the Address info is saved when the form data is submitted. Update the Register() method on the AccountController:

Update the Register Method on AccountController:
[HttpPost]
[AllowAnonymous]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Register(RegisterViewModel model)
{
if (ModelState.IsValid)
    {
        var user = new ApplicationUser 
        { 
            UserName = model.Email, 
            Email = model.Email 
        };
// Add the Address properties:
        user.Address = model.Address;
        user.City = model.City;
        user.State = model.State;
        user.PostalCode = model.PostalCode;
        var result = await UserManager.CreateAsync(user, model.Password);
if (result.Succeeded)
        {
            var code = await UserManager.GenerateEmailConfirmationTokenAsync(user.Id);
            var callbackUrl = Url.Action("ConfirmEmail", "Account", 
new { userId = user.Id, code = code }, protocol: Request.Url.Scheme);
            await UserManager.SendEmailAsync(user.Id, 
"Confirm your account", 
"Please confirm your account by clicking this link: <a href=\"" 
                + callbackUrl + "\">link</a>");
            ViewBag.Link = callbackUrl;
return View("DisplayEmail");
        }
        AddErrors(result);
    }
// If we got this far, something failed, redisplay form
return View(model);
}

 

Update the Users Admin Components to Use the New Properties

Now, the basic registration functionality has been updated to utilize the new Address properties. However, the Identity Samples project also provides some administrative functionality by which a member of the Admin role can view and edit user information.

We need to update a few ViewModels, Views, and Controller methods here as well.

Update the UsersAdmin/Create.cshtml User View

In the Views => UsersAdmin folder, the Create.cshtml View uses the now-familiar RegisterViewModel to allow system administrators to add new users to the system. We want to afford data entry of Address information here, too:

Update the UsersAdmin/Create.cshtml View:
@model IdentitySample.Models.RegisterViewModel
@{
    ViewBag.Title = "Create";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("Create", "UsersAdmin", FormMethod.Post, 
new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
    @Html.ValidationSummary("", new { @class = "text-error" })
<div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.Address, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.Address, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.City, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.City, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.State, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.State, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.PostalCode, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.PostalCode, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">
            Select User Role
</label>
<div class="col-md-10">
            @foreach (var item in (SelectList)ViewBag.RoleId)
            {
<input type="checkbox" name="SelectedRoles" 
value="@item.Value" class="checkbox-inline" />
                @Html.Label(item.Value, new { @class = "control-label" })
            }
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Create" />
</div>
</div>
}
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

Again, we can see where we need to update the View by the highlighted area above.

Update the Edit User ViewModel

The EditUserViewModel is used by the UserAdminController and associated Views to support editing user information. We need to include any new properties here that we want to be able to edit. The EditUserViewModel is defined in the AdminViewModels.cs code file. Update as follows:

Update the EditUserViewModel:
publicclass EditUserViewModel
{
publicstring Id { get; set; }
    [Required(AllowEmptyStrings = false)]
    [Display(Name = "Email")]
    [EmailAddress]
publicstring Email { get; set; }
// Add the Address Info:
publicstring Address { get; set; }
publicstring City { get; set; }
publicstring State { get; set; }
// Use a sensible display name for views:
    [Display(Name = "Postal Code")]
publicstring PostalCode { get; set; }
public IEnumerable<SelectListItem> RolesList { get; set; }
}

 

Update the EditUser.cshtml View

Now that our EditUserViewModel has been updated, we again need to add the corresponding fields to the EditUser.cshtml View, also located in the Views => UsersAdmin folder:

Update the EditUser.cshtml View:
@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Edit User Form.</h4>
<hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)
<div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" })
<div class="col-md-10">
               @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
               @Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.Address, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(m => m.Address, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.City, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(m => m.City, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.State, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(m => m.State, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.PostalCode, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(m => m.PostalCode, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
            @Html.Label("Roles", new { @class = "control-label col-md-2" })
<span class=" col-md-10">
                @foreach (var item in Model.RolesList)
                {
<input type="checkbox" name="SelectedRole" value="@item.Value" checked="@item.Selected" class="checkbox-inline" />
                    @Html.Label(item.Value, new { @class = "control-label" })
                }
</span>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

Update the Users Admin Index, Delete, and Detail Views

For the UserAdmin Index, Delete, and Detail Views, we are going to do something a little different. We will use the DisplayAddress property to concatenate the address info into a single line suitable for display in a table or single form label. For the sake of brevity, we will only update the Index view here, also found in Views => UsersAdmin:

Update the UsersAdmin Index.cshtml View:
@model IEnumerable<IdentitySample.Models.ApplicationUser>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
            @Html.DisplayNameFor(model => model.UserName)
</th>
        @*Add a table header for the Address info:*@
<th>
            @Html.DisplayNameFor(model => model.DisplayAddress)
</th>
<th>
</th>
</tr>
    @foreach (var item in Model)
    {
<tr>
<td>
                @Html.DisplayFor(modelItem => item.UserName)
</td>
<td>
                @*Add table data for the Address info:*@
                @Html.DisplayFor(modelItem => item.DisplayAddress)
</td>
<td>
                @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                @Html.ActionLink("Details", "Details", new { id = item.Id }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
    }
</table>

 

We can see in the above that all we really did was add a table header element and a table data element to display the DisplayAddress data (which is a function masquerading as a property). The very same thing can be done for the Delete.cshtml View and the  Details.cshtml View, so we wont do that here.

Update the User Admin Controller

Now that we have updated the relevant ViewModel and Views, we also need to update the corresponding controller actions on the UserAdminController so that model data is properly passed to and from the Views. Specifically, we need to modify the Create() and Edit() methods.

Update the Create Method on UserAdminController

The create method allows an administrator to create a new system user. Add the functionality to include the new Address properties when the new user is created:

Modified Create method on UserAdminController:
[HttpPost]
public async Task<ActionResult> Create(RegisterViewModel userViewModel, paramsstring[] selectedRoles)
{
if (ModelState.IsValid)
    {
        var user = new ApplicationUser 
        { 
            UserName = userViewModel.Email, Email = 
            userViewModel.Email, 
// Add the Address Info:
            Address = userViewModel.Address,
            City = userViewModel.City,
            State = userViewModel.State,
            PostalCode = userViewModel.PostalCode
        };
// Add the Address Info:
        user.Address = userViewModel.Address;
        user.City = userViewModel.City;
        user.State = userViewModel.State;
        user.PostalCode = userViewModel.PostalCode;
// Then create:
        var adminresult = await UserManager.CreateAsync(user, userViewModel.Password);
//Add User to the selected Roles 
if (adminresult.Succeeded)
        {
if (selectedRoles != null)
            {
                var result = await UserManager.AddToRolesAsync(user.Id, selectedRoles);
if (!result.Succeeded)
                {
                    ModelState.AddModelError("", result.Errors.First());
                    ViewBag.RoleId = new SelectList(await RoleManager.Roles.ToListAsync(), "Name", "Name");
return View();
                }
            }
        }
else
        {
            ModelState.AddModelError("", adminresult.Errors.First());
            ViewBag.RoleId = new SelectList(RoleManager.Roles, "Name", "Name");
return View();
        }
return RedirectToAction("Index");
    }
    ViewBag.RoleId = new SelectList(RoleManager.Roles, "Name", "Name");
return View();
}

 

Next, update the Edit() method in a similar manner. Take careful note, though, to also include the additional bindings in the arguments:

Modified Edit Method on UserAdminController:
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(Include = 
"Email,Id,Address,City,State,PostalCode")] 
    EditUserViewModel editUser, paramsstring[] selectedRole)
{
if (ModelState.IsValid)
    {
        var user = await UserManager.FindByIdAsync(editUser.Id);
if (user == null)
        {
return HttpNotFound();
        }
        user.UserName = editUser.Email;
        user.Email = editUser.Email;
        user.Address = editUser.Address;
        user.City = editUser.City;
        user.State = editUser.State;
        user.PostalCode = editUser.PostalCode;
        var userRoles = await UserManager.GetRolesAsync(user.Id);
        selectedRole = selectedRole ?? newstring[] { };
        var result = await UserManager.AddToRolesAsync(user.Id, 
            selectedRole.Except(userRoles).ToArray<string>());
if (!result.Succeeded)
        {
            ModelState.AddModelError("", result.Errors.First());
return View();
        }
        result = await UserManager.RemoveFromRolesAsync(user.Id, 
            userRoles.Except(selectedRole).ToArray<string>());
if (!result.Succeeded)
        {
            ModelState.AddModelError("", result.Errors.First());
return View();
        }
return RedirectToAction("Index");
    }
    ModelState.AddModelError("", "Something failed.");
return View();
}

 

Role-Based Authorization is Already Implemented

When we looked at customizing Identity 1.0 in the article Extending Identity User and Implementing Role-Based Authorization, we needed significantly modify the basic project in order to assign users to roles. There was no provision in the default ASP.NET MVC project to directly manage user-role assignment.

The Identity Samples project addressed this deficiency, and has implemented user/role management out of the box. Where we previously needed to roll our own controller methods, models, and views in order to display and select roles for each user, this functionality is now included out of the box, in a manner very similar to what we had to do ourselves previously. However, what this means is that we need to make sure we initialize the application with a pre-built admin user.

Take Note of The IdentityConfig File

Within the Identity Samples project, database initialization and seeding is handled in the App_Start => IdentityConfig.cs file. For now, we don't need to make any changes to this file. However, note the ApplicationDbInitializer class, in which we define an initial Admin user, and initial Role, and a few other database configuration items:

The ApplicationDbInitializer Class in IdentityConfig.cs
publicclass ApplicationDbInitializer 
    : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{
protectedoverridevoid Seed(ApplicationDbContext context) {
        InitializeIdentityForEF(context);
base.Seed(context);
    }
//Create User=Admin@Admin.com with password=Admin@123456 in the Admin role        
publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db) {
        var userManager = 
            HttpContext.Current.GetOwinContext()
                .GetUserManager<ApplicationUserManager>();
        var roleManager = 
            HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
conststring name = "admin@example.com";
conststring password = "Admin@123456";
conststring roleName = "Admin";
//Create Role Admin if it does not exist
        var role = roleManager.FindByName(roleName);
if (role == null) {
            role = new IdentityRole(roleName);
            var roleresult = roleManager.Create(role);
        }
        var user = userManager.FindByName(name);
if (user == null) {
            user = new ApplicationUser { UserName = name, Email = name };
            var result = userManager.Create(user, password);
            result = userManager.SetLockoutEnabled(user.Id, false);
        }
// Add user admin to Role Admin if not already added
        var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name)) {
            var result = userManager.AddToRole(user.Id, role.Name);
        }
    }
}

 

Also note in the above that, in the default code the ApplicationDbInitializer class is derived from DropCreateDatabaseIfModelChanges<ApplicationDbContext> . As the name implies, this will cause a new database to be created, replacing the old, only when changes to the model impact the database schema. Often, this is sufficient. However, sometimes, it is handy to start with a fresh database each time the project is run. In these cases, we can simply change the class declaration to derive from DropCreateDatabaseAlways<ApplicationDbContext> which again, as the name implies, will cause a fresh database to be initialized each time the application is run.

For now, all we need to be aware of is the default admin user defined in the InitializeIdentityForEF() method, so we know how to log in for the first time.

Running the Project with the IdentityUser Modifications in Place

Thus far, all we have really done is add a few new properties to the existing implementation of the ApplicationUser model, and updated the corresponding ViewModels, Views, and Controllers. However, to extend IdentityUser in this manner, that is all that is needed. The project should now run, and the Address properties we have added should be properly represented within our application.

If we run the project, log in as the user defined in the IdentityConfig.cs file, we have admin access to the users and roles:

Logged In to the Identity Samples Application:

initial-login-modified-user

If we select the UsersAdmin tab, we find a list, which includes (to this point) only the seeded admin user, and in fact the Address information is blank. That's because we didn't seed any address values:

The Users Admin Tab of the Identity Samples Project with Empty Address:

select-users-admin-before-edit

We can now navigate to the Edit View, and update our initial user with some address information:

Edit the Default Admin User and Add Address Info:

edit-user-before-save

Once we have entered our address information and save, the list is updated, and the Users Admin Index view displays the updated info:

The Updated Users Admin Tab:

admin-user-index-after-edit

Things should work in a similar manner if we were to create a new user by navigating to the Create New link on the Admin Users tab, and also if we were to log out, and register as a new user.

Extending the basic IdentityUser implementation was simple enough, and it appears the Identity Samples project was fairly designed with this in mind. However, when it comes to extending or modifying the IdentityRole implementation, things become a little more complicated.

Extending Identity Role

As we noted earlier, the code Identity 2.0 framework was designed with a great deal of flexibility in mind, through the use of generic types and generic methods in the base classes used for key components. We saw previously how this creates a very flexible set of models, but working with them can be a little tricky when they become interdependent.

We want to use our existing, modified Identity Samples project, and add further customizations to the Identity Role implementation. Note that out of the box, Identity Samples does not define an ApplicationRole class - the project relies upon the basic IdentityRole provided by the framework itself.

The Identity Samples project simply uses the default implementation of the IdentityRole class defined in the namespace Microsoft.AspNet.Identity.EntityFramework. As we saw earlier, the default definition for IdentityRole looks like this:

The Default IdentityRole Implementation:
publicclass IdentityRole : IdentityRole<string, IdentityUserRole>
{
public IdentityRole()
    {
base.Id = Guid.NewGuid().ToString();
    }
public IdentityRole(string roleName) : this()
    {
base.Name = roleName;
    }
}

 

Again, as we discussed earlier, the Identity team has created a sensible default implementation by deriving from IdentityRole<TKey, TUserRole>, passing in a string and the Identity framework type IdentityUserRole as type arguments to the generic class definition.

If we wish to extend this implementation to include some custom properties, we will need to define our own. We can do this by inheriting directly from the default, and adding one or more of our own properties. We could, alternatively, start from the bottom and create our own implementation by deriving from IdentityRole<Tkey, TUserRole> but for our purposes here, we have no reason to start that low in the abstraction chain. We are sticking with the default string key type, and the basic IdentityUserRole.

A Note About IdentityRole and IdentityUserRole

Let's pause for a second to note a potential point of confusion. The Identity framework defines two seemingly similar classes, IdentityRole and IdentityUserRole. At the lowest framework implementation level, both are generic classes which implement specific interfaces. As suggested above, the generic implementation of IdentityRole looks like this:

Base implementation of the IdentityRole Class in Identity Framework 2.0:
publicclass IdentityRole<TKey, TUserRole> : IRole<TKey>
where TUserRole : IdentityUserRole<TKey>
{
public TKey Id
    {
get
        {
return JustDecompileGenerated_get_Id();
        }
set
        {
            JustDecompileGenerated_set_Id(value);
        }
    }
publicstring Name
    {
get;
set;
    }
public ICollection<TUserRole> Users
    {
get
        {
return JustDecompileGenerated_get_Users();
        }
set
        {
            JustDecompileGenerated_set_Users(value);
        }
    }
public IdentityRole()
    {
this.Users = new List<TUserRole>();
    }
}

 

Meanwhile, the generic base IdentityUserRole class looks like this:

The Generic Base Implementation for IdentityUserRole:
publicclass IdentityUserRole<TKey>
{
publicvirtual TKey RoleId
    {
get;
set;
    }
publicvirtual TKey UserId
    {
get;
set;
    }
public IdentityUserRole()
    {
    }
}

 

We don't need to worry overly much about these low-level details for our purposes here, other than to note that IdentityRole and IdentityUserRole are two different classes, with two different purposes. IdentityRole represents an actual Role entity in our application and in the database, while IdentityUserRole represents the relationship between a User and a Role.

With the similar names, it is easy to confuse one with the other in the midst of typing out code, and particularly when relying on VS intellisense. Of course, the compiler will let you know if you confuse the two, but it is still good to remain cognizant of the distinction, particularly when attempting more advanced customizations.

Adding a Customized Role to the Identity Samples Project

Bearing all of the above in mind, let's add a modified Role definition to our project. In keeping with the convention used for the project implementation of IdentityUser ("ApplicationUser"), we will add a class to the IdentityModels.cs file named ApplicationRole which inherits from IdentityRole and implements a custom Description property:

A Custom Implementation Derived from the Default IdentityRole Class:
publicclass ApplicationRole : IdentityRole
{
public ApplicationRole() : base() { }
public ApplicationRole(string name) : base(name) { }
publicstring Description { get; set; }
}

 

Now, that wasn't too bad, right? Well, we're only just getting started here. Since we are no longer using the default IdentityRole implementation, if we want to actually USE our custom class in the Identity Samples project, we need to introduce some non-trivial changes in a number of places.

Re-Implementing RoleStore and ApplicationRoleManager

First off, if we take another look at the App_Start => IdentityConfig.cs file, we find a class definition for ApplicationRoleManager:

Existing Implementation of ApplicationRoleManager in Identity Samples Project:
publicclass ApplicationRoleManager : RoleManager<IdentityRole>
{
public ApplicationRoleManager(IRoleStore<IdentityRole,string> roleStore)
        : base(roleStore)
    {
    }
publicstatic ApplicationRoleManager Create(
        IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
    {
returnnew ApplicationRoleManager(
new RoleStore<IdentityRole>(context.Get<ApplicationDbContext>()));
    }
}

 

As we can see, this class is rather heavily dependent upon the default framework type IdentityRole. We will need to replace all of the references to the IdentityRole type with our own ApplicationRole implementation.

Modified ApplicationRoleManager Class Depends on Custom ApplicationRole:
publicclass ApplicationRoleManager : RoleManager<ApplicationRole>
{
public ApplicationRoleManager(
        IRoleStore<ApplicationRole,string> roleStore)
        : base(roleStore)
    {
    }
publicstatic ApplicationRoleManager Create(
        IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
    {
returnnew ApplicationRoleManager(
new RoleStore<ApplicationRole>(context.Get<ApplicationDbContext>()));
    }
}

 

Also, in the InitializeDatabaseForEF() method in our ApplicationDbInitializer class (also in the IdentityConfig.cs file), we need to initialize a new ApplicationRole instead of a new IdentityRole:

Initialize ApplicationRole in Database Set-Up:
publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db) {
    var userManager = 
        HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
    var roleManager = 
        HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
conststring name = "admin@example.com";
conststring password = "Admin@123456";
conststring roleName = "Admin";
//Create Role Admin if it does not exist
    var role = roleManager.FindByName(roleName);
if (role == null) {
        role = new ApplicationRole(roleName);
        var roleresult = roleManager.Create(role);
    }
    var user = userManager.FindByName(name);
if (user == null) {
        user = new ApplicationUser { UserName = name, Email = name };
        var result = userManager.Create(user, password);
        result = userManager.SetLockoutEnabled(user.Id, false);
    }
// Add user admin to Role Admin if not already added
    var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name)) {
        var result = userManager.AddToRole(user.Id, role.Name);
    }
}

 

Update the Create Method on the Roles Admin Controller

Similar to the InitializeDatabaseForEF() method, we also need to properly initialize a new instance of ApplicationRole instead of IdentityRole in the Create() method on the RolesAdminController:

Update the Create Method on RolesAdminController:
public async Task<ActionResult> Create(RoleViewModel roleViewModel)
{
if (ModelState.IsValid)
    {
// Initialize ApplicationRole instead of IdentityRole:
        var role = new ApplicationRole(roleViewModel.Name);
        var roleresult = await RoleManager.CreateAsync(role);
if (!roleresult.Succeeded)
        {
            ModelState.AddModelError("", roleresult.Errors.First());
return View();
        }
return RedirectToAction("Index");
    }
return View();
}

 

Now we need to make sure we can consume our new and improved Role implementation in our Views. As we did with the modified ApplicationUser class, we now need to accommodate or new Role implementation in our ViewModels and View, and make sure we are passing the property data between the controllers and views appropriately.

Add Extended Properties to the RoleViewModel

In the AdminViewModels.cs file, we need to update the definition for RoleViewModel by adding our new Description property:

The Updated RoleViewModel:
publicclass RoleViewModel
{
publicstring Id { get; set; }
    [Required(AllowEmptyStrings = false)]
    [Display(Name = "RoleName")]
publicstring Name { get; set; }
publicstring Description { get; set; }
}

 

Next, we need to make sure the appropriate views make the Description property available for display and/or form entry.

Update the Roles Admin Create.cshtml View

The Views we need to update are in the Views => RolesAdmin folder in the VS Solution Explorer.

Similar to what we did with the Views for User Admin, we need to make the Description property available so that when administrators create new Roles, they can also enter and save the description. Add a form element to the Views => RolesAdmin => Create.cshtml view for the Description property:

The Updated Create.cshtml View for Role Admin:
@model IdentitySample.Models.RoleViewModel
@{
    ViewBag.Title = "Create";
}
<h2>Create.</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Role.</h4>
<hr />
        @Html.ValidationSummary(true)
<div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(model => model.Description, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Description)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

Update the Roles Admin Edit.cshtml View

Next, we do a similar modification to the Views => RolesAdmin => Edit.cshtml View:

The Modified Roles Admin Edit.cshtml View:
@model IdentitySample.Models.RoleViewModel
@{
    ViewBag.Title = "Edit";
}
<h2>Edit.</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Roles.</h4>
<hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)
<div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(model => model.Name, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.TextBoxFor(model => model.Description, new { @class = "form-control" })
                @Html.ValidationMessageFor(model => model.Description)
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

Update the Roles Admin Index.cshtml View

Unlike the Create and Edit Views, the Index, Delete, and Detail views need a few additional adjustments. Note that, in their existing form, these three View templates expect an instance of List<IdentityRole> as the model to be passed from the controller. We need to change the very first line of code to expect an IEnumerable<ApplicationRole> instead. Then, we make a relatively simple addition to the table header and table row elements in order to display the Description property:

The Updated Roles Admin Index.cshtml View
@model IEnumerable<IdentitySample.Models.ApplicationRole>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
            @Html.DisplayNameFor(model => model.Name)
</th>
<th>
            @Html.DisplayNameFor(model => model.Description)
</th>
<th>
</th>
</tr>
    @foreach (var item in Model)
    {
<tr>
<td>
                @Html.DisplayFor(modelItem => item.Name)
</td>
<td>
                @Html.DisplayFor(modelItem => item.Description)
</td>
<td>
                @Html.ActionLink("Edit", "Edit", new { id = item.Id }) |
                @Html.ActionLink("Details", "Details", new { id = item.Id }) |
                @Html.ActionLink("Delete", "Delete", new { id = item.Id })
</td>
</tr>
    }
</table>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

The Delete.cshtml and the Details.cshtml Views can be modified in a similar fashion, so we won't do that here in the interest of brevity. Note, however, that for the Index View, the View expects an IEnnumerable<ApplicationRole> whereas the Details and Delete Views will expect a singular instance of ApplicationRole.

Updating The Roles Admin Controller

In order for all this to work, we now need to modify the Create() and Edit() methods on the RolesAdminController so that the proper data is passed to and from the corresponding Views, and properly persisted to the backing store.

Update the Create Method on the Roles Admin Controller

The create method receives an instance of ApplicationRole as form data and persists the new Role to the database. All we need to do here is make sure the new Description data is also saved:

The Updated Create Method on Roles Admin Controller:
[HttpPost]
public async Task<ActionResult> Create(RoleViewModel roleViewModel)
{
if (ModelState.IsValid)
    {
        var role = new ApplicationRole(roleViewModel.Name);
// Save the new Description property:
        role.Description = roleViewModel.Description;
        var roleresult = await RoleManager.CreateAsync(role);
if (!roleresult.Succeeded)
        {
            ModelState.AddModelError("", roleresult.Errors.First());
return View();
        }
return RedirectToAction("Index");
    }
return View();
}

 

Update the Edit Method on the Roles Admin Controller

There are a few additional items to tend to with the Edit() method. First off, we need to populate the form with the current data in the GET request, then, when the POST comes back, we need to bind the appropriate form data, and make sure the new Description property is saved along with everything else.

Update the Edit Method on Roles Admin Controller:
public async Task<ActionResult> Edit(string id)
{
if (id == null)
    {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    var role = await RoleManager.FindByIdAsync(id);
if (role == null)
    {
return HttpNotFound();
    }
    RoleViewModel roleModel = new RoleViewModel 
    { 
        Id = role.Id, 
        Name = role.Name 
    };
// Update the new Description property for the ViewModel:
    roleModel.Description = role.Description;
return View(roleModel);
}
[HttpPost]
[ValidateAntiForgeryToken]
public async Task<ActionResult> Edit([Bind(
    Include = "Name,Id,Description")] 
    RoleViewModel roleModel)
{
if (ModelState.IsValid)
    {
        var role = await RoleManager.FindByIdAsync(roleModel.Id);
        role.Name = roleModel.Name;
// Update the new Description property:
        role.Description = roleModel.Description;
        await RoleManager.UpdateAsync(role);
return RedirectToAction("Index");
    }
return View();
}

 

Running the Project with Role Modifications in Place

If we have been careful as we updated all of our views and controllers, we should now be able to see our extended role in action. If we run the project, log in, and navigate to the RoleAdmin tab, we find a list containing a single Role. The description field is blank at this point, because we didn't add a description to the pre-defined initial role in our seed method.

The Roles Admin Tab at Startup:

role-admin-index

If we choose to Edit the existing role, we see we can type in a new description:

The Edit Role View - Data Entry:

edit-role-before-save

Once we save the new entry, we can see that the Index View now displays the Role Description:

The Roles Admin Index View After Edit:

role-admin-index-after-save

Wrapping It Up

In this article, we've taken a look at how to extend and modify the key IdentityUser and IdentityRole components of the Identity 2.0 framework. We have Done so in the context of the Identity Samples project, which provides a strong platform for both learning how to implement Identity 2.0 for basic authentication and authorization purposes, as well as a great foundation for the Identity portion of your own web application.

Items to keep in mind are:

The Identity Samples project is an alpha release, and is likely to evolve over time - there may be future changes which impact the specifics of this article.

Identity 2.0 RTM brings substantial flexibility and a host of additional capabilities to the ASP.NET platform, capabilities which until now had been notably missing. We have only scratched the surface here.

Identity 2.0 and the Identity Samples project present a simplified abstraction over a more flexible, and more complex underlying model. Customization is possible to a greater degree, with fewer hack-like work-arounds. However, the steps necessary are not necessarily immediately apparent. The framework of generically-typed components requires some additional thought when customizing due to the inter-dependent nature of the components.

As developers, it is within our power to dig in and explore, and figure things out. We get to do a lot of that as we set out to maximize the benefit of Identity 2.0 to our applications, and learn the new framework in general.

Additional Resources and Items of Interest

Identity 2.0 Resources:

ASP.NET Identity 2.0 Extending Identity Models and Using Integer Keys Instead of Strings

$
0
0

Identity-240The ASP.NET Identity framework was released to manufacture on March 20 2014, bringing with it a slew of long-awaited enhancements, delivering a fully-formed authentication and authorization platform to the ASP.NET developer community.

In previous posts, we have taken a broad look at the structure of the new framework, and how it differs from the 1.0 release. We've also walked through implementing email account confirmation and two-factor authentication, as well as extending the basic User and Role models (which requires a bit more effort than you might think).

Image by Josh Cowper  | Some Rights Reserved

In this post we're going take a deeper look at extending the core set of models afforded by the Identity 2.0 framework, and re-implementing the basic Identity Samples project using integer keys for all of our models, instead of the default string keys which are the default.

Source Code on Github

In the course of this article, we will basically re-implement the Identity Samples project with integer keys. you can clone the completed source code from my Github repo. Also, if you find bugs and/or have suggestions, please do open an issue and/or shoot me a pull request!

Why Does ASP.NET Identity Use String Keys in the First Place?

A popular, and somewhat confounding question is "why did the Identity team choose string keys as the default for the Identity framework models? Many of us who grew up using databases tend towards easy, auto-incrementing integers as database primary keys, because it's easy, and at least in theory, there are some performance advantages with respect to table indexes and such.

The decision of the Identity Team to use strings as keys is best summarized in a Stack Overflow answer by Rick Anderson, writer for ASP.NET at Microsoft:

  1. The Identity runtime prefers strings for the user ID because we don’t want to be in the business of figuring out proper serialization of the user IDs (we use strings for claims as well for the same reason), e.g. all (or most) of the Identity interfaces refer to user ID as a string.
  2. People that customize the persistence layer, e.g. the entity types, can choose whatever type they want for keys, but then they own providing us with a string representation of the keys.
  3. By default we use the string representation of GUIDs for each new user, but that is just because it provides a very easy way for us to automatically generate unique IDs.

The decision is not without its detractors in the community. The default string key described above is essentially a string representation of a Guid. As this discussion on Reddit illustrates, there is contention about the performance aspects of this against a relational database backend.

The concerns noted in the Reddit discussion focus mainly on database index performance, and are unlikely to be an issue for a large number of smaller sites and web applications, and particularly for learning projects and students. However, as noted previously, for many of us, the auto-incrementing integer is the database primary key of choice (even in cases where it is not the BEST choice), and we want our web application to follow suit.

Identity 2.0 Core Classes use Generic Type Arguments

As we discussed in the post on customizing ASP.NET Identity 2.0 Users and Roles, the framework is built up from a structure of generic Interfaces and base classes. At the lowest level, we find interfaces, such as IUser<TKey> and IRole<TKey>. These, and related Interfaces and base classes are defined in the Microsoft.AspNet.Identity.Core library.

Moving up a level of abstraction, we can look at the Microsoft.AspNet.Identity.EntityFramework library, which uses the components defined in …Identity.Core to build the useful, ready-to-use classes commonly used in applications, and in particular by the Identity Samples project we have been using to explore Identity 2.0.

The Identity.EntityFramework library gives us some Generic base classes, as well as a default concrete implementation for each. For example, Identity.EntityFramework gives us the following generic base implementation for a class IdentityRole:

Generic Base for IdentityRole:
publicclass IdentityRole<TKey, TUserRole> : IRole<TKey>
where TUserRole : IdentityUserRole<TKey>
{
public TKey Id { get; set; }
publicstring Name { get; set; }
public ICollection<TUserRole> Users { get; set; }
public IdentityRole()
    {
this.Users = new List<TUserRole>();
    }
}

 

As we can see, the above defines IdentityRole in terms of generic type arguments for the key and UserRole, and must implement the interface IRole<TKey>. Note that Identity defines both an IdentityRole class, as well as an IdentityUserRole class, both of which are required to make things work. More on this later.

The Identity team also provides what amounts to a default implementation of this class:

Default Implementation of IdentityRole with non-generic type arguments:
publicclass IdentityRole : IdentityRole<string, IdentityUserRole>
{
public IdentityRole()
    {
base.Id = Guid.NewGuid().ToString();
    }
public IdentityRole(string roleName) : this()
    {
base.Name = roleName;
    }
}

 

Notice how the default implementation class is defined in terms of a string key and a specific implementation of IdentityUserRole?

This means that we can only pass strings as keys, and in fact the IdentityRole model will be defined in our database with a string-type primary key. It also means that the specific, non-generic implementation of IdentityUserRole will be what is passed to the type argument into the base class.

If we steal a page from the previous post, and take a look at the default type definitions provided by Identity 2.0, we find the following (it's not exhaustive, but these are what we will be dealing with later):

Default Identity 2.0 Class Signatures with Default Type Arguments:
publicclass IdentityUserRole 
    : IdentityUserRole<string>
publicclass IdentityRole 
    : IdentityRole<string, IdentityUserRole>
publicclass IdentityUserClaim 
    : IdentityUserClaim<string>
publicclass IdentityUserLogin 
    : IdentityUserLogin<string>
publicclass IdentityUser 
    : IdentityUser<string, IdentityUserLogin, 
        IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
publicclass IdentityDbContext 
    : IdentityDbContext<IdentityUser, IdentityRole, string, 
        IdentityUserLogin, IdentityUserRole, IdentityUserClaim>
publicclass UserStore<TUser> 
    : UserStore<TUser, IdentityRole, string, IdentityUserLogin, 
        IdentityUserRole, IdentityUserClaim>, 
        IUserStore<TUser>, IUserStore<TUser, string>, IDisposable
    where TUser : IdentityUser
publicclass RoleStore<TRole> 
    : RoleStore<TRole, string, IdentityUserRole>, IQueryableRoleStore<TRole>, 
        IQueryableRoleStore<TRole, string>, IRoleStore<TRole, string>, IDisposable
    where TRole : IdentityRole, new()

 

We can see that, starting with IdentityUserRole, the types are defined with string keys, and as importantly, progressively defined in terms of the others. This means that if we want to use integer keys instead of string keys for all of our models (and corresponding database tables), we need to basically implement our own version of the stack above.

Implementing Integer Keys Using Identity 2.0 and the Identity Samples Project

As in previous posts, we are going to use the Identity Samples project as our base for creating an Identity 2.0 MVC application. The Identity team has put together the Identity Samples project primarily (I assume) as a demonstration platform, but in fact it contains everything one might need (after a few tweaks, anyway) in order to build out a complete ASP.NET MVC project using the Identity 2.0 framework.

The concepts we are going to look at here apply equally well if you are building up your own Identity-based application from scratch. The ways and means might vary according to your needs, but in general, much of what we see here will apply whether you are starting from the Identity Samples project as a base, or "rolling your own" so to speak.

The important thing to bear in mind is that the generic base types and interfaces provided by Identity framework allow great flexibility, but also introduced complexity related to the dependencies introduced by the generic type arguments. In particular, the type specified as the key for each model must propagate through the stack, or the compiler gets angry.

Getting Started - Installing the Identity Samples Project

The Identity Samples project is available on Nuget. First, create an empty ASP.NET Web Project (It is important that you use the "Empty" template here, not MVC, not Webforms, EMPTY). Then open the Package Manager console and type:

Install Identity Samples from the Package Manager Console:
PM> Install-Package Microsoft.AspNet.Identity.Samples -Pre

 

This may take a minute or two to run. When complete, your will see a basic ASP.NET MVC project in the VS Solution Explorer. Take a good look around the Identity 2.0 Samples project, and become familiar with what things are and where they are at.

Re-Engineering the Basic Identity Models

To get started, we need to re-engineer the basic model classes defined in the Identity Samples project, as well as add a few new ones. Because Identity Samples uses string-based keys for entity models, the authors, in many cases get away with depending upon the default class implementations provided by the framework itself. Where they extend, they extend from the default classes, meaning the string-based keys are still baked in to the derived classes.

Since we want to use integer keys for all of our models, we get to provide our own implementations for most of the models.

In many cases, this isn't as bad as it sounds. For example, there are a handful of model classes we need only define in terms of the generic arguments, and from there the base class implementation does the rest of the work.

NOTE: As we proceed to modify/add new classes here, the error list in Visual Studio will begin to light up like a Christmas tree until we are done. Leave that be for the moment. If we do this correctly, there should be no errors left when we finish. IF there are, they will help us find things we missed.

In the Models => IdentityModels.cs file, we find the model classes used by the Identity Samples application. To get started, we are going to add our own definitions for IndentityUserLogin, IdentityUserClaim, and IdentityUserRole. The Identity Samples project simply depended upon the default framework implementations for these classes, and we need our own integer based versions. Add the following to the IdentityModels.cs file:

Integer-Based Definitions for UserLogin, UserClaim, and UserRole:
publicclass ApplicationUserLogin : IdentityUserLogin<int> { }
publicclass ApplicationUserClaim : IdentityUserClaim<int> { }
publicclass ApplicationUserRole : IdentityUserRole<int> { }

 

Now, with that out of the way, we can define our own implementation of IdentityRole. The Samples project also depended upon the framework version for IdentityRole, and we are going to provide our own again. This time, though, there's a little more to it:

Integer-Based Definition for IdentityRole:
publicclass ApplicationRole : IdentityRole<int, ApplicationUserRole>, IRole<int>
{
publicstring Description { get; set; }
public ApplicationRole() { }
public ApplicationRole(string name)
        : this()
    {
this.Name = name;
    }
public ApplicationRole(string name, string description)
        : this(name)
    {
this.Description = description;
    }
}

 

Notice above, we have defined ApplicationRole in terms of an integer key, and also in terms of our custom class ApplicationUserRole? This is important, and will continue on up the stack as we re-implement the Identity classes we need for the Identity Samples project to run as expected.

Next, we are going to modify the existing definition for ApplicationUser. Currently, the IdentitySamples.cs file includes a fairly simple definition for ApplicationUser which derives from the default IdentityUser class provided by the framework, which requires no type arguments because they have already been provided in the default implementation. We need to basically re-define ApplicationUser starting from the ground up.

The existing ApplicationUser class in the IdentityModels.cs file looks like this:

Existing ApplicationUser Class in IdentityModels.cs:
publicclass ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> 
        GenerateUserIdentityAsync(UserManager<ApplicationUser> manager)
    {
        var userIdentity = await manager
            .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
    }
}

 

We need to replace the above in its entirety with the following:

Custom Implementation for ApplicationUser:
publicclass ApplicationUser 
: IdentityUser<int, ApplicationUserLogin, 
    ApplicationUserRole, ApplicationUserClaim>, IUser<int>
{
public async Task<ClaimsIdentity>
        GenerateUserIdentityAsync(UserManager<ApplicationUser, int> manager)
    {
        var userIdentity = await manager
            .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
    }
}

 

Once again, instead of deriving from the default Identity framework implementation for IdentityUser, we have instead used the generic base, and provided our own custom type arguments. Also again, we have defined our custom ApplicationUser in terms of an integer key, and our own custom types.

Modified Application Db Context

Also in the IdentityModels.cs file is an ApplicationDbContext class.

Now that we have built out the basic models we are going to need, we also need to re-define the ApplicationDbContext in terms of these new models. As previously, the existing ApplicationDbContext used in the Identity Samples application is expressed only in terms of ApplicationUser, relying (again) upon the default concrete implementation provided by the framework.

If we look under the covers, we find the ApplicationDbContext<ApplicationUser> actually inherits from IdentityDbContext<ApplicationUser>, which in turn is derived from:

IdentityDbContext<TUser, IdentityRole, string, IdentityUserLogin,
    IdentityUserRole, IdentityUserClaim>
    where TUser : Microsoft.AspNet.Identity.EntityFramework.IdentityUser

In other words, we once again have a default concrete implementation which is defined in terms of the other default framework types, all of which further depend upon a string-based key.

In order to define a DbContext which will work with our new custom types, we need to express our concrete class in terms of integer keys, and our own custom derived types.

Replace the existing ApplicationDbContext code with the following:

Modified ApplicationDbContext:
publicclass ApplicationDbContext 
    : IdentityDbContext<ApplicationUser, ApplicationRole, int, 
    ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
publicstatic ApplicationDbContext Create()
    {
returnnew ApplicationDbContext();
    }
}

 

Once again, we have now expressed ApplicationDbContext in terms of our own custom types, all of which use an integer key instead of a string.

Custom User and Role Stores

I am willing to bet that if you take a look at the Visual Studio Error Window right now, it is likely a block of what seems to be endless red error indicators. As mentioned previously, that's fine for now - ignore it.

Identity framework defines the notion of User and Role stores for accessing user and role information. As with most everything else to this point, the default framework implementations for UserStore and RoleStore are defined in terms of the other default classes we have seen to this point - in other words, they won't work with our new custom classes. We need to express a custom User store, and a custom Role store, in terms of integer keys and our own custom classes.

Add the following to the IdentityModels.cs file:

Adding a Custom User Store:
publicclass ApplicationUserStore : 
        UserStore<ApplicationUser, ApplicationRole, int,
        ApplicationUserLogin, ApplicationUserRole, 
        ApplicationUserClaim>, IUserStore<ApplicationUser, int>, 
        IDisposable
    {
public ApplicationUserStore() : this(new IdentityDbContext())
        {
base.DisposeContext = true;
        }
public ApplicationUserStore(DbContext context)
            : base(context)
        {
        }
    }
publicclass ApplicationRoleStore 
        : RoleStore<ApplicationRole, int, ApplicationUserRole>, 
        IQueryableRoleStore<ApplicationRole, int>, 
        IRoleStore<ApplicationRole, int>, IDisposable
    {
public ApplicationRoleStore()
            : base(new IdentityDbContext())
        {
base.DisposeContext = true;
        }
public ApplicationRoleStore(DbContext context)
            : base(context)
        {
        }
    }

 

Re-Engineering Identity Configuration Classes

The Identity Samples project includes a file named App_Start => IdentityConfig.cs. In this file is a bunch of code which basically configures the Identity System for use in your application. The changes we introduced on our IdentityModels.cs file will cause issues here (and basically, throughout the application) until they are addressed in the client code.

In most cases, we will either be replacing a reference to a default Identity class with one of our new custom classes, and/or calling method overrides which allow the passing of custom type arguments.

In the IdentityConfig.cs file, we find an ApplicationUserManager class, which contains code commonly called by our application to, well, manage users and behaviors. we will replace the existing code with the following, which essentially expresses ApplicationUserManager in terms of integer keys, and our new custom UserStore. If you look closely, we have added an int type argument to many of the method calls.

Customized ApplicationUserManager Class:
// *** PASS IN TYPE ARGUMENT TO BASE CLASS:
publicclass ApplicationUserManager : UserManager<ApplicationUser, int>
{
// *** ADD INT TYPE ARGUMENT TO CONSTRUCTOR CALL:
public ApplicationUserManager(IUserStore<ApplicationUser, int> store)
        : base(store)
    {
    }
publicstatic ApplicationUserManager Create(
        IdentityFactoryOptions<ApplicationUserManager> options,
        IOwinContext context)
    {
// *** PASS CUSTOM APPLICATION USER STORE AS CONSTRUCTOR ARGUMENT:
        var manager = new ApplicationUserManager(
new ApplicationUserStore(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
        manager.UserValidator = new UserValidator<ApplicationUser, int>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
// Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
// Configure user lockout defaults
        manager.UserLockoutEnabledByDefault = true;
        manager.DefaultAccountLockoutTimeSpan = TimeSpan.FromMinutes(5);
        manager.MaxFailedAccessAttemptsBeforeLockout = 5;
// Register two factor authentication providers. 
// This application uses Phone and Emails as a step of receiving a 
// code for verifying the user You can write your own provider and plug in here.
// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
        manager.RegisterTwoFactorProvider("PhoneCode", 
new PhoneNumberTokenProvider<ApplicationUser, int>
        {
            MessageFormat = "Your security code is: {0}"
        });
// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
        manager.RegisterTwoFactorProvider("EmailCode", 
new EmailTokenProvider<ApplicationUser, int>
        {
            Subject = "SecurityCode",
            BodyFormat = "Your security code is {0}"
        });
        manager.EmailService = new EmailService();
        manager.SmsService = new SmsService();
        var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
        {
// *** ADD INT TYPE ARGUMENT TO METHOD CALL:
            manager.UserTokenProvider =
new DataProtectorTokenProvider<ApplicationUser, int>(
                    dataProtectionProvider.Create("ASP.NET Identity"));
        }
return manager;
    }
}

 

That's a lot of code there. Fortunately, modifying the ApplicationRoleManager class is not such a big deal. We're essentially doing the same thing - expressing ApplicationRoleManager in terms of integer type arguments, and our custom classes.

Replace the ApplicationRoleManager code with the following:

Customized ApplicationRoleManager Class:
// PASS CUSTOM APPLICATION ROLE AND INT AS TYPE ARGUMENTS TO BASE:
publicclass ApplicationRoleManager : RoleManager<ApplicationRole, int>
{
// PASS CUSTOM APPLICATION ROLE AND INT AS TYPE ARGUMENTS TO CONSTRUCTOR:
public ApplicationRoleManager(IRoleStore<ApplicationRole, int> roleStore)
        : base(roleStore)
    {
    }
// PASS CUSTOM APPLICATION ROLE AS TYPE ARGUMENT:
publicstatic ApplicationRoleManager Create(
        IdentityFactoryOptions<ApplicationRoleManager> options, IOwinContext context)
    {
returnnew ApplicationRoleManager(
new ApplicationRoleStore(context.Get<ApplicationDbContext>()));
    }
}

 

Modify The Application Database Initializer and Sign-in Manager

The ApplicationDbInitializer class is what manages the creation and seeding of the backing database for our application. In this class we create a basic admin role user, and set up additional items such as the Email and SMS messaging providers.

The only thing we need to change here is where we initialize an instance of ApplicationRole. In the existing code, the ApplicationDbInitializer class instantiates an instance of IdentityRole, and we need to create an instance of our own ApplicationRole instead.

Replace the existing code with the following, or make the change highlighted below:

Modify the ApplicationDbInitializer Class:
publicclass ApplicationDbInitializer : DropCreateDatabaseIfModelChanges<ApplicationDbContext> 
{
protectedoverridevoid Seed(ApplicationDbContext context) {
        InitializeIdentityForEF(context);
base.Seed(context);
    }
//Create User=Admin@Admin.com with password=Admin@123456 in the Admin role        
publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db) {
        var userManager = HttpContext.Current.GetOwinContext().GetUserManager<ApplicationUserManager>();
        var roleManager = HttpContext.Current.GetOwinContext().Get<ApplicationRoleManager>();
conststring name = "admin@example.com";
conststring password = "Admin@123456";
conststring roleName = "Admin";
//Create Role Admin if it does not exist
        var role = roleManager.FindByName(roleName);
if (role == null) {
// *** INITIALIZE WITH CUSTOM APPLICATION ROLE CLASS:
            role = new ApplicationRole(roleName);
            var roleresult = roleManager.Create(role);
        }
        var user = userManager.FindByName(name);
if (user == null) {
            user = new ApplicationUser { UserName = name, Email = name };
            var result = userManager.Create(user, password);
            result = userManager.SetLockoutEnabled(user.Id, false);
        }
// Add user admin to Role Admin if not already added
        var rolesForUser = userManager.GetRoles(user.Id);
if (!rolesForUser.Contains(role.Name)) {
            var result = userManager.AddToRole(user.Id, role.Name);
        }
    }
}

 

Fixing up the ApplicationSignInManager is even more simple. Just change the string type argument in the class declaration to int:

Modify the ApplicationSignInManager Class:
// PASS INT AS TYPE ARGUMENT TO BASE INSTEAD OF STRING:
publicclass ApplicationSignInManager : SignInManager<ApplicationUser, int>
{
public ApplicationSignInManager(
        ApplicationUserManager userManager, IAuthenticationManager authenticationManager) : 
base(userManager, authenticationManager) { }
publicoverride Task<ClaimsIdentity> CreateUserIdentityAsync(ApplicationUser user)
    {
return user.GenerateUserIdentityAsync((ApplicationUserManager)UserManager);
    }
publicstatic ApplicationSignInManager Create(
     IdentityFactoryOptions<ApplicationSignInManager> options, IOwinContext context)
    {
returnnew ApplicationSignInManager(context.GetUserManager<ApplicationUserManager>(), context.Authentication);
    }
}

 

Cookie Authentication Configuration

In the file App_Start => Startup.Auth there is a partial class definition, Startup. in the single method call defined in the partial class, there is a call to app.UseCookieAuthentication(). Now that our application is using integers as keys instead of strings, we need to make a modification to the way the CookieAuthenticationProvider is instantiated.

The existing call to app.UseCookieAuthentication (found smack in the middle of the middle of the ConfigureAuth() method) needs to be modified. Where the code calls OnVlidateIdentity the existing code passes ApplicationUserManager and ApplicationUser as type arguments. What is not obvious is that this is an override which assumes a third, string type argument for the key (yep - we're back to that whole string keys thing again).

We need to change this code to call another override, which accepts a third type argument, and pass it an int argument.

The existing code looks like this:

Existing Call to app.UseCookieAuthentication:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a 
// password or add an external login to your account.  
        OnValidateIdentity = SecurityStampValidator
            .OnValidateIdentity<ApplicationUserManager, ApplicationUser>(
                validateInterval: TimeSpan.FromMinutes(30),
                regenerateIdentity: (manager, user) 
                    => user.GenerateUserIdentityAsync(manager))
    }
});

 

We need to modify this code in a couple of non-obvious ways. First, as mentioned above, we need to add a third type argument specifying that TKey is an int.

Less obvious is that we also need to change the name of the second argument from regenerateIdentity to regenerateIdentityCallback. Same argument, but different name in the overload we are using.

Also less than obvious is the third Func we need to pass into the call as getUserIdCallback. Here, we need to retreive a user id from a claim, which stored the Id as a string. We need to parse the result back into an int.

Replace the existing code above with the following:

Modified Call to app.UseCookieAuthentication:
app.UseCookieAuthentication(new CookieAuthenticationOptions
{
    AuthenticationType = DefaultAuthenticationTypes.ApplicationCookie,
    LoginPath = new PathString("/Account/Login"),
    Provider = new CookieAuthenticationProvider
    {
// Enables the application to validate the security stamp when the user logs in.
// This is a security feature which is used when you change a 
// password or add an external login to your account.  
        OnValidateIdentity = SecurityStampValidator
// ADD AN INT AS A THIRD TYPE ARGUMENT:
            .OnValidateIdentity<ApplicationUserManager, ApplicationUser, int>(
                validateInterval: TimeSpan.FromMinutes(30),
// THE NAMED ARGUMENT IS DIFFERENT:
                regenerateIdentityCallback: (manager, user) 
                    => user.GenerateUserIdentityAsync(manager),
// Need to add THIS line because we added the third type argument (int) above:
                    getUserIdCallback:  (claim) => int.Parse(claim.GetUserId()))
    }
});

 

With that, most of the Identity infrastructure is in place. Now we need to update a few things within our application.

Update Admin View Models

The Models => AdminViewModels.cs file contains  class definitions for a RolesAdminViewModel and a UsersAdminViewModel. In both cases, we need to change the type of the Id property from string to int:

Modify the Admin View Models:
publicclass RoleViewModel
{
// Change the Id type from string to int:
publicint Id { get; set; }
    [Required(AllowEmptyStrings = false)]
    [Display(Name = "RoleName")]
publicstring Name { get; set; }
}
publicclass EditUserViewModel
{
// Change the Id Type from string to int:
publicint Id { get; set; }
    [Required(AllowEmptyStrings = false)]
    [Display(Name = "Email")]
    [EmailAddress]
publicstring Email { get; set; }
public IEnumerable<SelectListItem> RolesList { get; set; }
}

 

Update Controller Method Parameter Arguments

A good many of the controller action methods currently expect an id argument of type string. We need to go through all of the methods in our controllers and change the type of the id argument from string to int.

In each of the following controllers, we need to change the existing Id from string to int as shown for the action methods indicated (we're only showing the modified method signatures here):

Account Controller:
public async Task<ActionResult> ConfirmEmail(int userId, string code)

 

Roles Admin Controller:
public async Task<ActionResult> Edit(int id)
public async Task<ActionResult> Details(int id)
public async Task<ActionResult> Delete(int id)
public async Task<ActionResult> DeleteConfirmed(int id, string deleteUser)

 

Users Admin Controller:
public async Task<ActionResult> Details(int id)
public async Task<ActionResult> Edit(int id)
public async Task<ActionResult> Delete(int id)
public async Task<ActionResult> DeleteConfirmed(int id)

 

Update the Create Method on Roles Admin Controller

Anywhere we are creating a new instance of a Role, we need to make sure we are using our new ApplicationRole instead of the default IdentityRole. Specifically, in the Create() method of the RolesAdminController:

Instantiate a new ApplicationRole Instead of IdentityRole:
[HttpPost]
public async Task<ActionResult> Create(RoleViewModel roleViewModel)
{
if (ModelState.IsValid)
    {
// Use ApplicationRole, not IdentityRole:
        var role = new ApplicationRole(roleViewModel.Name);
        var roleresult = await RoleManager.CreateAsync(role);
if (!roleresult.Succeeded)
        {
            ModelState.AddModelError("", roleresult.Errors.First());
return View();
        }
return RedirectToAction("Index");
    }
return View();
}

 

Add Integer Type Argument to GetUserId() Calls

If we take a look at our Error list now, we see the preponderance of errors are related to calls to User.Identity.GetUserId(). If we take a closer look at this method, we find that once again, the default version of GetUserId() returns a string, and that there is an overload which accepts a type argument which determines the return type.

Sadly, calls to GetUserId() are sprinkled liberally throughout ManageController, and a few places in AccountController as well. We need to change all of the calls to reflect the proper type argument, and the most efficient way to do this is an old fashioned Find/Replace.

Fortunately, you can use Find/Replace for the entire document on both ManageController and AccountController, and get the whole thing done in one fell swoop. Hit Ctrl + H, and in the "Find" box, enter the following:

Find all instances of:
Identity.GetUserId()

 

Replace with:
Identity.GetUserId<int>()

 

If we've done this properly, most of the glaring red errors in our error list should now be gone. There are a few stragglers, though. In these cases, we need to counter-intuitively convert the int Id back into a string.

Return a String Where Required

There are a handful of methods which call to GetUserId(), but regardless of the type the Id represents (in our case, now, an int) want a string representation of the Id passed as the argument. All of these methods are found on ManageController, and in each case, we just add a call to .ToString().

First, in the Index() method of ManageController, we find a call to AuthenticationManager.TwoFactorBrowserRemembered() . Add the call to .ToString() after the call to GetUserId():

Add Call to ToString() to TwoFactorBrowserRemembered:
public async Task<ActionResult> Index(ManageMessageId? message)
{
    ViewBag.StatusMessage =
        message == ManageMessageId.ChangePasswordSuccess ? 
"Your password has been changed."
        : message == ManageMessageId.SetPasswordSuccess ? 
"Your password has been set."
        : message == ManageMessageId.SetTwoFactorSuccess ? 
"Your two factor provider has been set."
        : message == ManageMessageId.Error ? 
"An error has occurred."
        : message == ManageMessageId.AddPhoneSuccess ? 
"The phone number was added."
        : message == ManageMessageId.RemovePhoneSuccess ? 
"Your phone number was removed."
        : "";
    var model = new IndexViewModel
    {
        HasPassword = HasPassword(),
        PhoneNumber = await UserManager.GetPhoneNumberAsync(User.Identity.GetUserId<int>()),
        TwoFactor = await UserManager.GetTwoFactorEnabledAsync(User.Identity.GetUserId<int>()),
        Logins = await UserManager.GetLoginsAsync(User.Identity.GetUserId<int>()),
// *** Add .ToString() to call to GetUserId():
        BrowserRemembered = await AuthenticationManager
            .TwoFactorBrowserRememberedAsync(User.Identity.GetUserId<int>().ToString())
    };
return View(model);
}

 

Similarly, do the same for the RememberBrowser method, also on ManageController:

Add Call to ToString() to RememberBrowser Method:
[HttpPost]
public ActionResult RememberBrowser()
{
    var rememberBrowserIdentity = AuthenticationManager
        .CreateTwoFactorRememberBrowserIdentity(
// *** Add .ToString() to call to GetUserId():
            User.Identity.GetUserId<int>().ToString());
    AuthenticationManager.SignIn(
new AuthenticationProperties { IsPersistent = true }, 
        rememberBrowserIdentity);
return RedirectToAction("Index", "Manage");
}

 

Lastly,the same for the LinkLogin() and LinkLoginCallback() methods:

Add Call to ToString() to LinkLogin():
[HttpPost]
[ValidateAntiForgeryToken]
public ActionResult LinkLogin(string provider)
{
returnnew AccountController
        .ChallengeResult(provider, Url.Action("LinkLoginCallback", "Manage"), 
// *** Add .ToString() to call to GetUserId():
            User.Identity.GetUserId<int>().ToString());
}

 

Add Call to ToString() to LinkLoginCallback():
public async Task<ActionResult> LinkLoginCallback()
{
    var loginInfo = await AuthenticationManager
        .GetExternalLoginInfoAsync(XsrfKey, User.Identity.GetUserId<int>().ToString());
if (loginInfo == null)
    {
return RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
    }
    var result = await UserManager
// *** Add .ToString() to call to GetUserId():
        .AddLoginAsync(User.Identity.GetUserId<int>().ToString(), loginInfo.Login);
return result.Succeeded ? RedirectToAction("ManageLogins") 
        : RedirectToAction("ManageLogins", new { Message = ManageMessageId.Error });
}

 

With that, we have addressed most of the egregious issues, and we basically taken a project built against a model set using all string keys and converted it to using integers. The integer types will be propagated as auto-incrementing integer primary keys in the database backend as well.

But there are still a few things to clean up.

Fix Null Checks Against Integer Types

Scattered throughout the primary identity controllers are a bunch of null checks against the Id values received as arguments in the method calls. If you rebuild the project, the error list window in Visual Studio should now contain a bunch of the yellow "warning" items about this very thing.

You can handle this in your preferred manner, but for me, I prefer to check for a positive integer value. We'll look at the Details() method from the UserAdminController as an example, and you can take it from there.

The existing code in the Details() method looks like this:

Existing Details() Method from UserAdminController:
public async Task<ActionResult> Details(int id)
{
if (id == null)
    {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
    }
    var user = await UserManager.FindByIdAsync(id);
    ViewBag.RoleNames = await UserManager.GetRolesAsync(user.Id);
return View(user);
}

 

In the above, we can see that previously, the code checked for a null value for the (formerly) string-typed Id argument. Now that we are receiving an int, the check for null is meaningless. Instead, we want to check for a positive integer value. If the check is true, then we want to process accordingly. Otherwise, we want to return the BadRequest result.

In other words, we need to invert the method logic. Previously, if the conditional evaluated to true, we wanted to return the error code. Now, is the result is true, we want to proceed, and only return the error result if the conditional is false. So we're going to swap our logic around.

Replace the code with the following:

Modified Details() Method with Inverted Conditional Logic:
public async Task<ActionResult> Details(int id)
{
if (id > 0)
    {
// Process normally:
        var user = await UserManager.FindByIdAsync(id);
        ViewBag.RoleNames = await UserManager.GetRolesAsync(user.Id);
return View(user);
    }
// Return Error:
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
}

 

We can do something similar for the other cases in UserAdminController, RolesAdminController, and AccountController. Think through the logic carefully, and all should be well.

Update Roles Admin Views

Several of the View Templates currently use the default IdentityRole model instead of our new, custom ApplicationRole. We need to update the Views in Views => RolesAdmin to reflect our new custom model.

The Create.cshtml and Edit.cshtml Views both depend upon the RoleViewModel, which is fine. However, the Index.cshtml, Details.cshtml, and Delete.cshtml Views all currently refer to IdentityRole. Update all three as follows

The Index.cshtml View currently expects an IEnumerable<IdentityRole> . We need to change this to expect an IEnumerable<ApplicationRole> . Note that we need to include the project Models namespace as well:

Update the RolesAdmin Index.cshtml View:
@model IEnumerable<IdentitySample.Models.ApplicationRole>
// ... All the view code ...

 

All we need to change here is the first line, so I omitted the rest of the View code.

Similarly, we need to update the Details.cshtml and Delete.cshtml Views to expect ApplicationRole instead of IdentityRole. Change the first line in each to match the following:

Update the Details.cshtml and Delete.cshtml Views:
@model IdentitySample.Models.ApplicationRole
// ... All the view code ...

 

Obviously, if your default project namespace is something other than IdentitySamples, change the above to suit.

Additional Extensions are Easy Now

Now that we have essentially re-implemented most of the Identity object models with our own derived types, it is easy to add custom properties to the ApplicationUser and/.or ApplicationRole models. All of our custom types already depend upon each other in terms of the interrelated generic type arguments, so we are free to simply add what properties we wish to add, and then update our Controllers, ViewModels, and Views accordingly.

To do so, review the previous post on extending Users and Roles, but realize all of the type structure stuff is already done. Review that post just to see what goes on with updating the Controllers, Views, and ViewModels.

A Note on Security

The basic Identity Samples application is a great starting point for building out your own Identity 2.0 application. However, realize that, as a demo, there are some things built in that should not be present in production code. For example, the database initialization currently includes hard-coded admin user credentials.

Also, the Email confirmation and two-factor authentication functionality currently circumvents the actual confirmation and two-factor process, by including links on each respective page which short-circuit the process.

The above items should be addressed before deploying an actual application based upon the Identity Samples project.

Wrapping Up

We've taken a rather exhaustive look at how to modify the Identity Samples application to use integer keys instead of strings. Along the way, we (hopefully) gained a deeper understanding of the underlying structure in an Identity 2.0 based application. There's a lot more there to learn, but this is a good start.

Additional Resources and Items of Interest

ASP.NET Identity 2.0: Extensible Template Projects

$
0
0

Authorized-240We've spent the last few posts looking at various customizations of the basic Identity Samples project. I decided to take what we've learned so far and create a general, easily extensible template project, so that we don't have to futz about nearly from scratch every time we want some customization of our Identity models.

We've been working with the Identity Samples project as a starting point, playing with and building upon the work of the Identity team in order to explore the Identity 2.0 framework. With the Identity Samples project, the Identity team has provided a reasonable jumping off point, but it is far from a one-size fits all solution.

 

Image by Tom Magliery  | Some Rights Reserved

In ASP.NET Identity 2.0: Customizing Users and Roles we looked at some basic customization of the IdentityUser and IdentityRole models. With ASP.NET Identity 2.0 Extending Identity Models and Using Integer Keys Instead of Strings we went several steps further, and basically needed to re-implement all of the basic Identity model classes from their generic base classes, in order to use integer keys instead of the default string-based keys in the original Identity Samples project.

I've applied the concepts we covered in those two posts to build out a pair of template projects from which extending any of the Identity model classes is straightforward.

ASP.NET Identity 2.0 Extensible Project Templates on Github

I've created two repos on Github, one for a template project with string keys (adhering to the Identity team's decision to use string-based keys as the default), and another which uses integer keys.

The choice of key type has significantly far-reaching impact upon the project code base that it makes more sense to use a separate template for each.

To get a better feel for the how and why this was necessary, see the previous posts:

Extending the Basic Classes

So long as you are comfortable with your choice of Key type, you can now easily extend any of the core Identity model classes. If we take a look at the Models => IdentityModels.cs file we find the basic classes we need. Since they are all now defined in terms of each other with respect to the generic type arguments, we can easily add al properties or methods to any of the classes found here without throwing the compiler into a tizzy.

A quick look at the code for the string-based key version of the project shows us where we can add our own properties or methods and extend the basic classes:

The Basic Identity Models, Extended:
// You will not likely need to customize there, but it is necessary/easier to create our own 
// project-specific implementations, so here they are:
publicclass ApplicationUserLogin : IdentityUserLogin<string> { }
publicclass ApplicationUserClaim : IdentityUserClaim<string> { }
publicclass ApplicationUserRole : IdentityUserRole<string> { }
// Must be expressed in terms of our custom Role and other types:
publicclass ApplicationUser 
    : IdentityUser<string, ApplicationUserLogin, 
    ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationUser()
    {
this.Id = Guid.NewGuid().ToString();
// Add any custom User properties/code here
    }
public async Task<ClaimsIdentity>
        GenerateUserIdentityAsync(ApplicationUserManager manager)
    {
        var userIdentity = await manager
            .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
    }
}
// Must be expressed in terms of our custom UserRole:
publicclass ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
public ApplicationRole() 
    {
this.Id = Guid.NewGuid().ToString();
    }
public ApplicationRole(string name)
        : this()
    {
this.Name = name;
    }
// Add any custom Role properties/code here
}
// Must be expressed in terms of our custom types:
publicclass ApplicationDbContext 
    : IdentityDbContext<ApplicationUser, ApplicationRole, 
string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
publicstatic ApplicationDbContext Create()
    {
returnnew ApplicationDbContext();
    }
// Add additional items here as needed
}
// Most likely won't need to customize these either, but they were needed because we implemented
// custom versions of all the other types:
publicclass ApplicationUserStore 
    :UserStore<ApplicationUser, ApplicationRole, string,
        ApplicationUserLogin, ApplicationUserRole, 
        ApplicationUserClaim>, IUserStore<ApplicationUser, string>, 
    IDisposable
{
public ApplicationUserStore()
        : this(new IdentityDbContext())
    {
base.DisposeContext = true;
    }
public ApplicationUserStore(DbContext context)
        : base(context)
    {
    }
}
publicclass ApplicationRoleStore
: RoleStore<ApplicationRole, string, ApplicationUserRole>,
IQueryableRoleStore<ApplicationRole, string>,
IRoleStore<ApplicationRole, string>, IDisposable
{
public ApplicationRoleStore()
        : base(new IdentityDbContext())
    {
base.DisposeContext = true;
    }
public ApplicationRoleStore(DbContext context)
        : base(context)
    {
    }
}

 

Since we've already covered most of what went into this, and why, we won't here.

Feel free to clone/fork away, and if you find any bugs, feel free to open an issue, shoot me a pull request, or both!

Additional Resources and Items of Interest

ASP.NET Identity 2.0: Implementing Group-Based Permissions Management

$
0
0

authorized-personel-onlyEarlier this year we looked at Implementing Group-Based Permissions Management using the ASP.NET Identity 1.0 framework. The objective of that project was to gain a little more granular control of application authorization, by treating the now-familiar Identity Role as more of a "permission" which could be granted to members of a group.

With the release of Identity 2.0 in March 2014 came some breaking changes, and a significant expansion of features and complexity. Identity 2.0 is now a full-grown authorization and authentication system for ASP.NET. However, the added features came at a price. There is a lot to get your mind around to start using Identity 2.0 effectively.

 

Image by Thomas Hawk  |  Some Rights Reserved

In previous articles, we have covered some of the basics:

The code we used to implement Group-based permissions under Identity 1.0 breaks in moving to Identity 2.0. Simply too much has changed between the two versions to make a clean, easy upgrade. In this article, we will revisit the Group-Based Permission idea, and implement the concept under the Identity 2.0 framework.

A Quick Review

Under the familiar ASP.NET Identity structure, Users are assigned one or more Roles. Traditionally, access to certain application functionality is governed, through the use of the [Authorize] attribute, by restricting access to certain controllers or controller methods to members of certain roles. This is effective as far as it goes, but does not lend itself to efficient management of more granular access permissions.

The Group-Based Permissions project attempts to find a middle ground between the complexities of a full-blown, Claims-based authorization scheme, and the simplicity (and limitations) of the authorization offered by Identity out of the box. Here, we will implement another familiar idea - Users are assigned to one or more Groups. Groups are granted set of permissions corresponding to the various authorizations required by group members to perform their function.

I discussed the overall concept, and security concerns in the previous article, so I won't rehash all that here. For reference, the following topics might be worth a quick visit:

In this article, we will implement a similar structure using Identity 2.0.

Getting Started - Clone a Handy Project Template

We're going to start with a handy, ready-to-customize project template based on the Identity Samples project created by the Identity team. I've used what we've learned in the past few posts to create a ready to extend project which can be cloned from my Github account (and hopefully soon, from Nuget!).

Or, Clone the Finished Source for this Project

Or, if you like, you can clone the source for the completed Group Permissions project, also on Github:

If you are starting with the template project and following along, it's probably best to rename the directory and project files to reflect the current effort. if you do this, make sure to also update the Web.Config file as well. You may want to update the connection string so that when the back-end database is created, the name reflects the Group Permissions application.

You MUST update the appSettings =>owin:AppStartup element so that the startup assembly name matches the name you provide in Project => Properties => Assembly Name. In my case, I set my connection string and owin:appStartup as follows:

Update Web.Config Connection String and owin:appStartup elements:
<connectionStrings>
<addname="DefaultConnection"
connectionString="Data Source=(LocalDb)\v11.0;
           Initial Catalog=AspNetIdentity2GroupPermissions-5;
           Integrated Security=SSPI"
providerName="System.Data.SqlClient"/>
</connectionStrings>
<appSettings>
<addkey="owin:AppStartup"value="IdentitySample.Startup,AspNetIdentity2GRoupPermissions"/>
<addkey="webpages:Version"value="3.0.0.0"/>
<addkey="webpages:Enabled"value="false"/>
<addkey="ClientValidationEnabled"value="true"/>
<addkey="UnobtrusiveJavaScriptEnabled"value="true"/>
</appSettings></configuration>

 

Adding the Group Models

Let's get right to it. We can start by adding some new models to the Models => IdentityModels.cs file. We will be defining three different classes here: ApplicationGroup, which is the core Group model, as well as two additional classes which map ApplicationUser and ApplicationRole as collections within ApplicationGroup. Add the following to the IdentityModels.cs file:

The ApplicationGroup and Related Classes:
publicclass ApplicationGroup
{
public ApplicationGroup()
    {
this.Id = Guid.NewGuid().ToString();
this.ApplicationRoles = new List<ApplicationGroupRole>();
this.ApplicationUsers = new List<ApplicationUserGroup>();
    }
public ApplicationGroup(string name)
        : this()
    {
this.Name = name;
    }
public ApplicationGroup(string name, string description)
        : this(name)
    {
this.Description = description;
    }
    [Key]
publicstring Id { get; set; }
publicstring Name { get; set; }
publicstring Description { get; set; }
publicvirtual ICollection<ApplicationGroupRole> ApplicationRoles { get; set; }
publicvirtual ICollection<ApplicationUserGroup> ApplicationUsers { get; set; }
}
publicclass ApplicationUserGroup
{
publicstring ApplicationUserId { get; set; }
publicstring ApplicationGroupId { get; set; }
}
publicclass ApplicationGroupRole
{
publicstring ApplicationGroupId { get; set; }
publicstring ApplicationRoleId { get; set; }
}

 

Groups have a many-to-many relationship with both Users, and Roles. One user can belong to zero or more Groups, and one group can have zero or more users. Likewise with roles. A single role can be assigned to zero or more groups, and a single Group can have zero or more roles.

When we need to manage this type of relationship using EntityFramework, we can create what are essentially mapping classes, in this case, ApplicationUserGroup, and ApplicationGroupRole. The way we are doing this is similar to the structure used by the Identity team in defining Users, Roles, and UserRoles. For example, our ApplicationUser class is derived from IdentityUser, which defines a Roles property. Note that the Roles property of IdentityUser is not a collection of IdentityRole object, but instead a collection of IdentityUserRole objects. The difference being, the IdentityUserRole class defines only a UserId property, and a RoleId property.

We are doing the same thing here.We need to allow EF to manage the many-to-many relationships we described above by adding mapping classes between the collections defined on ApplicationGroup, and the domain objects involved in each relationship.

Override OnModelCreating in the DbContext Class

EntityFramework will not figure out our many-to-many relationships on its own, nor will it determine the proper table structures to create in our database. We need to help things along by overriding the OnModelCreating method in the ApplicationDbContext class. Also, we need to add ApplicationGroups as a property on our DbContext so that we can access our Groups from within our application.  Update the ApplicationDbContext class as follows:

Update ApplicationDbContext and Override OnModelCreating:
publicclass ApplicationDbContext
    : IdentityDbContext<ApplicationUser, ApplicationRole,
string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
publicstatic ApplicationDbContext Create()
    {
returnnew ApplicationDbContext();
    }
// Add the ApplicationGroups property:
publicvirtual IDbSet<ApplicationGroup> ApplicationGroups { get; set; }
// Override OnModelsCreating:
protectedoverridevoid OnModelCreating(DbModelBuilder modelBuilder)
    {
// Make sure to call the base method first:
base.OnModelCreating(modelBuilder);
// Map Users to Groups:
        modelBuilder.Entity<ApplicationGroup>()
            .HasMany<ApplicationUserGroup>((ApplicationGroup g) => g.ApplicationUsers)
            .WithRequired()
            .HasForeignKey<string>((ApplicationUserGroup ag) => ag.ApplicationGroupId);
        modelBuilder.Entity<ApplicationUserGroup>()
            .HasKey((ApplicationUserGroup r) => 
new
                { 
                    ApplicationUserId = r.ApplicationUserId, 
                    ApplicationGroupId = r.ApplicationGroupId 
                }).ToTable("ApplicationUserGroups");
// Map Roles to Groups:
        modelBuilder.Entity<ApplicationGroup>()
            .HasMany<ApplicationGroupRole>((ApplicationGroup g) => g.ApplicationRoles)
            .WithRequired()
            .HasForeignKey<string>((ApplicationGroupRole ap) => ap.ApplicationGroupId);
        modelBuilder.Entity<ApplicationGroupRole>().HasKey((ApplicationGroupRole gr) => 
new
            { 
                ApplicationRoleId = gr.ApplicationRoleId, 
                ApplicationGroupId = gr.ApplicationGroupId 
            }).ToTable("ApplicationGroupRoles");
    }
}

 

With these humble beginnings in place, let's run the project, and see if everything works the way we expect.

Running the Project and Confirming Database Creation

If we run the project now, we will be greeted by the standard MVC page. Recall that with the Entity Framework Code-First model, database creation will occur at first data access. In other words, as things stand, we need to log in.

To this point, we haven't added any explicit functionality to our front-end site - when we log in, there will be no evidence that our underlying model has changed. We simply want to see if the site starts up properly, and that the database and table we expect are in fact created.

Once we have run the project and logged in, we should be able to stop, and use  the Visual Studio Server Explorer to see what our database tables look like. We should see something like the following:

Server Explorer with Additional Tables for Groups:

server-explorer-with-group-tables

We see from the above that our ApplicationGroup and related classes are now represented by tables in our back-end database, along with the expected columns and primary keys. So far, so good!

Investigation: Building a Consistent Asynchronous Model Architecture

APS.NET Identity 2.0 offers a fully async model architecture. We are going to do our best to follow the conventions established by the Identity team in building up our Groups management structure, using similar abstractions to create a Group store, and Group Manager with fully async methods. In other words, perhaps we can take a look at how the Identity 2.0 team built the basic UserStore and RoleStore abstractions (including the async methods) and simply model up our own GroupStore along the same lines.

If we take a close look at the structure used by the Identity team to build up the basic UserStore and RoleStore classes within the Identity framework, we find that each are composed around an instance of a class called EntityStore<TEntity> , which wraps the most basic behaviors expected of a persistence store.

For example, if we look inside the RoleStore<TRole, TKey, TUserRole> class defined as part of the Identity 2.0 framework, we find the following:

Decomposing the RoleStore Class:
publicclass RoleStore<TRole, TKey, TUserRole> : 
    IQueryableRoleStore<TRole, TKey>, IRoleStore<TRole, TKey>, IDisposable
    where TRole : IdentityRole<TKey, TUserRole>, new()
    where TUserRole : IdentityUserRole<TKey>, new()
{
privatebool _disposed;
private EntityStore<TRole> _roleStore;
public DbContext Context { get; privateset; }
publicbool DisposeContext {get; set; }
public IQueryable<TRole> Roles
    {
get
        {
returnthis._roleStore.EntitySet;
        }
    }
public RoleStore(DbContext context)
    {
if (context == null)
        {
thrownew ArgumentNullException("context");
        }
this.Context = context;
this._roleStore = new EntityStore<TRole>(context);
    }
publicvirtual async Task CreateAsync(TRole role)
    {
this.ThrowIfDisposed();
if (role == null)
        {
thrownew ArgumentNullException("role");
        }
this._roleStore.Create(role);
        TaskExtensions.CultureAwaiter<int> cultureAwaiter = 
this.Context.SaveChangesAsync().WithCurrentCulture<int>();
        await cultureAwaiter;
    }
publicvirtual async Task DeleteAsync(TRole role)
    {
this.ThrowIfDisposed();
if (role == null)
        {
thrownew ArgumentNullException("role");
        }
this._roleStore.Delete(role);
        TaskExtensions.CultureAwaiter<int> cultureAwaiter = 
this.Context.SaveChangesAsync().WithCurrentCulture<int>();
        await cultureAwaiter;
    }
publicvoid Dispose()
    {
this.Dispose(true);
        GC.SuppressFinalize(this);
    }
protectedvirtualvoid Dispose(bool disposing)
    {
if (this.DisposeContext && disposing && this.Context != null)
        {
this.Context.Dispose();
        }
this._disposed = true;
this.Context = null;
this._roleStore = null;
    }
public Task<TRole> FindByIdAsync(TKey roleId)
    {
this.ThrowIfDisposed();
returnthis._roleStore.GetByIdAsync(roleId);
    }
public Task<TRole> FindByNameAsync(string roleName)
    {
this.ThrowIfDisposed();
return QueryableExtensions
            .FirstOrDefaultAsync<TRole>(this._roleStore.EntitySet, 
                (TRole u) => u.Name.ToUpper() == roleName.ToUpper());
    }
privatevoid ThrowIfDisposed()
    {
if (this._disposed)
        {
thrownew ObjectDisposedException(this.GetType().Name);
        }
    }
publicvirtual async Task UpdateAsync(TRole role)
    {
this.ThrowIfDisposed();
if (role == null)
        {
thrownew ArgumentNullException("role");
        }
this._roleStore.Update(role);
        TaskExtensions.CultureAwaiter<int> cultureAwaiter = 
this.Context.SaveChangesAsync().WithCurrentCulture<int>();
        await cultureAwaiter;
    }
}

 

The code above is interesting, and we will be looking more closely in a bit. For the moment, notice the highlighted item. RoleStore wraps an instance of EntityStore<TRole> . If we follow our noses a little further, we find a definition for EntityStore as well:

The EntityStore Class from Identity 2.0 Framework:
internalclass EntityStore<TEntity>
where TEntity : class
{
public DbContext Context { get; privateset; }
public DbSet<TEntity> DbEntitySet { get; privateset; }
public IQueryable<TEntity> EntitySet
    {
get
        {
returnthis.DbEntitySet;
        }
    }
public EntityStore(DbContext context)
    {
this.Context = context;
this.DbEntitySet = context.Set<TEntity>();
    }
publicvoid Create(TEntity entity)
    {
this.DbEntitySet.Add(entity);
    }
publicvoid Delete(TEntity entity)
    {
this.DbEntitySet.Remove(entity);
    }
publicvirtual Task<TEntity> GetByIdAsync(object id)
    {
returnthis.DbEntitySet.FindAsync(newobject[] { id });
    }
publicvirtualvoid Update(TEntity entity)
    {
if (entity != null)
        {
this.Context.Entry<TEntity>(entity).State = EntityState.Modified;
        }
    }

 

This code is also of great interest, despite its simplicity. Unfortunately, we cannot directly use the EntityStore class within our project. Note the internal modifier in the class declaration - this means EntityStore is only available to classes within the Microsoft.AspNet.Identity.EntityFramework assembly. In other words, we can't consume EntityStore in order to build up our own GroupStore implementation. Instead, we will take the time-honored approach of stealing/copying.

Building an Asynchronous GroupStore

We are going to apply the same conventions used by the Identity team in building out a GroupStore class, and then, in similar fashion, wrap a GroupManager class around THAT, much the same as Identity Framework wraps a RoleManager class around an instance of RoleStore.

But first, we need to deal with the EntityStore problem. in order to properly mimic the structure used to build up RoleStore and UserStore, we need to basically create our own implementation of EntityStore. In our case, we don't need a generically-typed class - we can create a non-generic implementation specific to our needs.

Mimicking EntityStore - Building the GroupStoreBase Class

We can basically steal most of the code from the EntityStore<TEntity> class shown above, and adapt it to suit our needs by removing the generic type arguments for the class itself, and by passing non-generic arguments where needed. Add a class named GroupStoreBase to the Models folder of your project, and then use the following code for the class itself. First, you will need the following using statements a the top of your code file:

Required Assembly References for the GroupStoreBase Class:
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;

 

The GroupStoreBase Class:
publicclass GroupStoreBase
{
public DbContext Context { get; privateset; }
public DbSet<ApplicationGroup> DbEntitySet { get; privateset; }
public IQueryable<ApplicationGroup> EntitySet
    {
get
        {
returnthis.DbEntitySet;
        }
    }
public GroupStoreBase(DbContext context)
    {
this.Context = context;
this.DbEntitySet = context.Set<ApplicationGroup>();
    }
publicvoid Create(ApplicationGroup entity)
    {
this.DbEntitySet.Add(entity);
    }
publicvoid Delete(ApplicationGroup entity)
    {
this.DbEntitySet.Remove(entity);
    }
publicvirtual Task<ApplicationGroup> GetByIdAsync(object id)
    {
returnthis.DbEntitySet.FindAsync(newobject[] { id });
    }
publicvirtual ApplicationGroup GetById(object id)
    {
returnthis.DbEntitySet.Find(newobject[] { id });
    }
publicvirtualvoid Update(ApplicationGroup entity)
    {
if (entity != null)
        {
this.Context.Entry<ApplicationGroup>(entity).State = EntityState.Modified;
        }
    }
}

 

Note the structure here. the GroupStoreBase provides methods for working with a DbSet<ApplicationGroup> , but performs no persistence to the backside database directly. Persistence will be controlled by the next class in our structure, ApplicationGroupStore.

Building the Primary ApplicationGroupStore Class

In following the pattern used by UserStore and RoleStore, we will now build out a GroupStore class, which will be composed around our new GroupStoreBase class. Add another class to the models folder named ApplicationGroupStore, and add the following code:

The ApplicationGroupStore Class:
publicclass ApplicationGroupStore : IDisposable
{
privatebool _disposed;
private GroupStoreBase _groupStore;
public ApplicationGroupStore(DbContext context)
    {
if (context == null)
        {
thrownew ArgumentNullException("context");
        }
this.Context = context;
this._groupStore = new GroupStoreBase(context);
    }
public IQueryable<ApplicationGroup> Groups
    {
get
        {
returnthis._groupStore.EntitySet;
        }
    }
public DbContext Context
    {
get;
privateset;
    }
publicvirtualvoid Create(ApplicationGroup group)
    {
this.ThrowIfDisposed();
if (group == null)
        {
thrownew ArgumentNullException("group");
        }
this._groupStore.Create(group);
this.Context.SaveChanges();
    }
publicvirtual async Task CreateAsync(ApplicationGroup group)
    {
this.ThrowIfDisposed();
if (group == null)
        {
thrownew ArgumentNullException("group");
        }
this._groupStore.Create(group);
        await this.Context.SaveChangesAsync();
    }
publicvirtual async Task DeleteAsync(ApplicationGroup group)
    {
this.ThrowIfDisposed();
if (group == null)
        {
thrownew ArgumentNullException("group");
        }
this._groupStore.Delete(group);
        await this.Context.SaveChangesAsync();
    }
publicvirtualvoid Delete(ApplicationGroup group)
    {
this.ThrowIfDisposed();
if (group == null)
        {
thrownew ArgumentNullException("group");
        }
this._groupStore.Delete(group);
this.Context.SaveChanges();
    }
public Task<ApplicationGroup> FindByIdAsync(string roleId)
    {
this.ThrowIfDisposed();
returnthis._groupStore.GetByIdAsync(roleId);
    }
public ApplicationGroup FindById(string roleId)
    {
this.ThrowIfDisposed();
returnthis._groupStore.GetById(roleId);
    }
public Task<ApplicationGroup> FindByNameAsync(string groupName)
    {
this.ThrowIfDisposed();
return QueryableExtensions
            .FirstOrDefaultAsync<ApplicationGroup>(this._groupStore.EntitySet, 
                (ApplicationGroup u) => u.Name.ToUpper() == groupName.ToUpper());
    }
publicvirtual async Task UpdateAsync(ApplicationGroup group)
    {
this.ThrowIfDisposed();
if (group == null)
        {
thrownew ArgumentNullException("group");
        }
this._groupStore.Update(group);
        await this.Context.SaveChangesAsync();
    }
publicvirtualvoid Update(ApplicationGroup group)
    {
this.ThrowIfDisposed();
if (group == null)
        {
thrownew ArgumentNullException("group");
        }
this._groupStore.Update(group);
this.Context.SaveChanges();
    }
// DISPOSE STUFF: ===============================================
publicbool DisposeContext
    {
get;
set;
    }
privatevoid ThrowIfDisposed()
    {
if (this._disposed)
        {
thrownew ObjectDisposedException(this.GetType().Name);
        }
    }
publicvoid Dispose()
    {
this.Dispose(true);
        GC.SuppressFinalize(this);
    }
protectedvirtualvoid Dispose(bool disposing)
    {
if (this.DisposeContext && disposing && this.Context != null)
        {
this.Context.Dispose();
        }
this._disposed = true;
this.Context = null;
this._groupStore = null;
    }
}

 

Some things to note about the ApplicationGroupStore class. First, notice that this class takes care of all the actual persistence to the backing store, by virtue of calls to .SaveChanges() or .SaveChangesAsync(). Also, we have provided both an async and a synchronous implementation for each of the methods.

However, we're not quite done yet. While the ApplicationGroupStore manages the basics of persistence for Groups, what it does NOT do is handle the complexities introduced by the relationships between Groups, Users, and Roles. Here, we can perform the basic CRUD operations on our groups, but we have no control over the relationships between the classes.

This becomes the job of the ApplicationGroupManager class.

Managing Complex Relationships - The ApplicationGroupManager Class

The relationships between Users, Groups, and Roles, for the sake of our application, are more complex than they might first appear.

Our Users-Groups-Roles structure is actually performing a bit of an illusion. It may appear, when we are done, that Roles will "belong" to groups, and that Users, by virtue of membership in a particular group, gain access to the Roles of that Group. However, what is really going on is that, when a User is assigned to a particular group, our application is then adding that user to each Role within the Group.

This is a subtle, but important distinction.

Let's assume we have an existing Group with two Roles assigned - "CanEditAccount" and "CanViewAccount." Let's further assume that there are three users in this group. Finally, let's say we want to add another (already existing) Role to this group - "CanDeleteAccount." What needs to happen?

  1. We assign the role to the group
  2. We need to add each member or the group to the new role

On the face of it, that is relatively straightforward. However, each User can belong to more than one group. Also, a Role can be assigned to more than one group. What if we want to remove a Role from a group?

  1. Remove each User in the Group from the Role, except when they are also a member of another group which also has that same role
  2. Remove the Role from the Group

This is a little more complicated. A similar situation arises if we wish to remove a User from a Group:

  1. Remove the User from all Roles in the Group, except when the user also belongs to another Group with the same role
  2. Remove the User from the Group

And so on. In order to get the predictable, intuitive behavior from our application which will be expected by the end user, there is more going on than meets the eye.

It will be the job of the ApplicationGroupManager to handle these types of problems for us, and afford a clear API against which our controllers can work between the user and the backside data.

We have created the GroupStore class to handle the basic persistence of Group data, and we have the ApplicationUserManager and ApplicationRoleManager classes to handle the relationships between Users, Roles, and persistence. For the most part, the ApplicationGroupManager's job will mainly be governing the interactions of these three stores, and occasionally the DbContext directly.

We will accomplish this by defining an API which, similar to the Identity base classes UserManager and RoleManager, affords us the intuitive methods we need to deal with Group-based Role management. We will provide both synchronous and asynchronous implementations.

Add another class to the Models folder, and name it ApplicationGroupManager. You will need the following using statements at the top of your code file:

Required Assembly References for ApplicationGroupManager:
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.Owin;
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Threading.Tasks;
using System.Web;

 

Now, add the following code:

The ApplicationGroupManager Class:
publicclass ApplicationGroupManager
{
private ApplicationGroupStore _groupStore;
private ApplicationDbContext _db;
private ApplicationUserManager _userManager;
private ApplicationRoleManager _roleManager;
public ApplicationGroupManager()
    {
        _db = HttpContext.Current
            .GetOwinContext().Get<ApplicationDbContext>();
        _userManager = HttpContext.Current
            .GetOwinContext().GetUserManager<ApplicationUserManager>();
        _roleManager = HttpContext.Current
            .GetOwinContext().Get<ApplicationRoleManager>();
        _groupStore = new ApplicationGroupStore(_db);
    }
public IQueryable<ApplicationGroup> Groups
    {
get
        {
return _groupStore.Groups;
        }
    }
public async Task<IdentityResult> CreateGroupAsync(ApplicationGroup group)
    {
        await _groupStore.CreateAsync(group);
return IdentityResult.Success;
    }
public IdentityResult CreateGroup(ApplicationGroup group)
    {
        _groupStore.Create(group);
return IdentityResult.Success;
    }
public IdentityResult SetGroupRoles(string groupId, paramsstring[] roleNames)
    {
// Clear all the roles associated with this group:
        var thisGroup = this.FindById(groupId);
        thisGroup.ApplicationRoles.Clear();
        _db.SaveChanges();
// Add the new roles passed in:
        var newRoles = _roleManager.Roles.Where(r => roleNames.Any(n => n == r.Name));
foreach(var role in newRoles)
        {
            thisGroup.ApplicationRoles.Add(new ApplicationGroupRole 
            { 
                ApplicationGroupId = groupId, 
                ApplicationRoleId = role.Id 
            });
        }
        _db.SaveChanges();
// Reset the roles for all affected users:
foreach(var groupUser in thisGroup.ApplicationUsers)
        {
this.RefreshUserGroupRoles(groupUser.ApplicationUserId);
        }
return IdentityResult.Success;
    }
public async Task<IdentityResult> SetGroupRolesAsync(
string groupId, paramsstring[] roleNames)
    {
// Clear all the roles associated with this group:
        var thisGroup = await this.FindByIdAsync(groupId);
        thisGroup.ApplicationRoles.Clear();
        await _db.SaveChangesAsync();
// Add the new roles passed in:
        var newRoles = _roleManager.Roles
                        .Where(r => roleNames.Any(n => n == r.Name));
foreach (var role in newRoles)
        {
            thisGroup.ApplicationRoles.Add(new ApplicationGroupRole 
            { 
                ApplicationGroupId = groupId, 
                ApplicationRoleId = role.Id 
            });
        }
        await _db.SaveChangesAsync();
// Reset the roles for all affected users:
foreach (var groupUser in thisGroup.ApplicationUsers)
        {
            await this.RefreshUserGroupRolesAsync(groupUser.ApplicationUserId);
        }
return IdentityResult.Success;
    }
public async Task<IdentityResult> SetUserGroupsAsync(
string userId, paramsstring[] groupIds)
    {
// Clear current group membership:
        var currentGroups = await this.GetUserGroupsAsync(userId);
foreach (var group in currentGroups)
        {
            group.ApplicationUsers
                .Remove(group.ApplicationUsers
                .FirstOrDefault(gr => gr.ApplicationUserId == userId
            ));
        }
        await _db.SaveChangesAsync();
// Add the user to the new groups:
foreach (string groupId in groupIds)
        {
            var newGroup = await this.FindByIdAsync(groupId);
            newGroup.ApplicationUsers.Add(new ApplicationUserGroup 
            { 
                ApplicationUserId = userId, 
                ApplicationGroupId = groupId 
            });
        }
        await _db.SaveChangesAsync();
        await this.RefreshUserGroupRolesAsync(userId);
return IdentityResult.Success;
    }
public IdentityResult SetUserGroups(string userId, paramsstring[] groupIds)
    {
// Clear current group membership:
        var currentGroups = this.GetUserGroups(userId);
foreach(var group in currentGroups)
        {
            group.ApplicationUsers
                .Remove(group.ApplicationUsers
                .FirstOrDefault(gr => gr.ApplicationUserId == userId
            ));
        }
        _db.SaveChanges();
// Add the user to the new groups:
foreach(string groupId in groupIds)
        {
            var newGroup = this.FindById(groupId);
            newGroup.ApplicationUsers.Add(new ApplicationUserGroup 
            { 
                ApplicationUserId = userId, 
                ApplicationGroupId = groupId 
            });
        }
        _db.SaveChanges();
this.RefreshUserGroupRoles(userId);
return IdentityResult.Success;
    }
public IdentityResult RefreshUserGroupRoles(string userId)
    {
        var user = _userManager.FindById(userId);
if(user == null)
        {
thrownew ArgumentNullException("User");
        }
// Remove user from previous roles:
        var oldUserRoles = _userManager.GetRoles(userId);
if(oldUserRoles.Count > 0)
        {
            _userManager.RemoveFromRoles(userId, oldUserRoles.ToArray());
        }
// Find teh roles this user is entitled to from group membership:
        var newGroupRoles = this.GetUserGroupRoles(userId);
// Get the damn role names:
        var allRoles = _roleManager.Roles.ToList();
        var addTheseRoles = allRoles
            .Where(r => newGroupRoles.Any(gr => gr.ApplicationRoleId == r.Id
        ));
        var roleNames = addTheseRoles.Select(n => n.Name).ToArray();
// Add the user to the proper roles
        _userManager.AddToRoles(userId, roleNames);
return IdentityResult.Success;
    }
public async Task<IdentityResult> RefreshUserGroupRolesAsync(string userId)
    {
        var user = await _userManager.FindByIdAsync(userId);
if (user == null)
        {
thrownew ArgumentNullException("User");
        }
// Remove user from previous roles:
        var oldUserRoles = await _userManager.GetRolesAsync(userId);
if (oldUserRoles.Count > 0)
        {
            await _userManager.RemoveFromRolesAsync(userId, oldUserRoles.ToArray());
        }
// Find the roles this user is entitled to from group membership:
        var newGroupRoles = await this.GetUserGroupRolesAsync(userId);
// Get the damn role names:
        var allRoles = await _roleManager.Roles.ToListAsync();
        var addTheseRoles = allRoles
            .Where(r => newGroupRoles.Any(gr => gr.ApplicationRoleId == r.Id
        ));
        var roleNames = addTheseRoles.Select(n => n.Name).ToArray();
// Add the user to the proper roles
        await _userManager.AddToRolesAsync(userId, roleNames);
return IdentityResult.Success;
    }
public async Task<IdentityResult> DeleteGroupAsync(string groupId)
    {
        var group = await this.FindByIdAsync(groupId);
if (group == null)
        {
thrownew ArgumentNullException("User");
        }
        var currentGroupMembers = (await this.GetGroupUsersAsync(groupId)).ToList();
// remove the roles from the group:
        group.ApplicationRoles.Clear();
// Remove all the users:
        group.ApplicationUsers.Clear();
// Remove the group itself:
        _db.ApplicationGroups.Remove(group);
        await _db.SaveChangesAsync();
// Reset all the user roles:
foreach (var user in currentGroupMembers)
        {
            await this.RefreshUserGroupRolesAsync(user.Id);
        }
return IdentityResult.Success;
    }
public IdentityResult DeleteGroup(string groupId)
    {
        var group = this.FindById(groupId);
if(group == null)
        {
thrownew ArgumentNullException("User");
        }
        var currentGroupMembers = this.GetGroupUsers(groupId).ToList();
// remove the roles from the group:
        group.ApplicationRoles.Clear();
// Remove all the users:
        group.ApplicationUsers.Clear();
// Remove the group itself:
        _db.ApplicationGroups.Remove(group);
        _db.SaveChanges();
// Reset all the user roles:
foreach(var user in currentGroupMembers)
        {
this.RefreshUserGroupRoles(user.Id);
        }
return IdentityResult.Success;
    }
public async Task<IdentityResult> UpdateGroupAsync(ApplicationGroup group)
    {
        await _groupStore.UpdateAsync(group);
foreach (var groupUser in group.ApplicationUsers)
        {
            await this.RefreshUserGroupRolesAsync(groupUser.ApplicationUserId);
        }
return IdentityResult.Success;
    }
public IdentityResult UpdateGroup(ApplicationGroup group)
    {
        _groupStore.Update(group);
foreach(var groupUser in group.ApplicationUsers)
        {
this.RefreshUserGroupRoles(groupUser.ApplicationUserId);
        }
return IdentityResult.Success;
    }
public IdentityResult ClearUserGroups(string userId)
    {
returnthis.SetUserGroups(userId, newstring[] { });
    }
public async Task<IdentityResult> ClearUserGroupsAsync(string userId)
    {
return await this.SetUserGroupsAsync(userId, newstring[] { });
    }
public async Task<IEnumerable<ApplicationGroup>> GetUserGroupsAsync(string userId)
    {
        var result = new List<ApplicationGroup>();
        var userGroups = (from g inthis.Groups
                          where g.ApplicationUsers
                            .Any(u => u.ApplicationUserId == userId)
                          select g).ToListAsync();
return await userGroups;
    }
public IEnumerable<ApplicationGroup> GetUserGroups(string userId)
    {
        var result = new List<ApplicationGroup>();
        var userGroups = (from g inthis.Groups
                          where g.ApplicationUsers
                            .Any(u => u.ApplicationUserId == userId)
                          select g).ToList();
return userGroups;
    }
public async Task<IEnumerable<ApplicationRole>> GetGroupRolesAsync(
string groupId)
    {
        var grp = await _db.ApplicationGroups
            .FirstOrDefaultAsync(g => g.Id == groupId);
        var roles = await _roleManager.Roles.ToListAsync();
        var groupRoles = (from r in roles
                          where grp.ApplicationRoles
                            .Any(ap => ap.ApplicationRoleId == r.Id)
                          select r).ToList();
return groupRoles;
    }
public IEnumerable<ApplicationRole> GetGroupRoles(string groupId)
    {
        var grp = _db.ApplicationGroups.FirstOrDefault(g => g.Id == groupId);
        var roles = _roleManager.Roles.ToList();
        var groupRoles = from r in roles
                         where grp.ApplicationRoles
                            .Any(ap => ap.ApplicationRoleId == r.Id)
                         select r;
return groupRoles;
    }
public IEnumerable<ApplicationUser> GetGroupUsers(string groupId)
    {
        var group = this.FindById(groupId);
        var users = new List<ApplicationUser>();
foreach (var groupUser in group.ApplicationUsers)
        {
            var user = _db.Users.Find(groupUser.ApplicationUserId);
            users.Add(user);
        }
return users;
    }
public async Task<IEnumerable<ApplicationUser>> GetGroupUsersAsync(string groupId)
    {
        var group = await this.FindByIdAsync(groupId);
        var users = new List<ApplicationUser>();
foreach (var groupUser in group.ApplicationUsers)
        {
            var user = await _db.Users
                .FirstOrDefaultAsync(u => u.Id == groupUser.ApplicationUserId);
            users.Add(user);
        }
return users;
    }
public IEnumerable<ApplicationGroupRole> GetUserGroupRoles(string userId)
    {
        var userGroups = this.GetUserGroups(userId);
        var userGroupRoles = new List<ApplicationGroupRole>();
foreach(var group in userGroups)
        {
            userGroupRoles.AddRange(group.ApplicationRoles.ToArray());
        }
return userGroupRoles;
    }
public async Task<IEnumerable<ApplicationGroupRole>> GetUserGroupRolesAsync(
string userId)
    {
        var userGroups = await this.GetUserGroupsAsync(userId);
        var userGroupRoles = new List<ApplicationGroupRole>();
foreach (var group in userGroups)
        {
            userGroupRoles.AddRange(group.ApplicationRoles.ToArray());
        }
return userGroupRoles;
    }
public async Task<ApplicationGroup> FindByIdAsync(string id)
    {
return await _groupStore.FindByIdAsync(id);
    }
public ApplicationGroup FindById(string id)
    {
return _groupStore.FindById(id);
    }
}

 

As we can see from the above, there's a lot of code there. However, much of it is due to duplication between synchronous and asynchronous method implementations. With the above, we now have an API to work against from our controllers, and we can now get down to brass tacks, and add the Groups functionality to our site.

We've kept things as simple as possible in terms of adding and removing Users from Groups, Roles to and from Groups, and such. As you can see, each time we change the groups a user belongs to, we change all the group assignments at once, by calling SetUserGroups() and passing in an array of Group Id's. Similarly, we assign all of the Roles to a group in one shot by calling SetGroupRoles() and again, passing in an array of Role names, representing all of the roles assigned to a particular group.

We do these in this manner because, when we modify a User's Group membership, we need to essentially re-set all of the User's Roles anyway. In like manner, when we modify the Roles assigned to a particular group, we need to refresh the Roles assigned to every user within that group.

This is also handy because, when we receive the User and/or Role selections made by the user from either of the Admin Views, we get them as an array anyway. We'll see this more closely in a bit.

Adding a GroupViewModel

We will need a view model for passing group data between various controller methods and their associated Views. in the Models => AdminViewModel.cs file, add the following class:

The GroupVeiwModel Class:
publicclass GroupViewModel
{
public GroupViewModel()
    {
this.UsersList = new List<SelectListItem>();
this.PermissionsList = new List<SelectListItem>();
    }
    [Required(AllowEmptyStrings = false)]
publicstring Id { get; set; }
    [Required(AllowEmptyStrings = false)]
publicstring Name { get; set; }
publicstring Description { get; set; }
public ICollection<SelectListItem> UsersList { get; set; }
public ICollection<SelectListItem> RolesList { get; set; }
}

 

Notice here that we are passing ICollection<SelectListItem> to represent Users and Roles assigned to a Group. This way, we can pass a list of user names or or role names out to a view, allow the user to select one or more items from the list, and then process the selection choices made when the form data is submitted back to the controller via the HTTP POST method.

Update the EditUserViewModel

While we have the AdminViewModel.cs file open, let's also modify the EditUserViewModel, and add a collection property for Groups:

Add a GroupsList Property to EditUserViewModel:
publicclass EditUserViewModel
{
public EditUserViewModel()
    {
this.RolesList = new List<SelectListItem>();
this.GroupsList = new List<SelectListItem>();
    }
publicstring Id { get; set; }
    [Required(AllowEmptyStrings = false)]
    [Display(Name = "Email")]
    [EmailAddress]
publicstring Email { get; set; }
// We will still use this, so leave it here:
public ICollection<SelectListItem> RolesList { get; set; }
// Add a GroupsList Property:
public ICollection<SelectListItem> GroupsList { get; set; }
}

 

We will keep the RolesList collection as well. Even though we won't be assigning Roles directly to Users anymore, we may want to create a View which allows us to see what Roles a user has by virtue of membership in various Groups. This way, we can use the same ViewModel.

Now that we have our ViewModel all tuned up, let's add a GroupsAdminController.

Building the GroupsAdminController

Similar to the existing UserAdminController and the RolesAdminController, we need to provide a Controller to work with our new Groups functionality.

We need to add a controller in the Controllers directory. Instead of using the Context Menu => Add Controller method, just add a class, named GroupsAdminController, and add the following code:

Adding the GroupsAdminController:
publicclass GroupsAdminController : Controller
{
private ApplicationDbContext db = new ApplicationDbContext();
private ApplicationGroupManager _groupManager;
public ApplicationGroupManager GroupManager
    {
get
        {
return _groupManager ?? new ApplicationGroupManager();
        }
privateset
        {
            _groupManager = value;
        }
    }
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
    {
get
        {
return _roleManager ?? HttpContext.GetOwinContext()
                .Get<ApplicationRoleManager>();
        }
privateset
        {
            _roleManager = value;
        }
    }
public ActionResult Index()
    {
return View(this.GroupManager.Groups.ToList());
    } 
public async Task<ActionResult> Details(string id)
    {
if (id == null)
        {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        ApplicationGroup applicationgroup =
            await this.GroupManager.Groups.FirstOrDefaultAsync(g => g.Id == id);
if (applicationgroup == null)
        {
return HttpNotFound();
        }
        var groupRoles = this.GroupManager.GetGroupRoles(applicationgroup.Id);
string[] RoleNames = groupRoles.Select(p => p.Name).ToArray();
        ViewBag.RolesList = RoleNames;
        ViewBag.RolesCount = RoleNames.Count();
return View(applicationgroup);
    }
public ActionResult Create()
    {
//Get a SelectList of Roles to choose from in the View:
        ViewBag.RolesList = new SelectList(
this.RoleManager.Roles.ToList(), "Id", "Name");
return View();
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
public async Task<ActionResult> Create(
        [Bind(Include = "Name,Description")] ApplicationGroup applicationgroup, 
paramsstring[] selectedRoles)
    {
if (ModelState.IsValid)
        {
// Create the new Group:
            var result = await this.GroupManager.CreateGroupAsync(applicationgroup);
if (result.Succeeded)
            {
                selectedRoles = selectedRoles ?? newstring[] { };
// Add the roles selected:
                await this.GroupManager
                    .SetGroupRolesAsync(applicationgroup.Id, selectedRoles);
            }
return RedirectToAction("Index");
        }
// Otherwise, start over:
        ViewBag.RoleId = new SelectList(
this.RoleManager.Roles.ToList(), "Id", "Name");
return View(applicationgroup);
    }
public async Task<ActionResult> Edit(string id)
    {
if (id == null)
        {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        ApplicationGroup applicationgroup = await this.GroupManager.FindByIdAsync(id);
if (applicationgroup == null)
        {
return HttpNotFound();
        }
// Get a list, not a DbSet or queryable:
        var allRoles = await this.RoleManager.Roles.ToListAsync();
        var groupRoles = await this.GroupManager.GetGroupRolesAsync(id);
        var model = new GroupViewModel()
        {
            Id = applicationgroup.Id,
            Name = applicationgroup.Name,
            Description = applicationgroup.Description
        };
// load the roles/Roles for selection in the form:
foreach (var Role in allRoles)
        {
            var listItem = new SelectListItem()
            {
                Text = Role.Name,
                Value = Role.Id,
                Selected = groupRoles.Any(g => g.Id == Role.Id)
            };
            model.RolesList.Add(listItem);
        }
return View(model);
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(
        [Bind(Include = "Id,Name,Description")] GroupViewModel model, 
paramsstring[] selectedRoles)
    {
        var group = await this.GroupManager.FindByIdAsync(model.Id);
if (group == null)
        {
return HttpNotFound();
        }
if (ModelState.IsValid)
        {
            group.Name = model.Name;
            group.Description = model.Description;
            await this.GroupManager.UpdateGroupAsync(group);
            selectedRoles = selectedRoles ?? newstring[] { };
            await this.GroupManager.SetGroupRolesAsync(group.Id, selectedRoles);
return RedirectToAction("Index");
        }
return View(model);
    }
public async Task<ActionResult> Delete(string id)
    {
if (id == null)
        {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        ApplicationGroup applicationgroup = await this.GroupManager.FindByIdAsync(id);
if (applicationgroup == null)
        {
return HttpNotFound();
        }
return View(applicationgroup);
    }
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(string id)
    {
if (id == null)
        {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        ApplicationGroup applicationgroup = await this.GroupManager.FindByIdAsync(id);
        await this.GroupManager.DeleteGroupAsync(id);
return RedirectToAction("Index");
    }
protectedoverridevoid Dispose(bool disposing)
    {
if (disposing)
        {
            db.Dispose();
        }
base.Dispose(disposing);
    }
}

 

As we can see, we use the GroupsAdminController to manage the creation of groups, and the assignment of roles to various groups. Now, we need to modify the UsersAdminController so that instead of assigning Users to Roles directly, we are instead assigning Users to Groups, through which they gain access to the roles assigned to each group.

Modify the UsersAdminController

We need to make a few adjustments to the UsersAdminController to reflect the manner in which we are managing Groups and Roles. As mentioned previously, we are now assigning users to Groups instead of directly to roles, and our UsersAdminController needs to reflect this.

First off, we need to add an instance of ApplicationGroupManager to the controller. Next, we need to update all of our controller methods to consume Groups instead of Roles. When we create a new User, we want the View to include a list of available Groups to which the User might be assigned. When we Edit an existing User, we want the option to modify group assignments. When we Delete a user, we need to make sure the corresponding Group relationships are deleted as well.

The Following is the updated code for the entire UsersAdminController. It is easier to copy the entire thing in than to wade through it piece by piece. Then you can eyeball things, and fairly easily understand what is going on in each controller method. 

The Modified UsersAdminController:
[Authorize(Roles = "Admin")]
publicclass UsersAdminController : Controller
{
public UsersAdminController()
    {
    }
public UsersAdminController(ApplicationUserManager userManager, 
        ApplicationRoleManager roleManager)
    {
        UserManager = userManager;
        RoleManager = roleManager;
    }
private ApplicationUserManager _userManager;
public ApplicationUserManager UserManager
    {
get
        {
return _userManager ?? HttpContext.GetOwinContext()
                .GetUserManager<ApplicationUserManager>();
        }
privateset
        {
            _userManager = value;
        }
    }
// Add the Group Manager (NOTE: only access through the public
// Property, not by the instance variable!)
private ApplicationGroupManager _groupManager;
public ApplicationGroupManager GroupManager
    {
get
        {
return _groupManager ?? new ApplicationGroupManager();
        }
privateset
        {
            _groupManager = value;
        }
    }
private ApplicationRoleManager _roleManager;
public ApplicationRoleManager RoleManager
    {
get
        {
return _roleManager ?? HttpContext.GetOwinContext()
                .Get<ApplicationRoleManager>();
        }
privateset
        {
            _roleManager = value;
        }
    }
public async Task<ActionResult> Index()
    {
return View(await UserManager.Users.ToListAsync());
    }
public async Task<ActionResult> Details(string id)
    {
if (id == null)
        {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var user = await UserManager.FindByIdAsync(id);
// Show the groups the user belongs to:
        var userGroups = await this.GroupManager.GetUserGroupsAsync(id);
        ViewBag.GroupNames = userGroups.Select(u => u.Name).ToList();
return View(user);
    }
public ActionResult Create()
    {
// Show a list of available groups:
        ViewBag.GroupsList = 
new SelectList(this.GroupManager.Groups, "Id", "Name");
return View();
    }
    [HttpPost]
public async Task<ActionResult> Create(RegisterViewModel userViewModel, 
paramsstring[] selectedGroups)
    {
if (ModelState.IsValid)
        {
            var user = new ApplicationUser 
            { 
                UserName = userViewModel.Email, 
                Email = userViewModel.Email 
            };
            var adminresult = await UserManager
                .CreateAsync(user, userViewModel.Password);
//Add User to the selected Groups 
if (adminresult.Succeeded)
            {
if (selectedGroups != null)
                {
                    selectedGroups = selectedGroups ?? newstring[] { };
                    await this.GroupManager
                        .SetUserGroupsAsync(user.Id, selectedGroups);
                }
return RedirectToAction("Index");
            }
        }
        ViewBag.Groups = new SelectList(
            await RoleManager.Roles.ToListAsync(), "Id", "Name");
return View();
    }
public async Task<ActionResult> Edit(string id)
    {
if (id == null)
        {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var user = await UserManager.FindByIdAsync(id);
if (user == null)
        {
return HttpNotFound();
        }
// Display a list of available Groups:
        var allGroups = this.GroupManager.Groups;
        var userGroups = await this.GroupManager.GetUserGroupsAsync(id);
        var model = new EditUserViewModel()
        {
            Id = user.Id,
            Email = user.Email
        };
foreach (var group in allGroups)
        {
            var listItem = new SelectListItem()
            {
                Text = group.Name,
                Value = group.Id,
                Selected = userGroups.Any(g => g.Id == group.Id)
            };
            model.GroupsList.Add(listItem);
        }
return View(model);
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
public async Task<ActionResult> Edit(
        [Bind(Include = "Email,Id")] EditUserViewModel editUser, 
paramsstring[] selectedGroups)
    {
if (ModelState.IsValid)
        {
            var user = await UserManager.FindByIdAsync(editUser.Id);
if (user == null)
            {
return HttpNotFound();
            }
// Update the User:
            user.UserName = editUser.Email;
            user.Email = editUser.Email;
            await this.UserManager.UpdateAsync(user);
// Update the Groups:
            selectedGroups = selectedGroups ?? newstring[] { };
            await this.GroupManager.SetUserGroupsAsync(user.Id, selectedGroups);
return RedirectToAction("Index");
        }
        ModelState.AddModelError("", "Something failed.");
return View();
    }
public async Task<ActionResult> Delete(string id)
    {
if (id == null)
        {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
        }
        var user = await UserManager.FindByIdAsync(id);
if (user == null)
        {
return HttpNotFound();
        }
return View(user);
    }
    [HttpPost, ActionName("Delete")]
    [ValidateAntiForgeryToken]
public async Task<ActionResult> DeleteConfirmed(string id)
    {
if (ModelState.IsValid)
        {
if (id == null)
            {
returnnew HttpStatusCodeResult(HttpStatusCode.BadRequest);
            }
            var user = await UserManager.FindByIdAsync(id);
if (user == null)
            {
return HttpNotFound();
            }
// Remove all the User Group references:
            await this.GroupManager.ClearUserGroupsAsync(id);
// Then Delete the User:
            var result = await UserManager.DeleteAsync(user);
if (!result.Succeeded)
            {
                ModelState.AddModelError("", result.Errors.First());
return View();
            }
return RedirectToAction("Index");
        }
return View();
    }
}

 

Now that we have all of our Controllers in place, we need to add and/or update some Views.

Add Groups Admin as a Menu Item in the Main Layout View

In order to access our new Groups, we will need to add a menu item to Views => Shared => _Layout.cshtml. Since we only want Admin users to access menu item, we want to tuck it in with the other links to Admin-type Views. Modify the _Layout.cshtml file as follows (I've only included the relevant section of the View template below):

Add Groups Admin as a Link in the Main Layout View:
// Other View Code before...:
<ul class="nav navbar-nav">
<li>@Html.ActionLink("Home", "Index", "Home")</li>
<li>@Html.ActionLink("About", "About", "Home")</li>
<li>@Html.ActionLink("Contact", "Contact", "Home")</li>
    @if (Request.IsAuthenticated && User.IsInRole("Admin")) {
<li>@Html.ActionLink("RolesAdmin", "Index", "RolesAdmin")</li>
<li>@Html.ActionLink("UsersAdmin", "Index", "UsersAdmin")</li>
<li>@Html.ActionLink("GroupsAdmin", "Index", "GroupsAdmin")</li>
    }
</ul>
@Html.Partial("_LoginPartial")
// ...Other View Code After...

 

Adding Views for the GroupsAdminController

We're going to step through this fairly quickly, since there isn't a lot of discussion needed around View template code. Obviously, we need a view for each of our GroupsAdminController action methods.

Since Visual Studio won't generate quite what we need using the Add View Context Menu command, we'll do this manually.

Add a folder to the Views directory named GroupsAdmin. Now add the following Views:

The GroupsAdmin Index.cshtml View:
@model IEnumerable<IdentitySample.Models.ApplicationGroup>
@{
    ViewBag.Title = "Index";
}
<h2>Index</h2>
<p>
    @Html.ActionLink("Create New", "Create")
</p>
<table class="table">
<tr>
<th>
            @Html.DisplayNameFor(model => model.Name)
</th>
<th>
            @Html.DisplayNameFor(model => model.Description)
</th>
<th></th>
</tr>
@foreach (var item in Model) {
<tr>
<td>
            @Html.DisplayFor(modelItem => item.Name)
</td>
<td>
            @Html.DisplayFor(modelItem => item.Description)
</td>
<td>
            @Html.ActionLink("Edit", "Edit", new { id=item.Id }) |
            @Html.ActionLink("Details", "Details", new { id=item.Id }) |
            @Html.ActionLink("Delete", "Delete", new { id=item.Id })
</td>
</tr>
}
</table>

 

The GroupsAdmin Create.chtml View:
@model IdentitySample.Models.ApplicationGroup
@{
    ViewBag.Title = "Create";
}
<h2>Create</h2>
@using (Html.BeginForm()) 
{
    @Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ApplicationGroup</h4>
<hr />
        @Html.ValidationSummary(true)
<div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.EditorFor(model => model.Description)
                @Html.ValidationMessageFor(model => model.Description)
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">
                Select Group Roles
</label>
<div class="col-md-10">
                @foreach (var item in (SelectList)ViewBag.RolesList)
                {
<div>
<input type="checkbox" name="SelectedRoles" value="@item.Text" class="checkbox-inline" />
                        @Html.Label(item.Text, new { @class = "control-label" })
</div>
                }
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Create" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

The GroupsAdmin Edit.cshtml View:
@model IdentitySample.Models.GroupViewModel
@{
    ViewBag.Title = "Edit";
}
<h2>Edit</h2>
@using (Html.BeginForm())
{
    @Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>ApplicationGroup</h4>
<hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)
<div class="form-group">
            @Html.LabelFor(model => model.Name, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.EditorFor(model => model.Name)
                @Html.ValidationMessageFor(model => model.Name)
</div>
</div>
<div class="form-group">
            @Html.LabelFor(model => model.Description, new { @class = "control-label col-md-2" })
<div class="col-md-10">
                @Html.EditorFor(model => model.Description)
                @Html.ValidationMessageFor(model => model.Description)
</div>
</div>
<div class="form-group">
            @Html.Label("Permissions", new { @class = "control-label col-md-2" })
<span class=" col-md-10">
                @foreach (var item in Model.RolesList)
                {
<div>
<input type="checkbox" name="selectedRoles" value="@item.Text" checked="@item.Selected" class="checkbox-inline" />
                        @Html.Label(item.Text, new { @class = "control-label" })
</div>
                }
</span>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

The GroupsAdmin Details.cshtml View:
@model IdentitySample.Models.ApplicationGroup
@{
    ViewBag.Title = "Details";
}
<h2>Details</h2>
<div>
<h4>ApplicationGroup</h4>
<hr />
<dl class="dl-horizontal">
<dt>
            @Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
            @Html.DisplayFor(model => model.Name)
</dd>
<dt>
            @Html.DisplayNameFor(model => model.Description)
</dt>
<dd>
            @Html.DisplayFor(model => model.Description)
</dd>
</dl>
</div>
<h4>List of permissions granted this group</h4>
@if (ViewBag.PermissionsCount == 0)
{
<hr />
<p>No users found inthis role.</p>
}
<table class="table">
    @foreach (var item in ViewBag.RolesList)
    {
<tr>
<td>
                @item
</td>
</tr>
    }
</table>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
    @Html.ActionLink("Back to List", "Index")
</p>

 

The GroupsAdmin Delete.cshtml View:
@model IdentitySample.Models.ApplicationGroup
@{
    ViewBag.Title = "Delete";
}
<h2>Delete</h2>
<h3>Are you sure you want to delete this?</h3>
<div>
<h4>ApplicationGroup</h4>
<hr />
<dl class="dl-horizontal">
<dt>
            @Html.DisplayNameFor(model => model.Name)
</dt>
<dd>
            @Html.DisplayFor(model => model.Name)
</dd>
<dt>
            @Html.DisplayNameFor(model => model.Description)
</dt>
<dd>
            @Html.DisplayFor(model => model.Description)
</dd>
</dl>
    @using (Html.BeginForm()) {
        @Html.AntiForgeryToken()
<div class="form-actions no-color">
<input type="submit" value="Delete" class="btn btn-default" /> |
            @Html.ActionLink("Back to List", "Index")
</div>
    }
</div>

 

Updating the UserAdmin Views

We need to make a few minor changes to the UserAdmin Views. In the existing project, the UserAdmin Create and Edit Views allow us to assign Roles to the user. Instead, we want to assign the User to one or more Groups. Update the Create and Edit Views as follows:

Pay close attention when modifying the view code, and the names of Viewbag properties matter. 

The Modified UserAdmin Create.cshtml View:
@model IdentitySample.Models.RegisterViewModel
@{
    ViewBag.Title = "Create";
}
<h2>@ViewBag.Title.</h2>
@using (Html.BeginForm("Create", "UsersAdmin", FormMethod.Post, new { @class = "form-horizontal", role = "form" }))
{
    @Html.AntiForgeryToken()
<h4>Create a new account.</h4>
<hr />
    @Html.ValidationSummary("", new { @class = "text-error" })
<div class="form-group">
        @Html.LabelFor(m => m.Email, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.Password, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.PasswordFor(m => m.Password, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
        @Html.LabelFor(m => m.ConfirmPassword, new { @class = "col-md-2 control-label" })
<div class="col-md-10">
            @Html.PasswordFor(m => m.ConfirmPassword, new { @class = "form-control" })
</div>
</div>
<div class="form-group">
<label class="col-md-2 control-label">
            Select User Groups
</label>
<div class="col-md-10">
            @foreach (var item in (SelectList)ViewBag.GroupsList)
            {
<div>
<input type="checkbox" name="selectedGroups" value="@item.Value" class="checkbox-inline" />
                    @Html.Label(item.Text, new { @class = "control-label" })
</div>
            }
</div>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" class="btn btn-default" value="Create" />
</div>
</div>
}
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

The highlighted area calls out the primary impacted code.

Next, we will similarly modify the UsersAdmin => Edit.cshtml file.

The Modified UsersAdmin Edit.cshtml View:
@model IdentitySample.Models.EditUserViewModel
@{
    ViewBag.Title = "Edit";
}
<h2>Edit.</h2>
@using (Html.BeginForm()) {
    @Html.AntiForgeryToken()
<div class="form-horizontal">
<h4>Edit User Form.</h4>
<hr />
        @Html.ValidationSummary(true)
        @Html.HiddenFor(model => model.Id)
<div class="form-group">
            @Html.LabelFor(model => model.Email, new { @class = "control-label col-md-2" })
<div class="col-md-10">
               @Html.TextBoxFor(m => m.Email, new { @class = "form-control" })
               @Html.ValidationMessageFor(model => model.Email)
</div>
</div>
<div class="form-group">
            @Html.Label("This User belongs to the following Groups", new { @class = "control-label col-md-2" })
<span class=" col-md-10">
                @foreach (var item in Model.GroupsList)
                {
<div>
<input type="checkbox" name="selectedGroups" value="@item.Value" checked="@item.Selected" class="checkbox-inline" />
                        @Html.Label(item.Text, new { @class = "control-label" })
</div>
                }
</span>
</div>
<div class="form-group">
<div class="col-md-offset-2 col-md-10">
<input type="submit" value="Save" class="btn btn-default" />
</div>
</div>
</div>
}
<div>
    @Html.ActionLink("Back to List", "Index")
</div>
@section Scripts {
    @Scripts.Render("~/bundles/jqueryval")
}

 

The UsersAdmin Details.cshtml View displays a list of Roles assigned to the currently selected User. We will instead display a list of Groups:

The Modified UsersAdmin Details.cshtml View:
@model IdentitySample.Models.ApplicationUser
@{
    ViewBag.Title = "Details";
}
<h2>Details.</h2>
<div>
<h4>User</h4>
<hr />
<dl class="dl-horizontal">
<dt>
            @Html.DisplayNameFor(model => model.UserName)
</dt>
<dd>
            @Html.DisplayFor(model => model.UserName)
</dd>
</dl>
</div>
<h4>List ofGroups this user belongs to:</h4>
@if (ViewBag.GroupNames.Count == 0)
{
<hr />
<p>No Groups found forthis user.</p>
}
<table class="table">
    @foreach (var item in ViewBag.GroupNames)
    {
<tr>
<td>
                @item
</td>
</tr>
    }
</table>
<p>
    @Html.ActionLink("Edit", "Edit", new { id = Model.Id }) |
    @Html.ActionLink("Back to List", "Index")
</p>

 

Of course, there is more we could do with the Views in this project, and we could add a few more for displaying User effective permissions (the sum permissions a user holds by virtue of membership in the assigned Groups) for example. For now, though, we'll just get things working, and then you can fine-tune things to the needs of your project.

Modify the Identity.Config File and the DbInitializer

In the previous project, when we set up Group-Based Permissions Management under Identity 1.0, we used EF Migrations to perform the database creation and Code-First generation. This time around, we are going to continue using the DbInitializer from the IdentitySamples project.

The ApplicationDbInitializer is defined in App_Start => IdentityConfig.cs. I have set it up for development purposes to inherit from DropCreateDatabaseAlways. However, you can easily change this to DropCreateDatabaseIfModelChanges.

Of course, we want our application to run with a basic configuration ready to go. Currently, the DbInitializer sets things up by creating a default User, an Admin Role, and then assigns the default user to that role.

We want to create the same default user, but then also create a default group. Then, we will create the default Admin role and assign it to the default group. Finally, we'll add the user to that group.

Open the App_Start => Identity.Config file, and make the following changes to the InitializeIdentityForEF() Method in the ApplicationDbInitializer class:

The InitializeIdentityForEF Method:
publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db) {
    var userManager = HttpContext.Current
        .GetOwinContext().GetUserManager<ApplicationUserManager>();
    var roleManager = HttpContext.Current
        .GetOwinContext().Get<ApplicationRoleManager>();
conststring name = "admin@example.com";
conststring password = "Admin@123456";
conststring roleName = "Admin";
//Create Role Admin if it does not exist
    var role = roleManager.FindByName(roleName);
if (role == null) {
        role = new ApplicationRole(roleName);
        var roleresult = roleManager.Create(role);
    }
    var user = userManager.FindByName(name);
if (user == null) {
        user = new ApplicationUser 
        { 
            UserName = name, 
            Email = name, 
            EmailConfirmed = true
        };
        var result = userManager.Create(user, password);
        result = userManager.SetLockoutEnabled(user.Id, false);
    }
    var groupManager = new ApplicationGroupManager();
    var newGroup = new ApplicationGroup("SuperAdmins", "Full Access to All");
    groupManager.CreateGroup(newGroup);
    groupManager.SetUserGroups(user.Id, newstring[] { newGroup.Id });
    groupManager.SetGroupRoles(newGroup.Id, newstring[] { role.Name });
}

 

With that, we should be ready to run the application.

Running the Application

Once we've started the application and logged in, we should be able to navigate through the various admin functions. To make things interesting, let's add a few Roles, Groups, and Users and see what's what:

If we have added some additional Roles, Users, and Groups, we begin to see how this might work in the context of a real-world application. Lets take two fictitious departments, Sales and Purchasing. We might have some Roles at a relatively granular level (perhaps, at the level of our basic controller Actions) for each function:

Basic Roles for Sales and Purchasing Departments

sales-purchasing-roles

Now, this, and our other views could most likely use some help from a designer, or at least some presentation controls which would allow for better groupings, or something. Nonetheless, we see we have added some Roles here which correspond roughly with hypothetical controller actions we might find on a CustomersController and a ProductsController (OK - we're simplifying a little for the purpose of this example, but you get the idea).

Now, we might also define some Groups:

Basic Groups for Sales and Purchasing:

sales-purchasing-groups

Again, if we were worried about design aesthetics here, we might find our Groups management View a little lacking. But you can see that we have defined a few Groups related to the functions of the Sales and Purchasing departments.

Now, if we edit one of these groups, we can assign the appropriate Roles to the group:

Assigning Group Roles When Editing Group:

select-roles-for-group

Here, we have decided that users in the SalesAdmin Group should be able to add/edit/view/delete Customer data, as well as view (but not modify) product data.

Again, we might add some improvements to the display and grouping of the available roles here, but this works for demonstration purposes.

Now, if we save the SalesAdmin Group like this, we can then assign one or more users, who will then get all of the permissions associated with this group.

Creating a New User with Group Assignments:

create-user-with-group-assignments

Once we save, Jim will be a member of the SalesAdmin Group, and will have all of the Role permissions we assigned to that group.

Controlling Access with the [Authorize] Attribute

Of course, none of this does us any good if we don't put these granular Role permissions to use.

First off, we probably want to add some access control to our GroupsAdminController itself. We might want to add an [Authorize] decoration to the entire controller, similar to the UserAdminController, so that only those with the Admin Role can modify Groups.

Beyond that, though, let's expand upon our example above. Consider a hypothetical CustomersController. We might decorate the basic controller methods as follows, in keeping with the Roles we defined:

Hypothetical CustomersController:
publicclass CustomerController
{
    [Authorize(Roles = "CanViewCustomers")]
public async ActionResult Index()
    {
// Code...
    }
    [Authorize(Roles = "CanAddCustomers")]
public async ActionResult Create()
    {
// Code...
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "CanAddCustomers")]
public async Task<ActionResult> Create(SomeArguments)
    {
// Code...
    }
    [Authorize(Roles = "CanEditCustomers")]
public async ActionResult Edit(int id)
    {
// Code...
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "CanEditCustomers")]
public async Task<ActionResult> Edit(SomeArguments)
    {
// Code...
    }
    [Authorize(Roles = "CanDeleteCustomers")]
public async Task<ActionResult> Delete(id)
    {
// Code...
    }
    [HttpPost]
    [ValidateAntiForgeryToken]
    [Authorize(Roles = "CanDeleteCustomers")]
public async Task<ActionResult> Delete(SomeArguments)
    {
// Code...
    }
}

 

We can see that we have now implemented some authorization control which corresponds to some of the Roles we defined. The roles themselves are not specific to any one type of user. instead, Roles can be assigned to different Groups. From there, it is a simple matter to add or remove users from one or more groups, depending upon their function and access requirements.

Some Thoughts on Authorization and Security

The concepts in this project are sort of a middle ground between the basic, but highly functional authorization mechanism offered by Identity 2.0 out of the box, and more complex implementations using Claims or Active Directory.

The system illustrated here will afford a more granular control over Roles and Authorization to access and execute code. However, there is a practical limit.

Designing a robust application authorization matrix requires careful thought, and choosing the correct tools (as with most things in development). Planning carefully upfront will go a long ways towards helping you create a solid, maintainable application.

If you get too fine-grained in your Authorizations and Role definitions, you will have a difficult to manage mess. Not going granular enough results in a clunky, limited authorization scheme where you may find yourself giving users too much or too little access.

Errata, Ideas, and Pull Requests

It is entirely possible I have missed something in putting the code together for this article. Also, as noted, there is plenty of room for improvement in the design here. If you find something broken, have an idea to improve the concept, or (Especially) would like to improve the Views with respect to organizing Roles, Groups, etc, please open an issue or send me a Pull Request.

Additional Resources and Items of Interest

ASP.NET Identity 2.0: Introduction to Working with Identity 2.0 and Web API 2.2

$
0
0

Lock-320In recent posts, I've covered a lot of ground using ASP.NET Identity 2.0 in the context of an MVC application. Since it's RTM in March of this year, Identity 2.0 has offered a substantial expansion of the Authentication/Authorization . toolset available to MVC applications.

Similarly, Identity 2.0 expands the Identity management tools available through ASP.NET Web Api. The same flexibility and extensibility are available, although things work just a little differently.

In this post, I'm going to take a quick tour of a basic Identity 2.0-based Web Api application, and look at some basic usage examples. If you are an experienced web developer, there is probably nothing new for you here – this is intended to be a bit of a 101 level introduction. If you are new to Identity 2.0 and/or ASP.NET Web Api you will likely find some of this information useful.

Image by Universal Pops  |  Some Rights Reserved

In the next few posts, we'll take a closer look at using Identity 2.0 with Web Api. We'll see how to extend the Identity model, similar to what we did with Identity 2.0 for MVC. We'll create a more easily extensible Identity/Web Api project. We will also explore various Authentication and Authorization schemes, and develop a better understanding of effective Web Api security.

For a review of what we have covered on using Identity 2.0 in the context of an ASP.NET MVC project, see:

For now, we'll take a high-level look at the basic Web Api project template shipped with Visual Studio, and get familiar with the basic structure.

Getting Started - Create a New ASP.NET Web Api Project

As of Visual Studio 2013 Update 3, WebApi 2.0 and Identity 2.0 are part of the out-of-the-box Web Api project template. While this default project template is a bit cluttered for my tastes, it is a good starting point to get familiar with the basics.

We are going to create a basic Web Api project in visual studio, and then update the various Nuget packages. In part, because we generally want to tbe using the latest package versions, but in particular because we want to work with the latest release of Web Api (version 2.2 as of this writing, released in July 2014).

First, do File => New Project, and then select ASP.NET Web Application:

Create a New Web Application Project:

New Project

Update the Nuget Packages for the Solution

Then, Open the Nuget Package Manager and update the Nuget packages for the solution. Select "Update" from the sidebar on the left, then "Update All":

Update Nuget Packages for Solution:

update-nuget-packages

When you get partway through the update process, you will be greeted by a scary-looking window warning you that some project files are about to be overwritten. These are .cshtml View files, and SHOULD be overwritten, as they are being updated to work with the new libraries.

Resolve File Conflicts by Clicking “Yes to All”:

nuget-file-conflict-yes-to-all

View files, you say? I thought we were making a Web Api project?

We are. But as I said, the default Web Api project includes a bit 'o MVC, for the "Help" page, and a basic home page. More on this in a bit.

Run and Test the Default Web Api Project

Now that we have created a new Web Api project, let's give it a quick test spin and see if everything is working property.

Open another instance of Visual Studio, and create a console application. Next, use the Nuget package manager to install the Web Api Client Libraries:

Install Web Api Client Libraries into Console Application:

install-webapi-client-libraries-in-console-app

After the installation is complete, check for updates. Then, add the following code to the Program.cs file (be sure to add System.Net.Http and Newtonsoft.Json to the using statements at the top of the class):

Example code to run against Web Api Application:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Net.Http;
using Newtonsoft.Json;
namespace TestApi
{
class Program
    {
staticvoid Main(string[] args)
        {
string userName = "john@example.com";
string password = "Password@123";
            var registerResult = Register(userName, password);
            Console.WriteLine("Registration Status Code: {0}", registerResult);
string token = GetToken(userName, password);
            Console.WriteLine("");
            Console.WriteLine("Access Token:");
            Console.WriteLine(token);
            Console.Read();
        }
staticstring Register(string email, string password)
        {
            var registerModel = new
            { 
                Email = email, 
                Password = password, 
                ConfirmPassword = password 
            };
using (var client = new HttpClient())
            {
                var response =
                    client.PostAsJsonAsync(
"http://localhost:62069/api/Account/Register", 
                    registerModel).Result;
return response.StatusCode.ToString();
            } 
        }
staticstring GetToken(string userName, string password)
        {
            var pairs = new List<KeyValuePair<string, string>>
                        {
new KeyValuePair<string, string>( "grant_type", "password" ), 
new KeyValuePair<string, string>( "username", userName ), 
new KeyValuePair<string, string> ( "Password", password )
                        };
            var content = new FormUrlEncodedContent(pairs);
using (var client = new HttpClient())
            {
                var response = 
                    client.PostAsync("http://localhost:62069/Token", content).Result;
return response.Content.ReadAsStringAsync().Result;
            }
        }
    }
}

 

Now, Run your Web Api application. Once it has finished starting up, run the new Console application.

What we are going to do here is POST content representing a new user to the Register() method defined on the AccountsController of our Api. Next, we will make a call to the Token endpoint of our Api and retrieve an access token, which we can use to authenticate ourselves during subsequent calls to our Api.

If you aren't quite sure what is happening in the code above, don't worry about it for the moment. We'll look more closely at what is going on here (and what this "token" business is all about) in a bit. For the moment, let's just see if our application works.

If all went as expected, our console output should look something like this:

Console Output from Register and GetTokenDictionary Methods:
resitration Status Code: OK
Access Token:
{"access_token":"8NeiVoKARt5Rm_50mP2ZfudNvvPRkm-FehohX8cLmUmrm1y8kZj0PTccsH1nKbT
PFTGuKoFSfi2mfD2KD-UMOEQWVJ0PJPfiSebJubSPLElzYfR7vk_V8gcbbkLK6cZ0zS7gWrMhdbgQrrQ
yDPyR83gbkjZcE1ooQQiv9d7AEfjCassj_R76Q44PW7goMHcbFZl66dZLBKGKhf9t7lpcvWStoyS6z8a
m7B3SWppVeaTjAC5BZ6uHOG1d_0mzL8FiR_eV8NaA1w3-GfV-upErG6xk5-qykdoLHoe7zmv4tX5Dm7-
w2n3G0gAdVlPcbfAJgSvu1AmUQe85g5ABbWJ6e0OXoPtH658kYZWC0FxbWiFPLGz66wPMbUCwjk_Hq_p
rLDjOshWP6lIE3qwQ88U5ScB1XcGAXbrYYFZ9AYkwSt4o5cC2Vpw8xP2OFdLdDOUs2ESPtVK8FThhaAh
yFUUDpXSlXwhQ2nEuu27ISw1MK0bh06-xx4vcnfoaW9XuHBXm","token_type":"bearer","expire
s_in":1209599,"userName":"john@example.com",".issued":"Wed, 17 Sep 2014 02:14:29
 GMT",".expires":"Wed, 01 Oct 2014 02:14:29 GMT"}

 

Congratulations! You have just registered a user, and retrieved an access token from your new Web Api application.

What you see in the console output is, first, the result from registering a new user. After that you see what looks like a gob of Json because, well, it is. We de-serialized the response content into a string, and an ginormous blob of JSON is what we get for that.

If you look close, you can see first the access_token property, and there at the end are a few other properties, such as token_type, a time until the token expires, userName, and a few other properties. We will be looking more closely at tokens shortly.

Now that we see everything is working, let's take a look at how the Web Api application is structured, and identify the important pieces we need to be aware of when working with Web Api and Identity. Then we'll learn a little more about this token business. 

Important Note: The code above is strictly to see if our application starts up and runs, and as an example of obtaining an access token. In reality, you would always want to implement SSL before sending/receiving Bearer tokens in this manner.

Web Api Project Structure - Overview

As mentioned previously, the default project template contains some fluff we may or may not wish to use in a "real" Web Api project. There is a folder named "Areas" which contains a bunch of stuff for managing a "help" page, there is a Views folder containing, well, a few .cshtml Views, and a few other folders mostly supporting the MVC side of our project, such as the Content folder, fonts folder, Etc. For the moment, it is safe to say we can ignore the following project folders (although they may be useful later on, depending upon your needs):

VS Web Api Project Folders we can Ignore (for now):

  • Areas folder
  • Content folder
  • Fonts folder
  • Scripts folder
  • Views folder

On the other hand, while we are getting started with Web Api and Identity 2.0, the following folders DO Matter to us, and form a critical part of the project structure. We need to be familiar with these in order to extend/adapt/customize the default project to our needs:

VS Web Api Project Folders we ARE Interested in:

  • App-Start folder
  • Controllers folder
  • Models folder
  • Providers folder

The App_Start Folder

The App_Start folder contains various configuration items which need to happen at… application startup. Of particular interest to us, from the context of an Identity-based Web Api application, are the files named IdentityConfig.cs, WebApiConfig.cs, and Startup.Auth.cs.

As the names of these files imply, these are each respectively where we might setup and/or modify configuration options for each of the services indicated. IdentityConfig.cs and Startup.Auth.cs are where we configure most of the authentication and authorization options for our application. WebApiConfig.cs is where we set up our default routes for incoming requests.

The Controllers Folder

This should be familiar to any who have worked with a basic MVC project before. However, note that controllers in a Web Api application are not the same as controllers in an MVC application - Web Api controllers all inherit from the ApiController base class, whereas the familiar MVC controller inherits from the Controller base class.

Controllers are where we process incoming Http requests, and either return the requested resource, or respond with the appropriate Http status code. We'll get a closer look at this soon.

The Models Folder

In a Web Api application, much like an MVC application, we define the business entities used by our application in terms of Models, ViewModels, and BindingModels. The Models folder is generally where we will find the business objects we need to make our application work.

As a general rule, Models represent core business objects, often persisted in our back-end data store. ViewModels generally represent the data required for use by a user of our Api. BindingModels are similar to Viewmodels, but they generally represent incoming data, and are used by the controller to deserialize incoming content from Xml or Json into objects our application can use.

The Providers Folder

In the default Visual Studio Web Api Solution, the Providers folder contains a single class, the ApplicationOAuthProvider. In the default configuration, this class is consumed by the ConfigureAuth() method defined on Startup.Auth, and defines how Authentication and Authorization tokens are handled.

Identity 2.0 and hence, Web Api 2.2 rely heavily on Owin as the default Authorization and Authentication middleware.

Default Identity Models for Web Api

If we start with the IdentityModels.cs file, we can see there isn't much going on here. We have a basic ApplicationUser class, and the ApplicationDbContext, and that's it:

The Identity Models Class:
publicclass ApplicationUser : IdentityUser
{
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        UserManager<ApplicationUser> manager, string authenticationType)
    {
// Note the authenticationType must match the one defined in 
// CookieAuthenticationOptions.AuthenticationType
        var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
    }
}
publicclass ApplicationDbContext : IdentityDbContext<ApplicationUser>
{
public ApplicationDbContext()
        : base("DefaultConnection", throwIfV1Schema: false)
    {
    }
publicstatic ApplicationDbContext Create()
    {
returnnew ApplicationDbContext();
    }
}

 

The AccountViewModels.cs and AccountBindingModels.cs files contain the various ViewModels and BindingModels used by the AccountController methods. Pop those open and get a feel for what's there. The ViewModels represent what our Api expects to serialize and push OUT as content with a response, and the BindingModels generally represent data we expect to RECEIVE as content in an HTTP request, after being de-serialized by the appropriate format provider.

AccountController - an ApiController

Next let's take a look at AccountController. We won't walk through the code for this here in the post, but take a quick look at the various methods in this class. Many will look suspiciously similar to the AccountController in an MVC project. However, there are some important differences.

First off,  note that the methods on AccountController return either a data entity of some sort (such as the UserInfoViewModel returned by the GetUserInfo() method), or they return an instance of IHttpActionResult.

In other words, as we already suspected, Action methods on a Web Api controller don't return Views. They ultimately return HttpResponse messages (with some downstream assistance from the controller itself), with any content encoded in the response body.

By way of comparison, we find that the HomeController, also in the Controllers folder, inherits from the familiar Controller base class, and the Action methods defined on HomeController return the standard ActionResult, generally Views. That's because HomeController, here, is included to support the MVC component of our Web Api. We can ignore HomeController for now, as in currently doesn't provide access to any of our Api Methods.

Identity Configuration

In the App_Start folder, open the IdentityConfig.cs file. There's a lot less going on here than in the similar file found in a standard ASP.NET MVC project. Essentially, the only thing that happens here is that the ApplicationUserManager is defined for the Web Api Application. However, there are some important configuration items taking place here.

The ApplicationUserManager Class Defined in IdentityConfig.cs
publicstatic ApplicationUserManager Create(
        IdentityFactoryOptions<ApplicationUserManager> options, 
        IOwinContext context)
    {
        var manager = new ApplicationUserManager(
new UserStore<ApplicationUser>(context.Get<ApplicationDbContext>()));
// Configure validation logic for usernames
        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
        {
            AllowOnlyAlphanumericUserNames = false,
            RequireUniqueEmail = true
        };
// Configure validation logic for passwords
        manager.PasswordValidator = new PasswordValidator
        {
            RequiredLength = 6,
            RequireNonLetterOrDigit = true,
            RequireDigit = true,
            RequireLowercase = true,
            RequireUppercase = true,
        };
        var dataProtectionProvider = options.DataProtectionProvider;
if (dataProtectionProvider != null)
        {
            manager.UserTokenProvider = new DataProtectorTokenProvider<ApplicationUser>(
                dataProtectionProvider.Create("ASP.NET Identity"));
        }
return manager;
    }
}

 

In this file, we define the password requirements for our application, as well as place potential constraints on user names and email addresses.

While not included in the default implementation for a Web Api project, this is also where we might define two-factor authentication providers for email or SMS text, and also where we might define email account confirmation configuration.

If we wanted to extend the Identity implementation in our Web Api application to include Roles, and some database initialization, this file is where we would most likely define and configure a RoleManager and DbInitializer.

Startup Authentication and Authorization Configuration

The primary authentication and authorization strategy in Web Api is token-based. We'll look closer at what this means momentarily, but for now, assume that in order to access any secured portion of your Api, you will need to present an access token as part of any incoming Http Request.

In the Startup.Auth.cs file, we se where configuration for authentication processing is performed. We see that the Startup.Auth.cs file contains a partial class, Startup, which extends the default Startup class defined at the root level of our project.

If we take a look at the latter (the Startup class at the root level of the project) we see a single method call, to the ConfigureAuth() method:

The Core Startup Class:
public partial class Startup
{
publicvoid Configuration(IAppBuilder app)
    {
        ConfigureAuth(app);
    }
}

 

The ConfigureAuth() method is defined on the partial class in Startup.Auth.cs:

The ConfigureAuth Method from Startup.Auth.cs:
publicvoid ConfigureAuth(IAppBuilder app)
{
// Configure the db context and user manager to use a single instance per request
    app.CreatePerOwinContext(ApplicationDbContext.Create);
    app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
// Enable the application to use a cookie to store information for the signed in user
// and to use a cookie to temporarily store information about a 
// user logging in with a third party login provider
    app.UseCookieAuthentication(new CookieAuthenticationOptions());
    app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
// Configure the application for OAuth based flow
    PublicClientId = "self";
    OAuthOptions = new OAuthAuthorizationServerOptions
    {
        TokenEndpointPath = new PathString("/Token"),
        Provider = new ApplicationOAuthProvider(PublicClientId),
        AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
        AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
        AllowInsecureHttp = true
    };
// Enable the application to use bearer tokens to authenticate users
    app.UseOAuthBearerTokens(OAuthOptions);
// Uncomment the following lines to enable logging in with 
// third party login providers
//app.UseMicrosoftAccountAuthentication(
//    clientId: "",
//    clientSecret: "");
//app.UseTwitterAuthentication(
//    consumerKey: "",
//    consumerSecret: "");
//app.UseFacebookAuthentication(
//    appId: "",
//    appSecret: "");
//app.UseGoogleAuthentication(new GoogleOAuth2AuthenticationOptions()
//{
//    ClientId = "",
//    ClientSecret = ""
//});
}

 

In this method, we configure options for cookie and token authentication, and, optionally, allow sign-in via various third-party providers such as Facebook or Twitter.

Of particular interest to us is the highlighted line configuring the application to use Bearer tokens. We'll find out why this is important soon enough. For now, realize that the Startup.Auth.cs file is where you configure the authorization and authentication options for the application as a whole, and determine what your application will, and won't, accept as credentials.

Token Authentication and Bearer Tokens

The standard Visual Studio Web Api template is configured to use OAuth bearer tokens as a primary means of authentication. Bearer Tokens are exactly what the name implies - Web Api will consider the bearer of the token to be properly authenticated (provided the token is not expired, per the configuration settings in Startup.Auth.cs).

This can have some serious security implications. If a malicious actor were able to intercept a client request and get hold of the Bearer Token from the request header, they would then be able to gain access as an authenticated Api user.

For this reason, if you are planning to deploy a Web Api application using the default Bearer Token authentication scheme, it is critical that the production application implement SSL/TSL(Meaning, HTTPS) to encrypt and protect traffic between the client an  your Api.

If we take another look at the console output when we ran our application earlier, we the information we grabbed from the token:

Contents of the Default Access Token:
registration Status Code: OK
Access Token:
{"access_token":"8NeiVoKARt5Rm_50mP2ZfudNvvPRkm-FehohX8cLmUmrm1y8kZj0PTccsH1nKbT
PFTGuKoFSfi2mfD2KD-UMOEQWVJ0PJPfiSebJubSPLElzYfR7vk_V8gcbbkLK6cZ0zS7gWrMhdbgQrrQ
yDPyR83gbkjZcE1ooQQiv9d7AEfjCassj_R76Q44PW7goMHcbFZl66dZLBKGKhf9t7lpcvWStoyS6z8a
m7B3SWppVeaTjAC5BZ6uHOG1d_0mzL8FiR_eV8NaA1w3-GfV-upErG6xk5-qykdoLHoe7zmv4tX5Dm7-
w2n3G0gAdVlPcbfAJgSvu1AmUQe85g5ABbWJ6e0OXoPtH658kYZWC0FxbWiFPLGz66wPMbUCwjk_Hq_p
rLDjOshWP6lIE3qwQ88U5ScB1XcGAXbrYYFZ9AYkwSt4o5cC2Vpw8xP2OFdLdDOUs2ESPtVK8FThhaAh
yFUUDpXSlXwhQ2nEuu27ISw1MK0bh06-xx4vcnfoaW9XuHBXm", "token_type":"bearer" ,"expire
s_in":1209599,"userName":"john@example.com",".issued":"Wed, 17 Sep 2014 02:14:29
 GMT",".expires":"Wed, 01 Oct 2014 02:14:29 GMT"}

 

We see that the token_type property identifies this as a Bearer token.

To use a rather cliché example, Bearer tokens can be compared to currency - they are valid for whoever presents them.

The examples we have used to this point, and for the rest of this article will be using standard HTTP. While you are developing your application or trying on the examples, this is fine. However, if you are going to deploy a production application you will most definitely want to implement SSL/TSL, or investigate alternative authentication/authorization schemes.

We will take a closer look at Tokens, and alternate authentication mechanisms in an upcoming post.

Using Token Authentication and Accessing Web Api from a Client Application

We've already seen how to obtain a basic bearer token from our Api. Now let's take a more detailed look at grabbing a token, and then making some requests against the basic, default Web Api project.

First, let's change up our code a little bit. What we want to do is pull apart the JSON token into a Dictionary<string, string> so we can get at the access_token property. It is this we need to submit in the header of subsequent Api requests in order to authenticate ourselves.

Change the GetToken() method as follows, so that instead of returning s string, it returns a Dictionary. Let's also rename it as GetTokenDictionary() to better reflect what it does:

The New GetTokenDictionary() Method:
static Dictionary<string, string> GetTokenDictionary(
string userName, string password)
{
    var pairs = new List<KeyValuePair<string, string>>
                {
new KeyValuePair<string, string>( "grant_type", "password" ), 
new KeyValuePair<string, string>( "username", userName ), 
new KeyValuePair<string, string> ( "Password", password )
                };
    var content = new FormUrlEncodedContent(pairs);
using(var client = new HttpClient())
    {
        var response =
            client.PostAsync("http://localhost:62069/Token", content).Result;
        var result = response.Content.ReadAsStringAsync().Result;
// Deserialize the JSON into a Dictionary<string, string>
        Dictionary<string, string> tokenDictionary =
            JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
return tokenDictionary;
    }
}

 

Now let's update the Main() method to use our new dictionary, and write the various token properties out individually to the console:

Update Main() Method to Consume Deserialized Token Information:
static void Main(string[] args)
{
    string userName = "john@example.com";
    string password = "Password@123";
    var registerResult = Register(userName, password);
    Console.WriteLine("resitration Status Code: {0}", registerResult);
    //string token = GetToken(userName, password);
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
    // Write each item in the dictionary out to the console:
    foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
    Console.WriteLine("");
    Console.Read();
}

 

If we run the two applications now, we see the console output looks a little different:

Console Output Using the GetTokenDictionary() Method:
Registration Status Code: BadRequest
Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: zPrC7-CyHljhkPYQIDawhu7kgRd86p7oSJpRqHGifuANmEtM61syU5t6ciPGJrA3RX
I9u79IIOFaV3w5_GAQeF28DlUnc2HSkCxZsnqaYojLWfJ6gc8gfUlZo76SeJ7iO7MT6fdo8C5XgM_Geq
yun_8ykut9N456F41dI5PrrR6CyNc0ss_hy9OzdxnoqUdERglooNUrEcEt7WdZ9FHJ-cAi15fVPfV4z4
dUZZylrIyHuNSLVReet-zL769IEPvhgYixrp_hMgGQ6lDx8YMPTWvK_SVbe4W89DrHl1PbqfkiVgbJgJ
M09kmmIytNCFl_ua_GOdx1WyxXfPv0TLOmAgPX3klI4r_pglZl1QA0vihTN7zLsP2bkxIbMCBac3kq8z
4JT1JalxZ0OgArkW-Gy2qZJ-o-mPATCPUXLHtEd3z4lze17ECuCJyZzfLts3NN-hJgNwbmcqvGNvcakp
Y6SQ6U_ACdBJ3Q2JgZZeWf75pDupjeQbMhTqAPWUq9n35k
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Wed, 17 Sep 2014 02:55:45 GMT
.expires: Wed, 01 Oct 2014 02:55:45 GMT

 

First of all, why does it say "Bad Request" for our registration status code? We haven't changed THAT part of the code at all . . .  and there is the problem.

We have already registered a user named john@example.com, and Web Api has tossed back a validation error (the details of which are actually buried in the response content, but we'll worry about that later).

We can ignore that for now.

The next part of our console output is what we're interested in. Notice that, while the big, encrypted access_token still looks like a big blob of gibberish, our token as a whole is nicely split into its component properties on each line.

Now, let's try to access some of the Identity information from our Api. If we take a look at the AccountController in our Web Api project, we see there is a controller method named GetUserInfo() . Because our GetUserInfo() is decorated with the [Route] attribute “UserInfo" and our account controller [Route] attribute specifies a route of “api/Account” we know we can access this  method using the route “<host>/api/Account/UserInfo.”

Add the following static method to the Program class in our console application:

Add a GetUserInfo() Method to the Program Class:
staticstring GetUserInfo()
{
using(var client = new HttpClient())
    {
        var response = 
            client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
return response.Content.ReadAsStringAsync().Result;
    }
}

 

This simple method uses an instance of HttpClient to access the GetUserInfo() method on our AccountController, reads the response content as a string, and returns the result.

Now, we can call this method from the Main() method of our Console program and see what we get back. Update the Main() method of the Program class as follows:

Add a Call to GetUserInfo() to the Main() Method of the Program Class:
staticvoid Main(string[] args)
{
string userName = "john@example.com";
string password = "Password@123";
    var registerResult = Register(userName, password);
    Console.WriteLine("Registration Status Code: {0}", registerResult);
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
// Write each item in the dictionary out to the console:
foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
    Console.WriteLine("");
    Console.WriteLine("Getting User Info:");
    Console.WriteLine(GetUserInfo());
}

 

Now, start your Web Api project again, wait for it to spin up completely, and then run the console application. Your console output should look something like this:

Console Output After Updating Client with Call to GetUserInfo() Method:
Registration Status Code: BadRequest
Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: c47uW0q-1qsIm88et81YqFzGz0Nt2GflLZJ3nLLDUPIS8epwMiBMkG9lCmF7-Rk8Ji
KA33JJkgtFl-3mjn78N-iQcX2pLxEsYf4h65njj2BaSRCSheCyfWY5WcS2MPipRFfwr1e-wx49R4Awo3
DHk2nJmMe_ARIASzw7Ger4gpJgNrqxt8B4QWcJyjgrr7RwK95alKQ4MY-ZlzJyNdWthdCSeykTvzLJQ-
rGjH7KT-SYwknyt62Fm2bwE7WzcudFgs1RIq8HDzuPiM9Fx9dBLhhPT2sCq8iV1dDFrCTnDsNoLA5ncG
y9BncGFb5fmkqibP1tV8k2xW0OxqaAuVz4jaS212--o2P9JQ5kCmC6gSYH0faBgNva3SV8uZnM64YoyY
gJ3i_lOql0pxxjtqJYUYQLYSDwzYVJXXl_PiKLHGrjZhtn480kzSdfkgdv1i-jiqap2ymzIeJjGcd6Tm
fePqCXeiKLUEO3FsOJ4VeRkXFXEkXpFBbuGWIe6N64M4M3
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Sun, 21 Sep 2014 00:56:49 GMT
.expires: Sun, 05 Oct 2014 00:56:49 GMT
Getting User Info:
{"Message":"Authorization has been denied for this request."}

 

But . . . wait. What happened? The last line, the result of our call to GetUserInfo() says authorization has been denied. What are we missing?

Notice that our AccountController class is decorated with an [Authorize] attribute in the class declaration. As you probably already realize, this mean that not just any old body can call into the AccountController. The class itself is decorated with the [Authorize] Attribute, so by default only authorized users can call Action methods defined on the class using HTTP. The Register() method has been decorated with an [AllowAnonymous] attribute, so unauthorized/unregistered users can register. but the rest of the methods are not accessible to unauthorized users.

In our case, despite the fact that we have actually obtained an access token from our Web Api by calling the Token endpoint of the Web Api application, we have not actually provided the token with our request to GetUserInfo().

Setting the Default Access Token For Web Api Requests

In order to create pass a token in with our HTTP requests, we can use the DefaultRequestHeaders property of HttpClient like so:

Set the Default Authorization Header for Client Requests:
HttpClient client = new HttpClient();
client.DefaultRequestHeaders.Authorization = 
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);

 

We can modify the GetUserInfo() method on our Program class like so:

Set Default Authorization Header on Request for GetUserInfo() Method:
staticstring GetUserInfo(string token)
{
using(var client = new HttpClient())
    {
        client.DefaultRequestHeaders.Authorization = 
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
        var response = client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
return response.Content.ReadAsStringAsync().Result;
    }
}

 

Notice we are now passing an access token in as a method argument, specifying that it is a Bearer token, and then using that token to set in our default Authorization header.

Now, we simply need to pass that token to the method when we call it from Main() :

Pass the Access Token to GetUserInfo() when Calling from Main():
staticvoid Main(string[] args)
{
string userName = "john@example.com";
string password = "Password@123";
    var registerResult = Register(userName, password);
    Console.WriteLine("Registration Status Code: {0}", registerResult);
    Dictionary<string, string> token = GetTokenDictionary(userName, password);
    Console.WriteLine("");
    Console.WriteLine("Access Token:");
    Console.WriteLine(token);
// Write each item in the dictionary out to the console:
foreach (var kvp in token)
    {
        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
    }
    Console.WriteLine("");
    Console.WriteLine("Getting User Info:");
Console.WriteLine(GetUserInfo(token["access_token"]));
}

 

Take note – we are not passing in the entire token dictionary returned from the GetToken() method here – only the actual access_token itself. In this code, we are pulling it out of our token dictionary using the ”access_token” key when we pass it as an argument to the GetUserInfo() method.

If we run the Console application now, we get the following:

Running the Console Application and Passing a Proper Auth Token:
Registration Status Code: BadRequest
Access Token:
System.Collections.Generic.Dictionary`2[System.String,System.String]
access_token: ygYowtlVKbwyd3J9Lown2Py2IcMEwGgjfS5YAbJJjlhADh4HURG6upqIah4zQjqLgH
MjlyuiwKEcpzDv95Y0OpIqGO5pU_I4MmHNnLttMFORDFo-u4B0q9KUsiGskHjt_q25cIy5ZZNAejmA4B
u8qJKuxWagK33-XlQYMD_USVTShfUFkjMpi7IxffPmjpzWl5ipUzxnu4t-4LpR87QuWwIv7novf_o8Sl
9EAXc7ySqDZ0SzB1WgtDK4or7oLeIFMkouwOD9PK-E3FJTTmfpPtXT6RIdL93FEYM5oxgxTiHSLt_cRL
1Mb5kyIILcl6dCR7OuGn_8QN3jabKOmXg5q5XE52m--BMzJwUESTzXjDge-_2XoNWI09jTki9RXWg2fV
PL7DIhSwSfIff8AE0hiZm2cvEYaqPHzej221TKI_YX9DQGOrtmfLLpxx_lmtfbN1rbnwYYSa51d_vPDV
yzsfZbC2vA-xzxWJS3LP4Qm_I8ZvJp-JKVu47Q-Y5Z0ZG_
token_type: bearer
expires_in: 1209599
userName: john@example.com
.issued: Sun, 21 Sep 2014 02:23:36 GMT
.expires: Sun, 05 Oct 2014 02:23:36 GMT
Getting User Info:
{"Email":"john@example.com","HasRegistered":true,"LoginProvider":null}

 

Now, that’s more like it.

Clean Up that Damn Code!

You may have notices that our examples have begun to take on some “code smells.” Well, for one, these are just examples, dammit. However, we can immediately see some opportunities to clean things up a bit, do a little refactoring.

How you would actually approach this would totally depend upon your specific project needs. But we can see right away that every time we go to access our Web Api from our client, we need an instance of HttpClient . Also, it is very likely that more often than not, we will need to be including an Auth token as part of our request.

We might add a static factory method, CreateClient() to handle this for us, and then call this from each of our client methods:

Add a CreateClient() Method (for example):
static HttpClient CreateClient(string accessToken = "")
{
    var client = new HttpClient();
if(!string.IsNullOrWhiteSpace(accessToken))
    {
        client.DefaultRequestHeaders.Authorization = 
new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
    }
return client;            
}

 

Now, if a token is provided, the default Authorization header will be added. If not, an HttpClient will be returned without Authorization header.

Now, our GetUserInfo() method from the Console application might look like this:

Modified GetUserInfo() method:
staticstring GetUserInfo(string token)
{
using(var client = CreateClient(token))
    {
        var response = client.GetAsync("http://localhost:62069/api/Account/UserInfo").Result;
return response.Content.ReadAsStringAsync().Result;
    }
}

 

We still have the using block, and we really only saved one line of code. However, the initialization of the HttpClient, and the setting of the access token now all happen in the same place.

A Note About Security, Bearer Tokens, and SSL

As mentioned earlier, an ASP.NET Web Api project uses Bearer tokens out of the box when using the default Visual Studio project template. In order to implement proper security, Api’s which use this sort of authentication should ALWAYS use SSL/TLS, especially when accepting user credentials in order to provide the access token at the Token endpoint.

What the Default ASP.NET Web Api Project does NOT Have

You may notice that there are no Role management methods, no RolesAdminController (or even a UserAdminController) in the basic Identity-based Web Api project. In fact, there are no Roles at all at this early stage. The AccountController contains methods sufficient to Register a new user, perform some basic management (such as changing passwords), and not much else.

If we want role-based authorization in our Web Api project, we will need to add it ourselves. Similarly, if we want a little more admin flexibility via our Api (or even using a few MVC pages within the application for GUI-based Administration), we will also need to add that ourselves.

Last, before we charge in adding Roles and such, we will want to examine whether Role-Based Authorization is the best fit for our needs. Identity 2.0, and Web Api easily support Claims-Based Authorization, which offers some distinct advantages for more complex authorization scenarios.

We will look at all of this, and more, in upcoming posts.

Looking Deeper into Identity 2.0 and Web Api

In this post, we’ve taken a very broad look at the structure of a Web Api 2.2 project, and where the major pieces of the Identity 2.0 framework fit. We’ve looked at using Bearer tokes as the default authentication mechanism, how to retrieve a token from your Api Token endpoint, and how to perform some very basic Api access.

In upcoming posts we will:

  • Look more closely at Token-based authentication and authorization, and how it relates to the familiar Users and Roles model we are familiar with
  • Extend Identity 2.0 models in the context of ASP.NET Web Api
  • Serializing and de-serializing Model data to and from HTTP requests and responses
  • Customizing Identity Management for Web Api
  • Creating an Authentication Service using Identity 2.0 and ASP.NET Web Api

This has been basically the 101-level introduction to using Identity 2.0 and ASP.NET Web Api. There is more to come, and a lot to understand in order to get the most out of the ASP.NET Identity framework in a Web Api context, and to properly secure a Web Api.

Additional Resources and Items of Interest


ASP.NET Web Api: Unwrapping HTTP Error Results and Model State Dictionaries Client-Side

$
0
0

404 on wall-320When working with ASP.NET Web Api from a .NET client, one of the more confounding things can be handling the case where errors are returned from the Api. Specifically, unwrapping the various types of errors which may be returned from a specific API action method, and translating the error content into meaningful information for use be the client.

How we handle the various types of errors that may be returned to our Api client applications can be very dependent upon specific application needs, and indeed, the type of client we are building.

Image by Damien Roué  |  Some Rights Reserved

In this post we'll look at some general types of issues we might run into when handing error results client-side, and hopefully find some insight we can apply to specific cases as they arise.

Understanding HTTP Response Creation in the ApiController

Most Web Api Action methods will return one of the following:

  • Void: If the action method returns void, the HTTP Response created by ASP.NET Web Api will have a 204 status code, meaning "no content."
  • HttpResponseMessage: If the Action method returns an HttpResponseMessage, then the value will be converted directly into an HTTP response message. We can use the Request.CreateResponse() method to create instances of HttpResponseMessage, and we can optionally pass domain models as a method argument, which will then be serialized as part of the resulting HTTP response message.
  • IHttpActionResult: Introduced with ASP.NET Web API 2.0, the IHttpActionResult interface provides a handy abstraction over the mechanics of creating an HttpResponseMessage. Also, there are a host of pre-defined implementations for IHttpActionResult defined in System.Web.Http.Results, and the ApiController class provides helper methods which return various forms of IHttpActionResult, usable directly within the controller.
  • Other Type: Any other return type will need to be serialized using an appropriate media formatter.

For more details on the above, see Action Results in Web API 2 by Mike Wasson.

From Web Api 2.0 onward, the recommended return type for most Web Api Action methods is IHttpActionResult unless this type simply doesn't make sense.

Create a New ASP.NET Web Api Project in Visual Studio

To keep things general and basic, let's start by spinning up a standard ASP.NET Web Api project using the default Visual Studio Template. If you are new to Web Api, take a moment to review the basics, and get familiar with the project structure and where things live.

Make sure to update the Nuget packages after you create the project.

Create a Basic Console Client Application

Next, let's put together a very rudimentary client application. Open another instance of Visual Studio, and create a new Console application. Then, use the Nuget package manager to install the ASP.NET Web Api Client Libraries into the solution.

We're going to use the simple Register() method as our starting point to see how we might need to unwrap some errors in order to create a more useful error handling model on the client side.

The Register Method from the Account Controller

If we return to our Web Api project and examine the Register() method, we see the following:

The Register() method from AccountController:
[AllowAnonymous]
[Route("Register")]
public async Task<IHttpActionResult> Register(RegisterBindingModel model)
{
if (!ModelState.IsValid)
    {
return BadRequest(ModelState);
    }
    var user = new ApplicationUser() 
    { 
        UserName = model.Email, 
        Email = model.Email 
    };
    IdentityResult result = await UserManager.CreateAsync(user, model.Password);
if (!result.Succeeded)
    {
return GetErrorResult(result);
    }
return Ok();
}

 

In the above, we can see that there are a number of options for what might be returned as our IHttpActionResult.

First, if the Model state is invalid, the BadRequest() helper method defined as part of the ApiController class will be called, and will be passed the current ModelStateDictionary. This represents simple validation, and no additional processes or database requests have been called.

If the Mode State is valid, the CreateAsync() method of the UserManager is called, returning an IdentityResult. If the Succeeded property is not true, then GetErrorResult() is called, and passed the result of the call to CreateAsync().

GetErrorResult() is a handy helper method which returns the appropriate IHttpActionResult for a given error condition.

The GetErrorResult Method from AccountController
private IHttpActionResult GetErrorResult(IdentityResult result)
{
if (result == null)
    {
return InternalServerError();
    }
if (!result.Succeeded)
    {
if (result.Errors != null)
        {
foreach (string error in result.Errors)
            {
                ModelState.AddModelError("", error);
            }
        }
if (ModelState.IsValid)
        {
// No ModelState errors are available to send, 
// so just return an empty BadRequest.
return BadRequest();
        }
return BadRequest(ModelState);
    }
returnnull;
}

 

From the above, we can see we might get back a number of different responses, each with a slightly different content, which should assist the client in determining what went wrong.

Making a Flawed Request - Validation Errors

So, let's see some of the ways things can go wrong when making a simple POST request to the Register() method from our Console client application.

Add the following code to the console application. Note that we are intentionally making a flawed request. We will pass a valid password and a matching confirmation password, but we will pass an invalid email address. We know that Web Api will not like this, and should kick back a Model State Error as a result.

Flawed Request Code for the Console Client Application:
staticvoid Main(string[] args)
{
// This is not a valid email address, so the POST should fail:
string email = "john";
string password = "Password@123";
string confirmPassword = "Password@123";
    HttpResponseMessage result = 
        Register(email, password, confirmPassword);
if(result.IsSuccessStatusCode)
    {
        Console.WriteLine(
"The new user {0} has been successfully added.", email);
    }
else
    {
        Console.WriteLine(result.ReasonPhrase);
    }
    Console.Read();
}
publicstatic HttpResponseMessage Register(
string email, string password, string confirmPassword)
{
//Attempt to register:
using (var client = new HttpClient())
    {
        var response =
            client.PostAsJsonAsync("http://localhost:51137/api/Account/Register",
// Pass in an anonymous object that maps to the expected 
// RegisterUserBindingModel defined as the method parameter 
// for the Register method on the API:
new
            {
                Email = email,
                Password = password,
                ConfirmPassword = confirmPassword
            }).Result;
return response;
    }
}

If we run our Web Api application, wait for it to spin up, and then run our console app, we see the following output:

Console output from the flawed request:
Bad Request

 

Well, that's not very helpful.

If we de-serialize the response content to a string, we see there is more information to be had. Update the Main() method as follows:

De-serialize the Response Content:
staticvoid Main(string[] args)
{
// This is not a valid email address, so the POST should fail:
string email = "john";
string password = "Password@123";
string confirmPassword = "Password@123";
    HttpResponseMessage result = 
        Register(email, password, confirmPassword);
if(result.IsSuccessStatusCode)
    {
        Console.WriteLine(
"The new user {0} has been successfully added.", email);
    }
else
    {
string content = result.Content.ReadAsStringAsync().Result;
        Console.WriteLine(content);
    }
    Console.Read();
}

 

Now, if we run the Console application again, we see the following output:

Output from the Console Application with De-Serialized Response Content:
{"Message":"The request is invalid.","ModelState":{"":["Email 'john' is invalid."]}}

 

Now, what we see above is JSON. Clearly the JSON object contains a Message property and a ModelState property. But the ModelState property, itself another JSON object, contains an unnamed property, an array containing the error which occurred when validating the model.

Since a JSON object is essentially nothing but a set of key/value pairs, we would normally expect to be able to unroll a JSON object into a Dictionary<string, object>. However, the nameless property(ies) enumerated in the ModelState dictionary on the server side makes this challenging.

Unwrapping such an object using the Newtonsoft.Json library is doable, but slightly painful. Equally important, an error returned from our API may, or may not have a ModelState dictionary associated with it.

Another Flawed Request - More Validation Errors

Say we figured out that we need to provide a valid email address when we submit our request to the Register() method. Suppose instead, we are not paying attention and instead enter two slightly different passwords, and also forget that passwords have a minimum length.

Modify the code in the Main() method again as follows:

Flawed Request with Password Mismatch:
{
"Message":"The request is invalid.",
"ModelState": {
"model.Password": [
"The Password must be at least 6 characters long."],
"model.ConfirmPassword": [
"The password and confirmation password do not match."]
    }
}

 

In this case, it appears the items in the ModelState Dictionary are represented by valid key/value pairs, and the value for each key is an array.

Server Errors and Exceptions

We've seen a few examples of what can happen when the model we are passing with our POST request is invalid. But what happens if our Api is unavailable?

Let's pretend we finally managed to get our email and our passwords correct, but now the server is off-line.

Stop the Web Api application, and then re-run the Console application. Of course, after a reasonable server time-out, our client application throws an AggregateException.

What's an AggregateException? Well, it is what we get when an exception occurs during execution of an async method. If we pretend we don't know WHY our request failed, we would need to dig down into the InnerExceptions property of the AggregateException to find some useful information.

In the context of our rudimentary Console application, we will implement some top-level exception handling so that our Console can report the results of any exceptions like this to us.

Update the Main() method once again, as follows:

Add Exception Handling to the Main() Method of the Console Application:
staticvoid Main(string[] args)
{
// This is not a valid email address, so the POST should fail:
string email = "john@example.com";
string password = "Password@123";
string confirmPassword = "Password@123";
// Add a Try/Catch in case something goes wrong and the server throws:
try
    {
        HttpResponseMessage result =
            Register(email, password, confirmPassword);
if (result.IsSuccessStatusCode)
        {
            Console.WriteLine(
"The new user {0} has been successfully added.", email);
        }
else
        {
string content = result.Content.ReadAsStringAsync().Result;
            Console.WriteLine(content);
        }
    }
catch (AggregateException ex)
    {
        Console.WriteLine("One or more exceptions has occurred:");
foreach (var exception in ex.InnerExceptions)
        {
            Console.WriteLine("" + exception.Message);
        }
    }
    Console.Read();
}

 

If we run our console app now, while our Web Api application is offline, we get the following result:

Console Output with Exception Handling and Server Time-Out:
One or more exceptions has occurred:
  An error occurred while sending the request.

 

Here, we are informed that "An error occurred while sending the request" which at least tells us something, and averts the application crashing due to an unhandled AggregateException.

Unwrapping and Handling Errors and Exceptions in Web Api

We've seen a few different varieties of errors and exceptions which may arise when registering a user from our client application.

While outputting JSON from the response content is somewhat helpful, I doubt it's what we are looking for as Console output. What we need is a way to unwrap the various types of response content, and display useful console messages in a clean, concise format that is useful to the user.

While I was putting together a more in-depth, interactive console project for a future article, I implemented a custom exception, and a special method to handle these cases.

ApiException - a Custom Exception for Api Errors

Yeah, yeah, I know. Some of the cases above don't technically represent "Exceptions" by the hallowed definition of the term. In the case of a simple console application, however, a simple, exception-based system makes sense. Further, unwrapping all of our Api errors up behind a single abstraction makes it easy to demonstrate how to unwrap them.

Mileage may vary according to the specific needs of YOUR application. Obviously, GUI-based applications may extend or expand upon this approach, relying less on Try/Catch and throwing exceptions, and more upon the specifics of the GUI elements available.

Add a class named ApiException to the Console project, and add the following code:

ApiException - a Custom Exception
using System;
using System.Collections.Generic;
using System.Linq;
using System.Net;
using System.Net.Http;
namespace ApiWithErrorsTest
{
publicclass ApiException : Exception
    {
public HttpResponseMessage Response { get; set; }
public ApiException(HttpResponseMessage response)
        {
this.Response = response;
        }
public HttpStatusCode StatusCode
        {
get
            {
returnthis.Response.StatusCode;
            }
        }
public IEnumerable<string> Errors
        {
get
            {
returnthis.Data.Values.Cast<string>().ToList();
            }
        }
    }
}

 

Unwrapping Error Responses and Model State Dictionaries

Next, let's add a method to our Program which accepts an HttpResponseMessage as a method argument, and returns an instance of ApiException. Add the following code the the Program class of the Console application:

Add the CreateApiException Method the to Program Class:
publicstatic ApiException CreateApiException(HttpResponseMessage response)
{
    var httpErrorObject = response.Content.ReadAsStringAsync().Result;
// Create an anonymous object to use as the template for deserialization:
    var anonymousErrorObject = 
new { message = "", ModelState = new Dictionary<string, string[]>() };
// Deserialize:
    var deserializedErrorObject = 
        JsonConvert.DeserializeAnonymousType(httpErrorObject, anonymousErrorObject);
// Now wrap into an exception which best fullfills the needs of your application:
    var ex = new ApiException(response);
// Sometimes, there may be Model Errors:
if (deserializedErrorObject.ModelState != null)
    {
        var errors = 
            deserializedErrorObject.ModelState
                                    .Select(kvp => string.Join(". ", kvp.Value));
for (int i = 0; i < errors.Count(); i++)
        {
// Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(i, errors.ElementAt(i));
        }
    }
// Othertimes, there may not be Model Errors:
else
    {
        var error = 
            JsonConvert.DeserializeObject<Dictionary<string, string>>(httpErrorObject);
foreach (var kvp in error)
        {
// Wrap the errors up into the base Exception.Data Dictionary:
            ex.Data.Add(kvp.Key, kvp.Value);
        }
    }
return ex;
}

 

In the above, we get a sense for what goes into unwrapping an HttpResponseMessage which contains a mode state dictionary.

When the response content includes a property named ModeState, we unwind the ModelState dictionary using the magic of LINQ. We knit the string key together with the contents of the value array for each item present, and then add each item to the exception Data dictionary using an integer index for the key.

If no ModelState property is present in the response content, we simply unwrap the other errors present, and add them to the Data dictionary of the exception.

Error and Exception Handling in the Example Application

We've already added some minimal exception handling at the top level of our application. Namely, we have caught and handled AggregateExceptions which may be thrown by async calls to our api, which are not handled deeper in the call stack.

Now that we have added a custom exception, and a method for unwinding certain types error responses, let's add some additional exception handling, and see if we can do a little better, farther down.

Update the Register() method as follows:

Add Handle Errors in the Register() Method:
publicstatic HttpResponseMessage Register(
string email, string password, string confirmPassword)
{
//Attempt to register:
using (var client = new HttpClient())
    {
        var response =
            client.PostAsJsonAsync("http://localhost:51137/api/Account/Register",
// Pass in an anonymous object that maps to the expected 
// RegisterUserBindingModel defined as the method parameter 
// for the Register method on the API:
new
            {
                Email = email,
                Password = password,
                ConfirmPassword = confirmPassword
            }).Result;
if(!response.IsSuccessStatusCode)
        {
// Unwrap the response and throw as an Api Exception:
            var ex = CreateApiException(response);
throw ex;
        }
return response;
    }
}

 

You can see here, we are examining the HttpStatusCode associated with the response, and if it is anything other than successful, we call our CreateApiException() method, grab the new ApiException, and then throw.

In reality, for this simple console example we likely could have gotten by with creating a plain old System.Exception instead of a custom Exception implementation. However, for anything other than the simplest of cases, the ApiException will contain useful additional information.

Also, the fact that it is a custom exception allows us to catch ApiException and handle it specifically, as we will probably want our application to behave differently in response to an error condition in an Api response than we would other exceptions.

Now, all we need to do (for our super-simple example client, anyway) is handle ApiException specifically in our Main() method.

Catch ApiException in Main() Method

Now we want to be able to catch any flying ApiExceptions in Main(). Our Console application, shining example of architecture and complex design requirements that it is, pretty much only needs a single point of error handling to properly unwrap exceptions and write them out as console text!

Add the following code to Main() :

Handle ApiException in the Main() Method:
staticvoid Main(string[] args)
{
// This is not a valid email address, so the POST should fail:
string email = "john@example.com";
string password = "Password@123";
string confirmPassword = "Password@123";
// Add a Try/Cathc in case something goes wrong and the server throws:
try
    {
        HttpResponseMessage result =
            Register(email, password, confirmPassword);
if (result.IsSuccessStatusCode)
        {
            Console.WriteLine(
"The new user {0} has been successfully added.", email);
        }
else
        {
string content = result.Content.ReadAsStringAsync().Result;
            Console.WriteLine(content);
        }
    }
catch (AggregateException ex)
    {
        Console.WriteLine("One or more exceptions has occurred:");
foreach (var exception in ex.InnerExceptions)
        {
            Console.WriteLine("" + exception.Message);
        }
    }
catch(ApiException apiEx)
    {
        var sb = new StringBuilder();
        sb.AppendLine("  An Error Occurred:");
        sb.AppendLine(string.Format("    Status Code: {0}", apiEx.StatusCode.ToString()));
        sb.AppendLine("    Errors:");
foreach (var error in apiEx.Errors)
        {
            sb.AppendLine("" + error);
        }
// Write the error info to the console:
        Console.WriteLine(sb.ToString());
    }
    Console.Read();
}

 

All we are doing in the above is unwinding the ApiException and transforming the contents for the Data dictionary into console output (with some pretty hackey indentation).

Now let's see how it all works.

Running Through More Error Scenarios with Error and Exception Handling

Stepping all the way back to the beginning, lets see what happens now if we try to register a user with an invalid email address.

Change our registration values in Main() back to the following:

// This is not a valid email address, so the POST should fail:
string email = "john";
string password = "Password@123";
string confirmPassword = "Password@123";

 

Run the Web Api application once more. Once it has properly started, run the Console application with the modified registration values. The output to the console should look like this:

Register a User with Invalid Email Address:
An Error Occurred:
Status Code: BadRequest
Errors:
  Email 'john' is invalid.

 

Similarly, if we use a valid email address, but password values which are both too short, and also do not match, we get the following output:

Register a User with Invalid Password:
An Error Occurred:
Status Code: BadRequest
Errors:
  The Password must be at least 6 characters long.
  The password and confirmation password do not match.

 

Finally, let's see what happens if we attempt to register the same user more than once.

Change the registration values to the following:

Using Valid Registration Values:
string email = "john@example.com";
string password = "Password@123";
string confirmPassword = "Password@123";

 

Now, run the console application twice in a row. The first time, the console output should be:

Console Output from Successful User Registration:
The new user john@example.com has been successfully added.

 

The next time, however, an error result is returned from our Web Api:

Console Output from Duplicate User Registration:
An Error Occurred:
Status Code: BadRequest
Errors:
  Name john@example.com is already taken.. Email 'simon@example.com' is already taken.

 

Oh No You did NOT Use Exceptions to Deal with Api Errors!!

Oh, yes I did . . . at least, in this case. This is a simple, console-based application in which nearly every result needs to end up as text output. Also, I'm just a rebel like that, I guess. Sometimes.

The important thing to realize is how to get the information we need out of the JSON which makes up the response content, and that is not as straightforward as it may seem in this case. How different errors are dealt with will, as always, need to be addressed within terms best suited for your application.

In a good many cases, treating Api errors as exceptions, to me, has merit. Doing so most likely will rub some architecture purists the wrong way (many of the errors incoming in response content don't really meet the textbook definition of "exception"). That said, for less complex .NET-based Api Client applications, unwrapping the errors from the response content, and throwing as exceptions to be caught by an appropriate handler can save on a lot of duplicate code, and provides a known mechanism for handling problems.

In other cases, or for your own purposes, you may choose to re-work the code above to pull out what you need from the incoming error response, but otherwise deal with the errors without using exceptions. Register() (and whatever other methods you use to call into your Api) might, in the case of a simple console application, return strings, ready for output. In this case, you could side-step the exception issue.

Needless to say, a good bit of the time, you will likely by calling into your Web Api application not from a desktop .NET application, but instead from a web client, probably using Ajax or something.

That's a Long and Crazy Post about Dealing with Errors - Wtf?

Well, I am building out a more complex, interactive console-based application in order to demo some concepts in upcoming posts. One of the more irritating aspects of that process was figuring out a reasonable way to deal with the various issues that may arise, when all one has to work with is a command line interface to report output to the user.

This was part of that solution (ok, in the application I'm building, things are a little more complex, a little more organized, and there's more to it. But here we saw some of the basics).

But . . . Can't We Just do it Differently on the Server?

Well . . . YES!

In all likelihood, you just might tune up how and what you are pushing out to the client, depending upon the nature of your Web Api and the expected client use case. In this post, I went with the basic, default set-up (and really, we only looked at one method). But, depending upon how your Api will be used, you might very will handle errors and exceptions differently on the server side, which may impact how you handle things on the client side.

Additional Resources and Items of Interest

ASP.NET Web Api and Identity 2.0 - Customizing Identity Models and Implementing Role-Based Authorization

$
0
0

hermself 240In a previous post, we took a high-level look at using Identity 2.0 in the context of a Web Api application. We essentially poked and prodded the default Visual Studio Web Api project template, learned where things live, and got a basic sense for how it all is supposed to work.

However, the VS project template is very basic, using Bearer Tokens as the primary authentication mechanism, and does not offer any out-of-the-box support for advanced authorization scenarios. In a nutshell, the VS Project template affords us basic token-based authentication, and that's about it.

Additionally, the User model is simplistic, and there are no Role models defined. This may be intentional, since in some cases you may be using a Web Api project as a simple authentication service. In other scenarios, though, you may want to customize the User model and/or add Role-Based Authentication to the mix.

Image by madamepsychosis  | Some Rights Reserved

We have previously looked at customizing User and Role models in the context of an ASP.NET MVC application, and how we need to modify the stock MVC project to accommodate these customizations. In this post, we will do the same for a Web Api project.

You can find the source code for the example Web Api project on Github:

Consider Your Use Case Before Deciding on Your Auth Strategy

There are a number of options for Authentication and Authorization strategies in a Web Api project. Use of Bearer tokens and Role-Based Authentication is relatively simple to implement, but is not the most advanced architecture for an authorization solution. Before deciding upon traditional Role-Based Authorization, you may want to examine the scope of your authentication and authorization needs, and determine if something simpler, or something more advanced, may be warranted. 

ASP.NET Web Api can take full advantage of Claims-Based Authorization, which, for more complex systems, may be a better choice. Similarly, as mentioned previously, if the primary purpose of your Web Api is to act as an Authentication Service, you may want to go with a more robust token system (for example, shared private keys as opposed to the bearer tokens used by default), and do away with authorization at this level.

Role-Based Authorization is a good fit in a project where there exists a modest need for different levels of authorization/access, and possibly the Web Api is a part of, or associated with, a larger MVC or other ASP.NET site where Roles are used to govern authorization. Consider a standard MVC project, in which a few roles are sufficient to manage authorization, and which serves web pages as well as offers API access.

Applying What We've Learned Previously

Fortunately, much of what we are about to do, we have seen previously, and we can even borrow bits and pieces of code we've already written. If you are just getting familiar with Identity 2.0, feel free to review previous posts in which we performed some similar customization of Users and Roles in the context of an ASP.NET MVC project:

Now that we have some idea what we are dealing with, let's see how we can apply it in the Web Api context.

Getting Started - Create a New ASP.NET Web Api Project

First, in Visual Studio, create a new ASP.NET Web Api project. Once the project is created, update the Nuget packages in the solution, either using Manage Packages for Solution in the context menu for Solution Explorer, or by using Update-Package in the Package Manager Console.

This will update all the nuget packages, and specifically update Web Api to version 2.2.

Adding a Role Model, and Customizing ApplicationUser

To get started, let's take another look at the Models => IdentityModes.cs file. Currently, there is not a lot there:

The Default IdentityModels.cs File in Web Api:
using System.Security.Claims;
using System.Threading.Tasks;
using Microsoft.AspNet.Identity;
using Microsoft.AspNet.Identity.EntityFramework;
using Microsoft.AspNet.Identity.Owin;
namespace AspNetIdentity2WebApiCustomize.Models
{
publicclass ApplicationUser : IdentityUser
    {
public async Task<ClaimsIdentity> GenerateUserIdentityAsync(
        		UserManager<ApplicationUser> manager, string authenticationType)
        {
// Note the authenticationType must match the one defined in 
// CookieAuthenticationOptions.AuthenticationType
            var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
        }
    }
publicclass ApplicationDbContext : IdentityDbContext<ApplicationUser>
    {
public ApplicationDbContext()
            : base("DefaultConnection", throwIfV1Schema: false)
        {
        }
publicstatic ApplicationDbContext Create()
        {
returnnew ApplicationDbContext();
        }
    }
}

 

As we did in our ASP.NET MVC examples, we begin by modifying and adding to the existing models defined in Models => IdentityModels.cs. In fact, since we did a lot of the work previously, we will start by stealing the IdentityModels.cs code from the ASP.NET Extensible Template Project. Careful here. We can save ourselves some pain by pasting the classes into the existing namespace defined in the current code file, and leaving the using statements as they are for the moment:

Updated IdentityModels.cs Code:
// You will not likely need to customize there, but it is necessary/easier to create our own 
// project-specific implementations, so here they are:
publicclass ApplicationUserLogin : IdentityUserLogin<string> { }
publicclass ApplicationUserClaim : IdentityUserClaim<string> { }
publicclass ApplicationUserRole : IdentityUserRole<string> { }
// Must be expressed in terms of our custom Role and other types:
publicclass ApplicationUser 
    : IdentityUser<string, ApplicationUserLogin, 
    ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationUser()
    {
this.Id = Guid.NewGuid().ToString();
// Add any custom User properties/code here
    }
public async Task<ClaimsIdentity>
        GenerateUserIdentityAsync(ApplicationUserManager manager)
    {
        var userIdentity = await manager
            .CreateIdentityAsync(this, DefaultAuthenticationTypes.ApplicationCookie);
return userIdentity;
    }
}
// Must be expressed in terms of our custom UserRole:
publicclass ApplicationRole : IdentityRole<string, ApplicationUserRole>
{
public ApplicationRole() 
    {
this.Id = Guid.NewGuid().ToString();
    }
public ApplicationRole(string name)
        : this()
    {
this.Name = name;
    }
// Add any custom Role properties/code here
}
// Must be expressed in terms of our custom types:
publicclass ApplicationDbContext 
    : IdentityDbContext<ApplicationUser, ApplicationRole, 
string, ApplicationUserLogin, ApplicationUserRole, ApplicationUserClaim>
{
public ApplicationDbContext()
        : base("DefaultConnection")
    {
    }
static ApplicationDbContext()
    {
        Database.SetInitializer<ApplicationDbContext>(new ApplicationDbInitializer());
    }
publicstatic ApplicationDbContext Create()
    {
returnnew ApplicationDbContext();
    }
// Add additional items here as needed
}
// Most likely won't need to customize these either, but they were needed because we implemented
// custom versions of all the other types:
publicclass ApplicationUserStore 
    :UserStore<ApplicationUser, ApplicationRole, string,
        ApplicationUserLogin, ApplicationUserRole, 
        ApplicationUserClaim>, IUserStore<ApplicationUser, string>, 
    IDisposable
{
public ApplicationUserStore()
        : this(new IdentityDbContext())
    {
base.DisposeContext = true;
    }
public ApplicationUserStore(DbContext context)
        : base(context)
    {
    }
}
publicclass ApplicationRoleStore
: RoleStore<ApplicationRole, string, ApplicationUserRole>,
IQueryableRoleStore<ApplicationRole, string>,
IRoleStore<ApplicationRole, string>, IDisposable
{
public ApplicationRoleStore()
        : base(new IdentityDbContext())
    {
base.DisposeContext = true;
    }
public ApplicationRoleStore(DbContext context)
        : base(context)
    {
    }
}

 

Now, we need to add a few additional using statements at the top of the code file to bring in some references we need with the new code. Add the following to the using statements at the top of the file:

Additional Using Statements Added to IdentityModels.cs:
using System.Data.Entity;
using System.ComponentModel.DataAnnotations;
using System;

 

There are two immediate problems with the code we just pasted in there. The first is probably obvious, because the VS compiler is probably telling you that there is no DBInitializer class defined. Also, if you Build the project, a few other problems will surface in the VS error list. We'll take care of that in a moment.

The other is not so obvious. The code we pasted in here is from an MVC project. For the most part this is fine. However, our ApplicationUser class defines a method GenerateUserIdentityAsync. The code we stole from our MVC project has this method, but defines it in terms of a single parameter of type ApplicationUserManager. Recall the code we pasted over, which defined ApplicationUser with two constructor parameters. The missing parameter in our newly copied method is of type string, and represents the authenticationType.

This is important, because GenerateUserIdentityAsync is called when we need to retrieve a user's ClaimsIdentity, which represents the various claims the specific user has within our system.

Confused yet? We don't need to worry about the details of ClaimsIdentity just yet. What we DO need to do is update the GenerateUserIdentityAsync method defined on ApplicationUser to accept a string parameter representing the authenticationType.

Update ApplicationUser for Web Api

To make our ApplicationUser class ready for use in a Web Api context, we can replace the code for the GenerateUserIdentityAsync  method with the following:

Update GenerateUserIdentityAsync with Authentication Type Parameter:
// ** Add authenticationtype as method parameter:
public async Task<ClaimsIdentity>
    GenerateUserIdentityAsync(ApplicationUserManager manager, string authenticationType)
{
// Note the authenticationType must match the one defined 
// in CookieAuthenticationOptions.AuthenticationType
    var userIdentity = 
        await manager.CreateIdentityAsync(this, authenticationType);
// Add custom user claims here
return userIdentity;
}

 

                            Adding a DBInitializer and Other Identity Config Items

                            We mentioned earlier, and the compiler is helpfully pointing out to you, that the code we stole from the Identity Extensible Template project is attempting to use a DBInitializer class that doesn't exist (yet) in our Web Api project. Also, you probably notice (if you have built the project since adding the additional Identity Models), that there appear to be some problems with our new ApplicationUser class.

                            We will resolve most of these issues by once again stealing select bits of code from the Identity Extensible Template project.

                            If we look at the App_Start => IdentityConfig.cs file in our Web Api project, we see that, as with the original IdentityModels.cs file, there is not much there:

                            The Default Identity.config File from a Web Api Project:
                            using System.Threading.Tasks;
                            using Microsoft.AspNet.Identity;
                            using Microsoft.AspNet.Identity.EntityFramework;
                            using Microsoft.AspNet.Identity.Owin;
                            using Microsoft.Owin;
                            using AspNetIdentity2WebApiCustomize.Models;
                            namespace AspNetIdentity2WebApiCustomize
                            {
                            // Configure the application user manager used in this application. UserManager 
                            // is defined in ASP.NET Identity and is used by the application.
                            publicclass ApplicationUserManager : UserManager<ApplicationUser>
                                {
                            public ApplicationUserManager(IUserStore<ApplicationUser> store)
                                        : base(store)
                                    {
                                    }
                            publicstatic ApplicationUserManager Create(
                                            IdentityFactoryOptions<ApplicationUserManager> options, 
                                            IOwinContext context)
                                    {
                                        var manager = 
                            new ApplicationUserManager(
                            new UserStore<ApplicationUser>(
                                                                context.Get<ApplicationDbContext>()));
                            // Configure validation logic for usernames
                                        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
                                        {
                                            AllowOnlyAlphanumericUserNames = false,
                                            RequireUniqueEmail = true
                                        };
                            // Configure validation logic for passwords
                                        manager.PasswordValidator = new PasswordValidator
                                        {
                                            RequiredLength = 6,
                                            RequireNonLetterOrDigit = true,
                                            RequireDigit = true,
                                            RequireLowercase = true,
                                            RequireUppercase = true,
                                        };
                                        var dataProtectionProvider = options.DataProtectionProvider;
                            if (dataProtectionProvider != null)
                                        {
                                            manager.UserTokenProvider = 
                            new DataProtectorTokenProvider<ApplicationUser>(
                                                            dataProtectionProvider.Create("ASP.NET Identity"));
                                        }
                            return manager;
                                    }
                                }
                            }

                             

                            In order to work with Roles in our Web Api project, we will need an ApplicationRoleManager, and as mentioned previously, we will be adding the ApplicationDbInitializer from the Extensible Template project.

                            First, we need the following using statements at the top of the IdentityConfig.cs file:

                            Using Statements for the IdentityConfig.cs File:
                            using AspNetIdentity2WebApiCustomize.Models;
                            using Microsoft.AspNet.Identity;
                            using Microsoft.AspNet.Identity.EntityFramework;
                            using Microsoft.AspNet.Identity.Owin;
                            using Microsoft.Owin;
                            using System.Data.Entity;
                            using System.Web;

                             

                            Now, add the ApplicationRoleManager and ApplicationDbInitializer classes from the Extensible Template project to our IdentityConfig.cs file:

                            Add ApplicationRoleManager and ApplicationDbInitializer to IdentityConfig.cs:
                            using AspNetIdentity2WebApiCustomize.Models;
                            using Microsoft.AspNet.Identity;
                            using Microsoft.AspNet.Identity.EntityFramework;
                            using Microsoft.AspNet.Identity.Owin;
                            using Microsoft.Owin;
                            using System.Data.Entity;
                            using System.Web;
                            namespace AspNetIdentity2WebApiCustomize
                            {
                            publicclass ApplicationUserManager : UserManager<ApplicationUser>
                                {
                            public ApplicationUserManager(IUserStore<ApplicationUser> store)
                                        : base(store)
                                    {
                                    }
                            publicstatic ApplicationUserManager Create(
                                        IdentityFactoryOptions<ApplicationUserManager> options, 
                                        IOwinContext context)
                                    {
                                        var manager = new ApplicationUserManager(
                            new UserStore<ApplicationUser>(
                                                context.Get<ApplicationDbContext>()));
                            // Configure validation logic for usernames
                                        manager.UserValidator = new UserValidator<ApplicationUser>(manager)
                                        {
                                            AllowOnlyAlphanumericUserNames = false,
                                            RequireUniqueEmail = true
                                        };
                            // Configure validation logic for passwords
                                        manager.PasswordValidator = new PasswordValidator
                                        {
                                            RequiredLength = 6,
                                            RequireNonLetterOrDigit = true,
                                            RequireDigit = true,
                                            RequireLowercase = true,
                                            RequireUppercase = true,
                                        };
                                        var dataProtectionProvider = options.DataProtectionProvider;
                            if (dataProtectionProvider != null)
                                        {
                                            manager.UserTokenProvider = 
                            new DataProtectorTokenProvider<ApplicationUser>(
                                                    dataProtectionProvider.Create("ASP.NET Identity"));
                                        }
                            return manager;
                                    }
                                }
                            publicclass ApplicationRoleManager : RoleManager<ApplicationRole>
                                {
                            public ApplicationRoleManager(IRoleStore<ApplicationRole, string> roleStore)
                                        : base(roleStore)
                                    {
                                    }
                            publicstatic ApplicationRoleManager Create(
                                        IdentityFactoryOptions<ApplicationRoleManager> options, 
                                        IOwinContext context)
                                    {
                            returnnew ApplicationRoleManager(
                            new ApplicationRoleStore(context.Get<ApplicationDbContext>()));
                                    }
                                }
                            publicclass ApplicationDbInitializer 
                                    : DropCreateDatabaseAlways<ApplicationDbContext>
                                {
                            protectedoverridevoid Seed(ApplicationDbContext context)
                                    {
                                        InitializeIdentityForEF(context);
                            base.Seed(context);
                                    }
                            //Create User=Admin@Admin.com with password=Admin@123456 in the Admin role        
                            publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db)
                                    {
                                        var userManager = HttpContext.Current
                                            .GetOwinContext().GetUserManager<ApplicationUserManager>();
                                        var roleManager = HttpContext.Current
                                            .GetOwinContext().Get<ApplicationRoleManager>();
                            conststring name = "admin@example.com";
                            conststring password = "Admin@123456";
                            conststring roleName = "Admin";
                            //Create Role Admin if it does not exist
                                        var role = roleManager.FindByName(roleName);
                            if (role == null)
                                        {
                                            role = new ApplicationRole(roleName);
                                            var roleresult = roleManager.Create(role);
                                        }
                                        var user = userManager.FindByName(name);
                            if (user == null)
                                        {
                                            user = new ApplicationUser { UserName = name, Email = name };
                                            var result = userManager.Create(user, password);
                                            result = userManager.SetLockoutEnabled(user.Id, false);
                                        }
                            // Add user admin to Role Admin if not already added
                                        var rolesForUser = userManager.GetRoles(user.Id);
                            if (!rolesForUser.Contains(role.Name))
                                        {
                                            var result = userManager.AddToRole(user.Id, role.Name);
                                        }
                                    }
                                }
                            }

                             

                            Now, we need to make a few changes to our ApplicationUserManager. Since we have added our customizable models, including modified versions of UserStore and RoleStore, we need to adapt the ApplicationUserManager to play nice. We have expressed our models with different type arguments than the default implementation expected by the Web Api project. Specifically, we have employed a customized implementation of IUserStore. Rather than the concrete UserStore defined in Microsoft.AspNet.Identity.EntityFramework, we have implemented our own ApplicationUserStore, which is expressed in terms of specific type arguments.

                            We now need to tune up our ApplicationUserManager to work with our ApplicationUserStore.

                            Change the code for ApplicationUserManager in IdentityConfig.cs to the following:

                            Modified ApplicationUserManager:
                            publicclass ApplicationUserManager 
                                : UserManager<ApplicationUser, string>
                            {
                            public ApplicationUserManager(IUserStore<ApplicationUser, string> store)
                                    : base(store)
                                {
                                }
                            publicstatic ApplicationUserManager Create(
                                    IdentityFactoryOptions<ApplicationUserManager> options, 
                                    IOwinContext context)
                                {
                                    var manager = new ApplicationUserManager(
                            new UserStore<ApplicationUser, ApplicationRole, string, 
                                            ApplicationUserLogin, ApplicationUserRole, 
                                            ApplicationUserClaim>(context.Get<ApplicationDbContext>()));
                            // Configure validation logic for usernames
                                    manager.UserValidator = new UserValidator<ApplicationUser>(manager)
                                    {
                                        AllowOnlyAlphanumericUserNames = false,
                                        RequireUniqueEmail = true
                                    };
                            // Configure validation logic for passwords
                                    manager.PasswordValidator = new PasswordValidator
                                    {
                                        RequiredLength = 6,
                                        RequireNonLetterOrDigit = true,
                                        RequireDigit = true,
                                        RequireLowercase = true,
                                        RequireUppercase = true,
                                    };
                                    var dataProtectionProvider = options.DataProtectionProvider;
                            if (dataProtectionProvider != null)
                                    {
                                        manager.UserTokenProvider = 
                            new DataProtectorTokenProvider<ApplicationUser>(
                                                dataProtectionProvider.Create("ASP.NET Identity"));
                                    }
                            return manager;
                                }
                            }

                             

                            With that, the very minimal basics are in place for us to use our new, extensible model classes (including Roles, which were not directly available to us in the default Web Api implementation) in our Web Api project.

                            We do need to clean up one more issue though. The AccountController still appears to rely on Microsoft.AspNet.Identity.EntityFramework.IdentityUser, and we need it to use our new implementation ApplicationUser.

                            Modify AccountController to Use ApplicationUser

                            We can easily correct this last remaining issue. Open the AccountController class, and locate the GetManageInfo() method. We can see where a local variable user is declared, explicitly types as IdentityUser.

                            Below that, we can see in the foreach() loop, we explicitly declare an iterator variable linkedAccount as type IdentityUserLogin.

                            Existing Code in the Web Api AccountController GetManageInfo() Method:
                            [Route("ManageInfo")]
                            public async Task<ManageInfoViewModel> GetManageInfo(
                            string returnUrl, bool generateState = false)
                            {
                                IdentityUser user = 
                                    await UserManager.FindByIdAsync(User.Identity.GetUserId());
                            if (user == null)
                                {
                            returnnull;
                                }
                                List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
                            foreach (IdentityUserLogin linkedAccount in user.Logins)
                                {
                                    logins.Add(new UserLoginInfoViewModel
                                    {
                                        LoginProvider = linkedAccount.LoginProvider,
                                        ProviderKey = linkedAccount.ProviderKey
                                    });
                                }
                            if (user.PasswordHash != null)
                                {
                                    logins.Add(new UserLoginInfoViewModel
                                    {
                                        LoginProvider = LocalLoginProvider,
                                        ProviderKey = user.UserName,
                                    });
                                }
                            returnnew ManageInfoViewModel
                                {
                                    LocalLoginProvider = LocalLoginProvider,
                                    Email = user.UserName,
                                    Logins = logins,
                                    ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
                                };
                            }

                             

                            In both cases we have implemented our own versions of these types. Here, we can either change the declaration in each case to use the var keyword, which relieves us of the type constraint on the variable (but, some would argue, makes our code a bit ambiguous), or we can change the explicit type declaration in each case to use our own implementation.

                            For now, let's change the explicit type declaration to use our own implementations:

                            Modified Code for GetManageInfo() Method:
                            [Route("ManageInfo")]
                            public async Task<ManageInfoViewModel> GetManageInfo(
                            string returnUrl, bool generateState = false)
                            {
                                ApplicationUser user = 
                                    await UserManager.FindByIdAsync(User.Identity.GetUserId());
                            if (user == null)
                                {
                            returnnull;
                                }
                                List<UserLoginInfoViewModel> logins = new List<UserLoginInfoViewModel>();
                            foreach (ApplicationUserLogin linkedAccount in user.Logins)
                                {
                                    logins.Add(new UserLoginInfoViewModel
                                    {
                                        LoginProvider = linkedAccount.LoginProvider,
                                        ProviderKey = linkedAccount.ProviderKey
                                    });
                                }
                            if (user.PasswordHash != null)
                                {
                                    logins.Add(new UserLoginInfoViewModel
                                    {
                                        LoginProvider = LocalLoginProvider,
                                        ProviderKey = user.UserName,
                                    });
                                }
                            returnnew ManageInfoViewModel
                                {
                                    LocalLoginProvider = LocalLoginProvider,
                                    Email = user.UserName,
                                    Logins = logins,
                                    ExternalLoginProviders = GetExternalLogins(returnUrl, generateState)
                                };
                            }

                             

                            Above, we have simply changed the declared type for the local user variable from IdentityUser to ApplicationUser, and the iterator variable linkedAccount from IdentityUserLogin to ApplicationUserLogin.

                            Add Initialization for ApplicationRoleManager in Startup.Auth

                            Recall from our high-level exploration of ASP.NET Web Api and Identity that initialization and configuration of Identity 2.0 occurs in the Startup class defined in App_Start => Startup.Auth.

                            As we have seen, the original VS Web Api template did not really provide for Role-Based anything, and consequently, provides no configuration or initialization for our recently added ApplicationRoleManager at startup. We need to add a line of initialization code to our Startup.Auth file:

                            Add Initialization for ApplicationRoleManager in Statup.Auth:
                            publicvoid ConfigureAuth(IAppBuilder app)
                            {
                                app.CreatePerOwinContext(ApplicationDbContext.Create);
                                app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
                                app.CreatePerOwinContext<ApplicationRoleManager>(ApplicationRoleManager.Create);
                                app.UseCookieAuthentication(new CookieAuthenticationOptions());
                                app.UseExternalSignInCookie(DefaultAuthenticationTypes.ExternalCookie);
                            // Configure the application for OAuth based flow
                                PublicClientId = "self";
                                OAuthOptions = new OAuthAuthorizationServerOptions
                                {
                                    TokenEndpointPath = new PathString("/Token"),
                                    Provider = new ApplicationOAuthProvider(PublicClientId),
                                    AuthorizeEndpointPath = new PathString("/api/Account/ExternalLogin"),
                                    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                                    AllowInsecureHttp = true
                                };
                            // Enable the application to use bearer tokens to authenticate users
                                app.UseOAuthBearerTokens(OAuthOptions);
                            // ... Code for third-part logins omitted for brevity ...
                            }

                             

                            We've added a single line, which initializes an instance of ApplicationRoleManager for each incoming request.

                            About the ApplicationDbInitializer

                            With the changes we've introduced so far, we should be able to take our new and improved Web Api project for a test spin to see if the most basic functionality works.

                            Before we do, though, we need to recognize that we have fundamentally changed how the EF/Code-First database generation has been changed with the introduction of our custom ApplicationDbInitializer.

                            Recall from our explorations of customizing an MVC project with extensible models, the ApplicationDbInitializer allows us to specify some options for how and when the database behind our application is generated, and to provide some initial data to work with.

                            As we move towards Role-Based Authorization and a more restrictive security model for our Api, this becomes important.

                            The way we currently have ApplicationDbInitializer configured, it derives from DbDropCreateDatabaseAlways, which means every time we run our application, the backing store will be destroyed, and re-created from scratch. We also have it set up to create a default User, and we assign that user to the Admin role. In this manner, we start our application with a user with Admin-level access permissions.

                            The default VS Web Api project doesn't take advantage of this out of the box. If we look at the class declaration for AccountController we see that the class itself is decorated with a simple [Authorize] attribute. What this essentially does is restrict access to all of the Action methods on the class to authorized users (except those methods specifically decorated with an [AllowAnonymous] attribute).

                            In other words, for now, any user who is registered, and who successfully signs in and presents a valid Bearer Token can access any of the Action methods on AccountController.

                            We'll take a closer look at implementing Role-Based Authentication momentarily, First, we will extend our ApplicationUser and ApplicationRole classes with some custom properties.

                            Adding Custom Properties to ApplicationUser and ApplicationRole

                            As we saw when we examine customizing Users and Roles within an MVC project, we will add a few simple properties to our ApplicationUser and ApplicationRole models. Modify the code for each as follows:

                            Add Custom Properties to ApplicationUser and ApplicationRole:
                            // Must be expressed in terms of our custom Role and other types:
                            publicclass ApplicationUser
                                : IdentityUser<string, ApplicationUserLogin,
                                ApplicationUserRole, ApplicationUserClaim> 
                            {
                            public ApplicationUser()
                                {
                            this.Id = Guid.NewGuid().ToString();
                                }
                            public async Task<ClaimsIdentity>GenerateUserIdentityAsync(
                                    ApplicationUserManager manager, string authenticationType)
                                {
                            // Note the authenticationType must match the one 
                            // defined in CookieAuthenticationOptions.AuthenticationType
                                    var userIdentity = await manager.CreateIdentityAsync(this, authenticationType);
                            // Add custom user claims here
                            return userIdentity;
                                }
                            // Add Custom Properties:
                            publicstring Address { get; set; }
                            publicstring City { get; set; }
                            publicstring PostalCode { get; set; }
                            }
                            // Must be expressed in terms of our custom UserRole:
                            publicclass ApplicationRole : IdentityRole<string, ApplicationUserRole> 
                            {
                            public ApplicationRole() 
                                {
                            this.Id = Guid.NewGuid().ToString();
                                }
                            public ApplicationRole(string name) : this() 
                                {
                            this.Name = name;
                                }
                            // Add Custom Property:
                            publicstring Description { get; set; }
                            }

                             

                            Here, we have added an Address and related properties to ApplicationUser, and a simple Description property to ApplicationRole.

                            Now, let's update our ApplicationDbInitializer to set some sample values for these new properties. Update the code for the InitializeIdentityForEF() method as follows:

                            Set Initial Values for Custom Properties in ApplicationDbInitializer:
                            publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db)
                            {
                                var userManager = HttpContext.Current
                                    .GetOwinContext().GetUserManager<ApplicationUserManager>();
                                var roleManager = HttpContext.Current
                                    .GetOwinContext().Get<ApplicationRoleManager>();
                            conststring name = "admin@example.com";
                            conststring password = "Admin@123456";
                            // Some initial values for custom properties:
                            conststring address = "1234 Sesame Street";
                            conststring city = "Portland";
                            conststring state = "OR";
                            conststring postalCode = "97209";
                            conststring roleName = "Admin";
                            conststring roleDescription = "All access pass";
                            //Create Role Admin if it does not exist
                                var role = roleManager.FindByName(roleName);
                            if (role == null)
                                {
                                    role = new ApplicationRole(roleName);
                            // Set the new custom property:
                                    role.Description = roleDescription;
                                    var roleresult = roleManager.Create(role);
                                }
                                var user = userManager.FindByName(name);
                            if (user == null)
                                {
                                    user = new ApplicationUser { UserName = name, Email = name };
                            // Set the new custom properties:
                                    user.Address = address;
                                    user.City = city;
                                    user.State = state;
                                    user.PostalCode = postalCode;
                                    var result = userManager.Create(user, password);
                                    result = userManager.SetLockoutEnabled(user.Id, false);
                                }
                            // Add user admin to Role Admin if not already added
                                var rolesForUser = userManager.GetRoles(user.Id);
                            if (!rolesForUser.Contains(role.Name))
                                {
                                    var result = userManager.AddToRole(user.Id, role.Name);
                                }
                            }

                             

                            With that, we should be ready to see if everything at least works correctly . . .

                            Create a Simple Web Api Client Application

                            To see if everything is working properly to this point, we will create a simple console application as an Api client.

                            In Visual Studio, create a new Console Application, and the use the Manage Nuget Packages for Solutions to add the Microsoft Asp.NET Web Api 2.2 Client Libraries, or use the Package Manager Console and do:

                            Add Web Api 2.2 via the Nuget Package Manager Console:
                            PM> Install-Package Microsoft.AspNet.WebApi.Client

                             

                            Now that we have the required Web Api Client Libraries in our project, open the Program.cs file.

                            Make sure the following using statements are present at the top of the file. Note we have added references to System.Net.Http and Newtonsoft.Json, ad well as System.Threading:

                            Required Using Statements for Console Api Client Application:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            using System.Net.Http;
                            using Newtonsoft.Json;

                             

                            Next, let's add some very basic client code used to retrieve a token from the token endpoint of our Web Api. Add the following within the Program class:

                            Add Client Code to Retreive Response from Web Api Token Endpoint:
                            // You will need to substitute your own host Url here:
                            staticstring host = "http://localhost:63074/";
                            staticvoid Main(string[] args)
                            {
                                Console.WriteLine("Attempting to Log in with default admin user");
                            // Get hold of a Dictionary representing the JSON in the response Body:
                                var responseDictionary = 
                                    GetResponseAsDictionary("admin@example.com", "Admin@123456");
                            foreach(var kvp in responseDictionary)
                                {
                                    Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
                                }
                                Console.Read();
                            }
                            static Dictionary<string, string> GetResponseAsDictionary(
                            string userName, string password)
                            {
                                HttpClient client = new HttpClient();
                                var pairs = new List<KeyValuePair<string, string>>
                                            {
                            new KeyValuePair<string, string>( "grant_type", "password" ), 
                            new KeyValuePair<string, string>( "username", userName ), 
                            new KeyValuePair<string, string> ( "Password", password )
                                            };
                                var content = new FormUrlEncodedContent(pairs);
                            // Attempt to get a token from the token endpoint of the Web Api host:
                                HttpResponseMessage response =
                                    client.PostAsync(host + "Token", content).Result;
                                var result = response.Content.ReadAsStringAsync().Result;
                            // De-Serialize into a dictionary and return:
                                Dictionary<string, string> tokenDictionary =
                                    JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
                            return tokenDictionary;
                            }

                             

                            Note, at this point, we have added code the the Main() method, which calls out to a single, rather contrived method GetResponseAsDictionary() . All we are basically doing here is submitting an HTTP POST to the Token endpoint of our Web Api, and then de-serializing the JSON response body into a Dictionary<string, string> .

                            Once we have the Dictionary, we are iterating over each Key/Value pair, and writing the contents to the Console.

                            If everything has worked the way we expect, our Console output should be something along the lines of the following:

                            Console Output from Token Endpoint Response:
                            Attempting to Log in with default admin user
                            access_token: AuzOQkgG3BYubP1rlljcPhAzW7R7gA4Vew8dHy_MScMn2-Rs3R6dNlwCU_SuFwKveq
                            uf5rflB7PCfamlcT_-KJ4q3lfx7kiFNpSF9SdMLwKP_mCSOXGbrxrK3jXfH7bum3sZdl7w8k5irLa27i
                            Bvp_RqtXgkSmgpcNWitCU8RBz7aOaHr8r-FCklg4wUkLNE26qlR6Sl42DAAiBZNLpUZUt-M7vaOs8TZB
                            W4YehAzrqFAuTX3peMJBQB8K8_XxaTkRnEhSEMz9DnUnqzQjjVr5rnSdFSGxQmrQA8dBBwq4RaUfwbCU
                            7au787CMn7EGiDO9KRcGHAsGHOJqb8P8Z7A-ssV7tfEqJayrNH-F_Z2p5kiasDODQrG53CZNUE0vuDT6
                            Fp4_xOavE6wkYcHTfXWZJWFEMokE4NB9mtAl3lReYSZQyzKkcHWFNQCMAj3LoNGSdnEVVM_jzZtRSfWj
                            IG2OmhyR1wZNRCHY_6NwEMOIHGLpA_L-kFFAJPgwQWi-WljeV-X2KiMQIeYlGGdskaNw
                            token_type: bearer
                            expires_in: 1209599
                            userName: admin@example.com
                            .issued: Sun, 26 Oct 2014 13:21:03 GMT
                            .expires: Sun, 09 Nov 2014 13:21:03 GMT

                             

                            We've seen this before, in our overview article. The de-serialized JSON above represents the content of the response to our POST to the Token endpoint of our Web Api. The important part of the response is and access_token itself.

                            This Doesn't Look Any Different Than Before . . .

                            At this point, that de-serialized JSON response doesn't look any different than it did in our previous post, before we added all our fancy new Roles and custom properties. Shouldn't it have some new information in it now? Roles, and Addresses and stuff?

                            No.

                            A Little More On the Nature of Bearer Tokens (but only a little)

                            We had a really, really brief look Bearer Tokens in our Introduction to Identity in Web Api. As mentioned there, we will undertake a more in-depth exploration of Tokens in another post.

                            For our purposes here today, we are simply going to expand a little on what we learned previously, sufficient to understand how the access_token we retrieved as part of our JSON response above fits into the scheme of our newly modified Web Api project.

                            Bearer Tokens are, by design, "opaque" to the client. In other words, they are encoded (and sometimes encrypted) on the server, and can be decoded (and potentially decrypted) by the server. They are not designed to be decoded/decrypted by the client.

                            Recall from exploring the basic structure of an ASP.NET Web Api project, the ApplicationOauthProvider class, defined in the Providers => ApplicationOauthProvider.cs file.

                            When you POST a request to the Token endpoint of the ASP.NET Web Api application (at least, in the way we have it configured here), the server validates the credentials you present (in this case, user name + Password) by calling the GrantResourceOwnersCredentials() method defined on the ApplicationOauthProvider class:

                            The GrantResourceOwnersCredentials() Method from ApplicationOAuthProvider:
                            publicoverride async Task GrantResourceOwnerCredentials(
                                OAuthGrantResourceOwnerCredentialsContext context)
                            {
                                var userManager = context.OwinContext.GetUserManager<ApplicationUserManager>();
                                ApplicationUser user = await userManager.FindAsync(context.UserName, context.Password);
                            if (user == null)
                                {
                                    context.SetError("invalid_grant", "The user name or password is incorrect.");
                            return;
                                }
                                ClaimsIdentity oAuthIdentity = await user.GenerateUserIdentityAsync(userManager,
                                   OAuthDefaults.AuthenticationType);
                                ClaimsIdentity cookiesIdentity = await user.GenerateUserIdentityAsync(userManager,
                                    CookieAuthenticationDefaults.AuthenticationType);
                                AuthenticationProperties properties = CreateProperties(user.UserName);
                                AuthenticationTicket ticket = new AuthenticationTicket(oAuthIdentity, properties);
                                context.Validated(ticket);
                                context.Request.Context.Authentication.SignIn(cookiesIdentity);
                            }

                             

                            We can see that this code attempts to find a user with credentials matching those presented. If a valid user is found, the method calls the GenerateUserIdentityAsync() method defined on the ApplicationUser class to obtain an instance of ClaimsIdentity representing the user, and any claims the user may make within our system.

                            The ClaimsIdentity is then used to create an AuthenticationTicket.

                            In the code for GrantResourceOwnersCredentials(), above, when Validated() is called on the OAuthGrantResourceOwnerCredentialsContext, the OWIN middleware serializes the ClaimsIdentity into an encoded and signed token, to be returned in the HTTP Response header as a result of our request.

                            All of the above is a long-winded way of saying, the important user information, including user roles, and anything else we decide needs to be a part of our token, is present in the token when it is received by the client.

                            The Client just can't get to it.

                            A Note About Bearer Tokens and Security

                            As mentioned in our previous posts, using bearer tokens, and submitting credentials to obtain the token from the token endpoint should only be done over SSL/STL in a production system. Bearer tokens are exactly what their name implies - anyone presenting a valid bearer token will be granted access to the system, with whatever privileges the actual "owner" of the token has.

                            OAuth Bearer tokens represent a fairly simple authentication/authorization scheme, In building out your Web Api, consider all of the alternatives, and make the best choice for your application.

                            As mentioned previously, we will take a more thorough look at Claims Identity, and token authentication/authorization in later posts.

                            Adding Role-Based Authorization to the Web Api Application

                            Now that we understand how to authenticate ourselves using a bearer token, let's look at how we can use our new Role-Based Authorization capability within our application.

                            To start, let's look at the two primary controllers present in the Web Api application, AccountController and ValuesController (we are ignoring the HomeController, since it serves no purpose for our needs here).

                            We've already seen that AccountController is decorated with an [Authorize] attribute. This means that only authenticated users may access the action methods defined on this controller (unless, of course, the method itself is decorated with an [AllowAnonymous] attribute).

                            Let's look at the simplistic ValuesController. ValuesController is provided as a simple example of how one might add a basic CRUD-style functionality. ValuesController is similarly decorated with the [Authorize] attribute. Again, only authenticated users are able to access the Action methods defined on ValuesController.

                            As we saw in previous posts about implementing Role-Based Authorization in an MVC project, we can modify the access permissions for our Web Api, at either the Controller level, or the Action method level, by expanding on our use of [Authorize] .

                            Consider, we might want to restrict access to AccountController only to users who are in the Admin role, but allow access to ValuesController, and the functionality it provides, to any authenticated user.

                            In this case, we will want to make some modifications to our Web Api configuration.

                            Add a Vanilla Users Role as a Default in ApplicationDbInitializer

                            First, let's make sure we have two distinct Roles available in our application - the "Admin" role we already create as an initial value during configuration, and a new "Users" role. Update the InitializeDatabaseForEF() method as follows:

                            Add a Users Role and a Default User to InitializeDatabaseForEF() Method:
                            publicstaticvoid InitializeIdentityForEF(ApplicationDbContext db)
                            {
                                var userManager = HttpContext.Current
                                    .GetOwinContext().GetUserManager<ApplicationUserManager>();
                                var roleManager = HttpContext.Current
                                    .GetOwinContext().Get<ApplicationRoleManager>();
                            // Initial Admin user:
                            conststring name = "admin@example.com";
                            conststring password = "Admin@123456";
                            // Some initial values for custom properties:
                            conststring address = "1234 Sesame Street";
                            conststring city = "Portland";
                            conststring state = "OR";
                            conststring postalCode = "97209";
                            conststring roleName = "Admin";
                            conststring roleDescription = "All access pass";
                            //Create Role Admin if it does not exist
                                var role = roleManager.FindByName(roleName);
                            if (role == null)
                                {
                                    role = new ApplicationRole(roleName);
                            // Set the new custom property:
                                    role.Description = roleDescription;
                                    var roleresult = roleManager.Create(role);
                                }
                            // Create Admin User:
                                var user = userManager.FindByName(name);
                            if (user == null)
                                {
                                    user = new ApplicationUser { UserName = name, Email = name };
                            // Set the new custom properties:
                                    user.Address = address;
                                    user.City = city;
                                    user.State = state;
                                    user.PostalCode = postalCode;
                                    var result = userManager.Create(user, password);
                                    result = userManager.SetLockoutEnabled(user.Id, false);
                                }
                            // Add user admin to Role Admin if not already added
                                var rolesForUser = userManager.GetRoles(user.Id);
                            if (!rolesForUser.Contains(role.Name))
                                {
                                    userManager.AddToRole(user.Id, role.Name);
                                }
                            // Initial Vanilla User:
                            conststring vanillaUserName = "vanillaUser@example.com";
                            conststring vanillaUserPassword = "Vanilla@123456";
                            // Add a plain vannilla Users Role:
                            conststring usersRoleName = "Users";
                            conststring usersRoleDescription = "Plain vanilla User";
                            //Create Role Users if it does not exist
                                var usersRole = roleManager.FindByName(usersRoleName);
                            if (usersRole == null)
                                {
                                    usersRole = new ApplicationRole(usersRoleName);
                            // Set the new custom property:
                                    usersRole.Description = usersRoleDescription;
                                    var userRoleresult = roleManager.Create(usersRole);
                                }
                            // Create Vanilla User:
                                var vanillaUser = userManager.FindByName(vanillaUserName);
                            if (vanillaUser == null)
                                {
                                    vanillaUser = new ApplicationUser 
                                    { 
                                        UserName = vanillaUserName, 
                                        Email = vanillaUserName 
                                    };
                            // Set the new custom properties:
                                    vanillaUser.Address = address;
                                    vanillaUser.City = city;
                                    vanillaUser.State = state;
                                    vanillaUser.PostalCode = postalCode;
                                    var result = userManager.Create(vanillaUser, vanillaUserPassword);
                                    result = userManager.SetLockoutEnabled(vanillaUser.Id, false);
                                }
                            // Add vanilla user to Role Users if not already added
                                var rolesForVanillaUser = userManager.GetRoles(vanillaUser.Id);
                            if (!rolesForVanillaUser.Contains(usersRole.Name))
                                {
                                    userManager.AddToRole(vanillaUser.Id, usersRole.Name);
                                }
                            }

                             

                            Above, we have added a new role "Users" and another initial sample user.

                            Next, let's modify the [Authorize] attribute on our AccountController class, and add a Role argument:

                            Modified [Authorize] Attribute for AccountController:
                            [Authorize(Roles= "Admin")]
                            [RoutePrefix("api/Account")]
                            publicclass AccountController : ApiController
                            {
                            // ... All the Code ...
                            }

                             

                            Now, we just need to change up our client code to attempt to access some methods from each of the two controllers to see how our Role-Based Authorization is working for us.

                            Modify Client Code to Attempt Controller Access

                            Here, we will simply set up some client code to attempt to retreive some basic data from both AccountController and ValuesController. We will do this as a user in the Admin Role, and then also as a user in the Users Role.

                            Change the code in your Console application to match the following:

                            Modified Client Code to Access Both Controllers with Different Roles:
                            class Program
                            {
                            // You will need to substitute your own host Url here:
                            staticstring host = "http://localhost:63074/";
                            staticvoid Main(string[] args)
                                {
                            // Use the User Names/Emails and Passwords we set up in IdentityConfig:
                            string adminUserName = "admin@example.com";
                            string adminUserPassword = "Admin@123456";
                            string vanillaUserName = "vanillaUser@example.com";
                            string vanillaUserPassword = "Vanilla@123456";
                            // Use the new GetToken method to get a token for each user:
                            string adminUserToken = GetToken(adminUserName, adminUserPassword);
                            string vaniallaUserToken = GetToken(vanillaUserName, vanillaUserPassword);
                            // Try to get some data as an Admin:
                                    Console.WriteLine("Attempting to get User info as Admin User");
                            string adminUserInfoResult = GetUserInfo(adminUserToken);
                                    Console.WriteLine("Admin User Info Result: {0}", adminUserInfoResult);
                                    Console.WriteLine("");
                                    Console.WriteLine("Attempting to get Values info as Admin User");
                            string adminValuesInfoResult = GetValues(adminUserToken);
                                    Console.WriteLine("Admin Values Info Result: {0}", adminValuesInfoResult);
                                    Console.WriteLine("");
                            // Try to get some data as a plain old user:
                                    Console.WriteLine("Attempting to get User info as Vanilla User");
                            string vanillaUserInfoResult = GetUserInfo(vaniallaUserToken);
                                    Console.WriteLine("Vanilla User Info Result: {0}", vanillaUserInfoResult);
                                    Console.WriteLine("");
                                    Console.WriteLine("Attempting to get Values info as Vanilla User");
                            string vanillaValuesInfoResult = GetValues(vaniallaUserToken);
                                    Console.WriteLine("Vanilla Values Info Result: {0}", vanillaValuesInfoResult);
                                    Console.WriteLine("");
                                    Console.Read();
                                }
                            staticstring GetToken(string userName, string password)
                                {
                                    HttpClient client = new HttpClient();
                                    var pairs = new List<KeyValuePair<string, string>>
                                                {
                            new KeyValuePair<string, string>( "grant_type", "password" ), 
                            new KeyValuePair<string, string>( "username", userName ), 
                            new KeyValuePair<string, string> ( "Password", password )
                                                };
                                    var content = new FormUrlEncodedContent(pairs);
                            // Attempt to get a token from the token endpoint of the Web Api host:
                                    HttpResponseMessage response =
                                        client.PostAsync(host + "Token", content).Result;
                                    var result = response.Content.ReadAsStringAsync().Result;
                            // De-Serialize into a dictionary and return:
                                    Dictionary<string, string> tokenDictionary =
                                        JsonConvert.DeserializeObject<Dictionary<string, string>>(result);
                            return tokenDictionary["access_token"];
                                }
                            staticstring GetUserInfo(string token)
                                {
                            using (var client = new HttpClient())
                                    {
                                        client.DefaultRequestHeaders.Authorization =
                            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
                                        var response = client.GetAsync(host + "api/Account/UserInfo").Result;
                            return response.Content.ReadAsStringAsync().Result;
                                    }
                                }
                            staticstring GetValues(string token)
                                {
                            using (var client = new HttpClient())
                                    {
                                        client.DefaultRequestHeaders.Authorization =
                            new System.Net.Http.Headers.AuthenticationHeaderValue("Bearer", token);
                                        var response = client.GetAsync(host + "api/Values").Result;
                            return response.Content.ReadAsStringAsync().Result;
                                    }
                                }
                            }

                             

                            In the above, we changed our code up a bit. We now have a GetToken() method, which accepts a User Name/Password as arguments, and returns only the access_token string from the request to the Token endpoint of our Web Api.

                            Next, we added two different calls to our Web Api. One method calls the GetUserInfo() method on the AccountController, and the other calls the Get() method on our ValuesController.

                            If we spin up our Web Api, and, after it has spun up, run our client application, we should see the following output in our Console:

                            Console Output from Access Permissions Comparison:
                            Attempting to get User info as Admin User
                            Admin User Info Result: {"Email":"admin@example.com","HasRegistered":true,"Login
                            Provider":null}
                            Attempting to get Values info as Admin User
                            Admin Values Info Result: ["value1","value2"]
                            Attempting to get User info as Vanilla User
                            Vanilla User Info Result: {"Message":"Authorization has been denied for this req
                            uest."}
                            Attempting to get Values info as Vanilla User
                            Vanilla Values Info Result: ["value1","value2"]

                             

                            Note the output from that third attempt. We are trying to call into GetUserInfo() as a plain vanilla User, in the Users Role. Appropriately, our Web Api has returned an authorization error, since Users are not allowed access to the method by virtue of the [Authorize(Roles="Admin")] attribute on the class declaration for AccountController.

                            In contrast, both users are able to access the Get() method on ValuesController, since this controller is decorated with a simple [Authorize] attribute, which requires only an authenticated user for access.

                            Accessing Custom User Properties

                            We have also added some custom properties to our ApplicationUserModel. Let's take a look and see if we can work with those in the context of our examples here.

                            If we look more closely at the GetUserInfo() method on AccountController, we find that the actual return type for this method is UserInfoViewModel, which is found in the Models => AccountViewModels.cs file. Now, in our crude, simple Console application we are not going to all the effort of de-serializing the JSON from our GET request into an object, but we COULD.

                            For our purposes, here, it will be sufficient to modify the UserInfoViewModel to reflect the additional properties we want to return, and then update the GetUserInfo() method to suit.

                            Add our custom User properties to the UserInfoViewModel class:
                            publicclass UserInfoViewModel
                            {
                            publicstring Email { get; set; }
                            publicbool HasRegistered { get; set; }
                            publicstring LoginProvider { get; set; }
                            // Add our custom properties from ApplicationUser:
                            publicstring Address { get; set; }
                            publicstring City { get; set; }
                            publicstring State { get; set; }
                            publicstring PostalCode { get; set; }
                            }

                             

                            Next, update the GetUserInfo() method to provide values for the additional properties we just added to UserInfoViewModel:

                            Update GetUserInfo() Method on AccountController with Custom Properties:
                            public UserInfoViewModel GetUserInfo()
                            {
                                ExternalLoginData externalLogin 
                                    = ExternalLoginData.FromIdentity(User.Identity as ClaimsIdentity);
                            // We wouldn't normally be likely to do this:
                                var user = UserManager.FindByName(User.Identity.Name);
                            returnnew UserInfoViewModel
                                {
                                    Email = User.Identity.GetUserName(),
                                    HasRegistered = externalLogin == null,
                                    LoginProvider = externalLogin != null ? externalLogin.LoginProvider : null,
                            // Pass the custom properties too:
                                    Address = user.Address,
                                    City = user.City,
                                    State = user.State,
                                    PostalCode = user.PostalCode
                                };
                            }

                             

                            Above, we have called out to UserManager to retreive an instance of our user, so we can get at the new properties we have added. We then set the corresponding values on the UserInfoViewModel before returning.

                            This example is a little contrived, and we most likely would NOT do this in a production application this way. But for now, it will serve to demonstrate that our new and improved ApplicationUser indeed has the custom properties we added to the model, and that we are retrieving them from the database as expected.

                            If we run our Console Client application one last time, we should see the following output:

                            Output from the Console Application with Custom User Properties:
                            Attempting to get User info as Admin User
                            Admin User Info Result: {"Email":"admin@example.com","HasRegistered":true,"Login
                            Provider":null,"Address":"1234 Sesame Street","City":"Portland","State":"OR",
                            "PostalCode":"97209"}
                            Attempting to get Values info as Admin User
                            Admin Values Info Result: ["value1","value2"]
                            Attempting to get User info as Vanilla User
                            Vanilla User Info Result: {"Message":"Authorization has been denied for this 
                            request."}
                            Attempting to get Values info as Vanilla User
                            Vanilla Values Info Result: ["value1","value2"]

                             

                            And we see, our custom user properties are returned with the JSON response.

                            Role-Based Authorization Versus Claims-Based Authorization

                            In this post, we have looked briefly at implementing Role-Based Authorization in the context of an ASP.NET Web Api project, and we had the briefest look at how Bearer Tokens work. It is important to note though, that for any but the simplest of authorization/access control schemes, Role-Based Authorization ("RBA") is rapidly being overshadowed by Claims-Based Authorization.

                            Claims-Based Identity offers greater flexibility, and more effectively separates the Authentication and Authorization mechanism from your code. Note, in this example project, we need to specify, as part of the [Authorize] attribute, precisely which Roles are allowed access to which controllers and/or methods.

                            Claims-Based Auth is more complex than RBA, but is generally going to be a more natural fit for a Web Api scenario, unless your needs are fairly simple.

                            We will examine Tokens, and Claims-Based Identity, in an upcoming post.

                            Additional Resources and Items of Interest

                            ASP.NET Web Api: Understanding OWIN/Katana Authentication/Authorization Part I: Concepts

                            $
                            0
                            0

                            Ah-aint-long-for-this-whorl-240Recently we looked at the fundamentals of the OWIN/Katana Middleware pipeline, and we then applied what we learned, and built out a minimal, OWIN-Based, self-hosted Web Api. In doing so, we managed to avoid the heavy weight of the System.Web library or IIS, and we ended up with a pretty lightweight application. However, all of the concepts we have discussed remain valid no matter the hosting environment.

                            But what if we want to add some basic authentication to such a minimal project?

                            Image by Chad Miller  | Some Rights Reserved

                            Once again, we are going to see if we can't apply what we've learned, and pull a very small Authentication / Authorization component into our minimal Web Api application. We'll start by implementing a basic authentication/authorization model without using the components provided by the ASP.NET Identity framework.

                            Identity is fully compatible with the OWIN Authorization model, and when used in this manner, represents a very useful, ready-to go concrete implementation. But we can perhaps better understand the structure of OWIN authorization, and application security in general, if we start with simple concepts, and work our way up to concrete implementations and additional frameworks.

                            From the Ground Up

                            In this series of posts we will start with concepts, and slowly build from there.

                            • Part I (this post) - We will examine the basic OAuth Resource Owner Flow model for authentication, and assemble to most basic components we need to implement authentication using this model. We will not be concerning ourselves with the cryptographic requirements of properly hashing passwords, or persisting user information to a database. We will also not be using Identity, instead implementing security using the basic components available in the Microsoft.Owin libraries.
                            • Part II - We will mock up some basic classes needed to model our user data, and a persistence model to see how storage of user data and other elements works at a fundamental level.
                            • Part III - We will replace our mock objects with Identity 2.0 components to provide the crypto and security features (because rolling your own crypto is not a good idea).

                            As with our previous posts, the objective here is as much about building an understanding of how authentication in general, and Identity 2.0 in particular, actually fit in to the structure of an OWIN-based application as it is about simply "how to do it."

                            With that in mind, we will take this as far as we reasonably can using only the OWIN/Katana authorization components and simplified examples. Once we have seen the underlying structure for authentication and authorization in an OWIN-based  Web Api application, THEN we will bring Identity 2.0 in to provide the concrete implementation.

                            Source Code for Examples

                            We are building up a project over a series of posts here. In order that the source for each post make sense, I am setting up branches that illustrate each concept:

                            On Github, the branches of the Web Api repo so far look like this:

                            The code for the API client application is in a different repo, and the branches look like this:

                            Application Security is Hard - Don't Roll Your Own!

                            Implementing effective application security is a non-trivial exercise. Behind the simple-looking framework APIs we use, such as Identity 2.0 (or any other membership/auth library) is a few decades worth of development by the best and brightest minds in the industry.

                            Throughout the examples we will be looking at, you will see areas where we mock together some ridiculous methods of (for example) hashing or validating passwords. In reality, securely hashing passwords is a complex, but solved problem. You should never attempt to write your own crypto or data protection schemes.

                            Even a simple authentication mechanism such as we will implement here brings some complexity to the project, because authentication itself is inherently complex. Behind the simple-seeming framework API provided by frameworks such as ASP.NET Identity lies some crypto and logic that is best left as it is unless you REALLY know what you're doing.

                            That said, understanding how the pieces fit, and where you can dig in and adapt existing authorization / authentication flows to the needs of your application, is important, and forms the primary objective of this series.

                            The OAuth Owner Resource Flow Authentication Model

                            One of the commonly used patterns for authentication in a web application is the OAuth Resource Owner Flow model. In fact, this is the model used in the Web Api Template project in Visual Studio. We are going to implement authentication using the Resource Owner Flow from "almost scratch" in our OWIN-based Web Api application.

                            The Owner Resource Flow posits four principal "actors" in an authentication scenario:

                            • The Resource Owner - For example, a user, or perhaps another application.
                            • The Client - Generally a client application being used by the resource owner to access the protected resource. In our case, the Client might be our Web Api Client application.
                            • The Authorization Server - A server which accepts the Resource Owners credentials (generally a combination of some form of credentials and a password, such as a User Name/Password combination) and returns an encoded or encrypted Access Token.
                            • The Resource Server - The server on which the resource is located, and which protects the resource from unauthorized access unless valid authentication/authorization credentials are supplied with the request.
                            Overview of the Owner Resource Authentication Flow:

                            oath-resource-owner-flow

                            In the above, the Resource Owner presents a set of credentials to the Client. The Client then submits the credentials to the Authorization Server, and if the credentials can be properly validated by the Authorization Server, an encoded and/or encrypted Access Token is returned to the Client.

                            The Client then uses the Access Token to make requests to the Resource Server. The Resource Server has been configured to accept Access Tokens which originate at the Authorization Server, and to decode/decrypt those tokens to confirm the identity and authorization claims (if provided) of the Resource Owner.

                            All of this is predicated on the Resource Owner having been properly registered with the Authorization Server.

                            It should be noted there that the OAuth specification requires that any transaction involving transmission of password/credentials MUST be conducted using SSL/TSL (HTTPS).

                            Our implementation, and that of the VS Web Api project template, puts a slight twist on this, by embedding the Authentication Server within the Resource Server:

                            The Embedded Authentication Server Variant of the Owner Resource Flow:

                            oath-embedded-resource-owner-flow

                            The Basics - OWIN, Katana, and Authentication

                            We can put together a very stripped down example to demonstrate how the pieces fit together, before we clutter things up with higher-level components and any additional database concerns.

                            To get started, you can pull down the source for the Self-hosted web api we built in the previous post. We're going to pick up where we left off with that project, and add a basic authentication component.

                            Recall that we had assembled a fairly minimal Owin-Based Web Api, consisting of an OWIN Startup class, a simple Company model class, and a CompaniesController. The application itself is a console-based application, with a standard entry point in the Main() method of the Program class.

                            In that project, we had decided that since we were self-hosting the application, we would keep our data store in-process and use a local file-based data store. We opted to use SQL Server Compact Edition since it would readily work with Entity Framework and Code-First database generation. Therefore, we also added an ApplicationDbContext.

                            We can review our existing project components before we make any changes.

                            Starting Point - The Self-Hosted Web Api Project

                            First, we have our OWIN Startup class:

                            The OWIN Startup Class from the Minimal Self-Hosted Web Api Project:
                            // Add the following usings:
                            using Owin;
                            using System.Web.Http;
                            namespace MinimalOwinWebApiSelfHost
                            {
                            publicclass Startup
                                {
                            // This method is required by Katana:
                            publicvoid Configuration(IAppBuilder app)
                                    {
                                        var webApiConfiguration = ConfigureWebApi();
                            // Use the extension method provided by the WebApi.Owin library:
                                        app.UseWebApi(webApiConfiguration);
                                    }
                            private HttpConfiguration ConfigureWebApi()
                                    {
                                        var config = new HttpConfiguration();
                                        config.Routes.MapHttpRoute(
                            "DefaultApi",
                            "api/{controller}/{id}",
                            new { id = RouteParameter.Optional });
                            return config;
                                    }
                                }
                            }

                             

                            Then, we had a simple Company model, suitably located in the Models folder in our project:

                            The Original Company Model Class:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add using:
                            using System.ComponentModel.DataAnnotations;
                            namespace MinimalOwinWebApiSelfHost.Models
                            {
                            publicclass Company
                                {
                            // Add Key Attribute:
                                    [Key]
                            publicint Id { get; set; }
                            publicstring Name { get; set; }
                                }
                            }

                             

                             

                            And our original CompaniesController class, again suitably located in the Controllers folder within our project::

                            The Original Companies Controller:
                            publicclass CompaniesController : ApiController
                            {
                                ApplicationDbContext _Db = new ApplicationDbContext();
                            public IEnumerable<Company> Get()
                                {
                            return _Db.Companies;
                                }
                            public async Task<Company> Get(int id)
                                {
                                    var company = 
                                            await _Db.Companies.FirstOrDefaultAsync(c => c.Id == id);
                            if (company == null)
                                    {
                            thrownew HttpResponseException(
                                            System.Net.HttpStatusCode.NotFound);
                                    }
                            return company;
                                }
                            public async Task<IHttpActionResult> Post(Company company)
                                {
                            if (company == null)
                                    {
                            return BadRequest("Argument Null");
                                    }
                                    var companyExists = 
                                            await _Db.Companies.AnyAsync(c => c.Id == company.Id);
                            if (companyExists)
                                    {
                            return BadRequest("Exists");
                                    }
                                    _Db.Companies.Add(company);
                                    await _Db.SaveChangesAsync();
                            return Ok();
                                }
                            public async Task<IHttpActionResult> Put(Company company)
                                {
                            if (company == null)
                                    {
                            return BadRequest("Argument Null");
                                    }
                                    var existing = 
                                            await _Db.Companies.FirstOrDefaultAsync(c => c.Id == company.Id);
                            if (existing == null)
                                    {
                            return NotFound();
                                    }
                                    existing.Name = company.Name;
                                    await _Db.SaveChangesAsync();
                            return Ok();
                                }
                            public async Task<IHttpActionResult> Delete(int id)
                                {
                                    var company = 
                                            await _Db.Companies.FirstOrDefaultAsync(c => c.Id == id);
                            if (company == null)
                                    {
                            return NotFound();
                                    }
                                    _Db.Companies.Remove(company);
                                    await _Db.SaveChangesAsync();
                            return Ok();
                                }
                            }

                             

                            Also in the Models folder is our ApplicationDbContext.cs file, which actually contains the ApplicationDbContext itself, as well as a DBInitializer. For the moment, this derives from DropDatabaseCreateAlways, so that the database is blown away and re-seeded each time the application runs.

                            The Original ApplicationDbContext and DbInitializer:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add using:
                            using System.Data.Entity;
                            using Microsoft.AspNet.Identity;
                            using Microsoft.AspNet.Identity.EntityFramework;
                            namespace MinimalOwinWebApiSelfHost.Models
                            {
                            publicclass ApplicationDbContext : DbContext
                                {
                            public ApplicationDbContext()
                                        : base("MyDatabase")
                                    {
                                    }
                            static ApplicationDbContext()
                                    {
                                        Database.SetInitializer(new ApplicationDbInitializer());
                                    }
                            public IDbSet<Company> Companies { get; set; }
                                }
                            publicclass ApplicationDbInitializer 
                                    : DropCreateDatabaseAlways<ApplicationDbContext>
                                {
                            protectedoverridevoid Seed(ApplicationDbContext context)
                                    {
                                        context.Companies.Add(new Company { Name = "Microsoft" });
                                        context.Companies.Add(new Company { Name = "Apple" });
                                        context.Companies.Add(new Company { Name = "Google" });
                                        context.SaveChanges();
                                    }
                                }
                            }

                             

                            I actually changed the code for the original ApplicationDbContext since the previous post. I have added a static constructor which sets the Database Initializer when the context is instantiated. This will call the initializer the first time we hit the database.

                            This is a much cleaner solution than previously, where we were doing the database initialization in the Main() method of our Program class:

                            The Original Program.cs File (slightly modified):
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add reference to:
                            using Microsoft.Owin.Hosting;
                            using System.Data.Entity;
                            using MinimalOwinWebApiSelfHost.Models;
                            namespace MinimalOwinWebApiSelfHost
                            {
                            class Program
                                {
                            staticvoid Main(string[] args)
                                    {
                            // Specify the URI to use for the local host:
                            string baseUri = "http://localhost:8080";
                                        Console.WriteLine("Starting web Server...");
                                        WebApp.Start<Startup>(baseUri);
                                        Console.WriteLine("Server running at {0} - press Enter to quit. ", baseUri);
                                        Console.ReadLine();
                                    }
                                }
                            }

                             

                            Now that we know where we left off, let's see about implementing a very basic example of the OAuth Resource Owner Flow model for authentication.

                            The Microsoft.AspNet.Identity.Owin Nuget Package includes everything we need to implement a basic example of the Resource Owner Flow, even though we won't be dealing with Identity directly just yet.

                            Pull the Microsoft.AspNet.Identity.Owin package into our project:

                            Add Microsoft ASP.NET Identity Owin Nuget Package:
                            PM> Install-Package Microsoft.AspNet.Identity.Owin -Pre

                             

                            Now we are ready to get started…

                            Adding The Embedded Authorization Server

                            Key to the Resource Owner Flow is the Authorization Server. In our case, the Authorization Server will actually be contained within our Web Api application, but will perform the same function as it would if it were hosted separately.

                            The Microsoft.Owin.Security.OAuth library defines a default implementation of IOAuthAuthorizationServerProvider, OAuthAuthorizationServerProvider which allows us to derive a custom implementation for our application. You should recognize this if you have used the Visual Studio Web Api project templates before. Add a new folder to the project, OAuthServerProvider, and then add a class ass follows:

                            Add the ApplicationOAuthServerProvider Class:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add Usings:
                            using Microsoft.Owin.Security;
                            using Microsoft.Owin.Security.OAuth;
                            using System.Security.Claims;
                            using MinimalOwinWebApiSelfHost.Models;
                            namespace MinimalOwinWebApiSelfHost.OAuthServerProvider
                            {
                            publicclass ApplicationOAuthServerProvider 
                                    : OAuthAuthorizationServerProvider
                                {
                            publicoverride async Task ValidateClientAuthentication(
                                        OAuthValidateClientAuthenticationContext context)
                                    {
                            // This call is required...
                            // but we're not using client authentication, so validate and move on...
                                        await Task.FromResult(context.Validated());
                                    }
                            publicoverride async Task GrantResourceOwnerCredentials(
                                        OAuthGrantResourceOwnerCredentialsContext context)
                                    {
                            // DEMO ONLY: Pretend we are doing some sort of REAL checking here:
                            if (context.Password != "password")
                                        {
                                            context.SetError(
                            "invalid_grant", "The user name or password is incorrect.");
                                            context.Rejected();
                            return;
                                        }
                            // Create or retrieve a ClaimsIdentity to represent the 
                            // Authenticated user:
                                        ClaimsIdentity identity = 
                            new ClaimsIdentity(context.Options.AuthenticationType);
                                        identity.AddClaim(new Claim("user_name", context.UserName));
                            // Identity info will ultimately be encoded into an Access Token
                            // as a result of this call:
                                        context.Validated(identity);
                                    }
                                }
                            }

                             

                            You can see  we are overriding two of the methods available on OAuthAuthorizationServerProvider. The First, ValidateClientAuthentication(), is necessary even though in our case we are not validating the Client application (although we COULD, if we wanted to). We are simply calling Validated() on the ClientValidationContext and moving on. In a more complex scenario, or one for which stronger security was required, we might authenticate the client as well as the resource owner.

                            Where the meat and potatoes of our authentication process occurs is in the GrantResourceOwnerCredentials() method. For this part of our example, we're keeping this simple. We have hacked an authentication process which basically compares the password passed in with the hard-coded string value "password." IF this check fails, an error is set, and authentication fails.

                            In reality, of course, we would (and WILL, shortly) implement a more complex check of the user's credentials. For now though, this will do, without distracting us from the overall structure of things.

                            If the credentials check succeeds, an instance of ClaimsIdentity is created to represent the user data, including any Claims the user should have. For now, all we are doing is adding the user's name as the single claim, and then calling Validated() on the GrantResourceOwnerCredentials context.

                            The call to Validated() ultimately results in the OWIN middleware encoding the ClaimsIdentity data into an Access Token. How this happens, in the context of the Microsoft.Owin implementation, is complex and beyond the scope of this article. If you want to dig deeper on this, grab a copy of Telerik's fine tool Just Decompile. Suffice it to say that the ClaimsIdentity information is encrypted with a private key (generally, but not always the Machine Key of the machine on which the server is running). Once so encrypted, the access token is then added to the body of the outgoing HTTP response.

                            Configuring OWIN Authentication and Adding to the Middleware Pipeline

                            Now that we have our actual Authorization Server in place, let's configure our OWIN Startup class to authenticate incoming requests.

                            We will add a new method, ConfigureAuth() to our Startup class. Check to make sure you have added the following usings and code to Startup:

                            Add a ConfigureAuth() Method to the OWIN Startup Class:
                            using System;
                            // Add the following usings:
                            using Owin;
                            using System.Web.Http;
                            using MinimalOwinWebApiSelfHost.Models;
                            using MinimalOwinWebApiSelfHost.OAuthServerProvider;
                            using Microsoft.Owin.Security.OAuth;
                            using Microsoft.Owin;
                            namespace MinimalOwinWebApiSelfHost
                            {
                            publicclass Startup
                                {
                            // This method is required by Katana:
                            publicvoid Configuration(IAppBuilder app)
                                    {
                                        ConfigureAuth(app);
                                        var webApiConfiguration = ConfigureWebApi();
                                        app.UseWebApi(webApiConfiguration);
                                    }
                            privatevoid ConfigureAuth(IAppBuilder app)
                                    {
                                        var OAuthOptions = new OAuthAuthorizationServerOptions
                                        {
                                            TokenEndpointPath = new PathString("/Token"),
                                            Provider = new ApplicationOAuthServerProvider(),
                                            AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                            // Only do this for demo!!
                                            AllowInsecureHttp = true
                                        };
                                        app.UseOAuthAuthorizationServer(OAuthOptions);
                                        app.UseOAuthBearerAuthentication(
                            new OAuthBearerAuthenticationOptions());
                                    }
                            private HttpConfiguration ConfigureWebApi()
                                    {
                                        var config = new HttpConfiguration();
                                        config.Routes.MapHttpRoute(
                            "DefaultApi",
                            "api/{controller}/{id}",
                            new { id = RouteParameter.Optional });
                            return config;
                                    }
                                }
                            }

                             

                            There's a lot going on in the ConfigureAuth() method above.

                            First, we initialize an instance of OAuthAuthorizationServerOptions. As part of the initialization, we see that we set the token endpoint, as well as assign a new instance of our ApplicationOAuthAuthenticationServerProvider class to the Provider property of the options object.

                            We set an expiry for any tokens issues, and then we explicitly allow the Authorization Server to allow insecure HTTP connections. A note on this last - this is strictly for demo purposes. In the wild, you would definitely want to connect to the authorization server using a secure SSL/TLS protocol (HTTPS), since you are transporting user credentials in the clear.

                            Once our authorization server options are configured, we see the standard extension methods commonly used to add middleware to IAppBuilder. We pass our server options in with UseAuthorizationServer(), and then we indicate that we want to return Bearer Tokens with UseOAuthBearerAuthentication(). In this case, we are passing the default implementation for OAuthBearerAuthenticationOptions, although we could derive from that and customize if we needed to.

                            The server is added to the options object, which specifies other configuration items, and which is then passed into the middleware pipeline.

                            Authenticating the Client: Retrieve an Access Token from the Authorization Server

                            Again, from the previous post, we had put together a crude but effective API client application to exercise our API.

                            For this post, we are going to basically re-write the client application.

                            First, we will add a new Class, the apiClient class. This class will be responsible for submitting our credentials to our Web Api and obtaining a Dictionary<string, string> containing the de-serialized response body, which includes the access token, and additional information about the authentication process:

                            The ApiClient Class:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add Usings:
                            using System.Net.Http;
                            // Add for Identity/Token Deserialization:
                            using Newtonsoft.Json;
                            namespace MinimalOwinWebApiClient
                            {
                            publicclass apiClientProvider
                                {
                            string _hostUri;
                            publicstring AccessToken { get; privateset; }
                            public apiClientProvider(string hostUri)
                                    {
                                        _hostUri = hostUri;
                                    }
                            public async Task<Dictionary<string, string>> GetTokenDictionary(
                            string userName, string password)
                                    {
                                        HttpResponseMessage response;
                                        var pairs = new List<KeyValuePair<string, string>>
                                            {
                            new KeyValuePair<string, string>( "grant_type", "password" ), 
                            new KeyValuePair<string, string>( "username", userName ), 
                            new KeyValuePair<string, string> ( "password", password )
                                            };
                                        var content = new FormUrlEncodedContent(pairs);
                            using (var client = new HttpClient())
                                        {
                                            var tokenEndpoint = new Uri(new Uri(_hostUri), "Token");
                                            response =  await client.PostAsync(tokenEndpoint, content);
                                        }
                                        var responseContent = await response.Content.ReadAsStringAsync();
                            if (!response.IsSuccessStatusCode)
                                        {
                            thrownew Exception(string.Format("Error: {0}", responseContent));
                                        }
                            return GetTokenDictionary(responseContent);
                                    }
                            private Dictionary<string, string> GetTokenDictionary(
                            string responseContent)
                                    {
                                        Dictionary<string, string> tokenDictionary =
                                            JsonConvert.DeserializeObject<Dictionary<string, string>>(
                                            responseContent);
                            return tokenDictionary;
                                    }
                                }
                            }

                             

                            With that in place, we can re-implement the client Program class like so:

                            The Client Program Class:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add Usings:
                            using System.Net.Http;
                            namespace MinimalOwinWebApiClient
                            {
                            class Program
                                {
                            staticvoid Main(string[] args)
                                    {
                            // Wait for the async stuff to run...
                                        Run().Wait();
                            // Then Write Done...
                                        Console.WriteLine("");
                                        Console.WriteLine("Done! Press the Enter key to Exit...");
                                        Console.ReadLine();
                            return;
                                    }
                            static async Task Run()
                                    {
                            // Create an http client provider:
                            string hostUriString = "http://localhost:8080";
                                        var provider = new apiClientProvider(hostUriString);
                            string _accessToken;
                                        Dictionary<string, string> _tokenDictionary;
                            try
                                        {
                            // Pass in the credentials and retrieve a token dictionary:
                                            _tokenDictionary = await provider.GetTokenDictionary(
                            "john@example.com", "password");
                                            _accessToken = _tokenDictionary["access_token"];
                                        }
                            catch (AggregateException ex)
                                        {
                            // If it's an aggregate exception, an async error occurred:
                                            Console.WriteLine(ex.InnerExceptions[0].Message);
                                            Console.WriteLine("Press the Enter key to Exit...");
                                            Console.ReadLine();
                            return;
                                        }
                            catch (Exception ex)
                                        {
                            // Something else happened:
                                            Console.WriteLine(ex.Message);
                                            Console.WriteLine("Press the Enter key to Exit...");
                                            Console.ReadLine();
                            return;
                                        }
                            // Write the contents of the dictionary:
                            foreach(var kvp in _tokenDictionary)
                                        {
                                            Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
                                            Console.WriteLine("");
                                        }
                                    }
                                }
                            }

                             

                            Up to this point, we've ditched all the code that makes requests to the CompaniesController in our API, and we're only looking at the code which authenticates us and retrieves the access token.

                            Note, we have included some very rudimentary exception handling here. In a real application we would probably want a little more info, and we would need to incorporate a more robust mechanism for handling HTTP errors and other things that might go wrong.

                            If we run our Web Api application, and then run our client application, we should see the following output from our Client application:

                            Client Application Output after Authentication:

                            console-output-client-application-authentication 

                            And we see that we have successfully retrieved an access token from our extra-simple auth server. But, what if we pass invalid credentials?

                            Change the password we are passing in from "password" to something else, say, "assword" (but mom, all I did was take the letter "p" out??!!):

                            Client Application after Invalid Authentication:

                            console-output-client-application-invalid-authentication

                            Appropriately, we get back an error indicating we have provided an invalid grant.

                            Now let's implement the rest of our client, and try some calls into our API itself.

                            Implementing the API Client with Authenticated API Calls

                            Now, we'll add an updated version of the CompanyClient class. In this case, we have made everything async. Also, we have updated the class itself, and all of the methods, to work with the the new authentication requirement we have introduced in our API:

                            The Heavily Modified CompanyClient Class:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add Usings:
                            using System.Net.Http;
                            using System.Net;
                            using System.Net.Http.Headers;
                            // Add for Identity/Token Deserialization:
                            using Newtonsoft.Json;
                            namespace MinimalOwinWebApiClient
                            {
                            publicclass CompanyClient
                                {
                            string _accessToken;
                                    Uri _baseRequestUri;
                            public CompanyClient(Uri baseUri, string accessToken)
                                    {
                                        _accessToken = accessToken;
                                        _baseRequestUri = new Uri(baseUri, "api/companies/");
                                    }
                            // Handy helper method to set the access token for each request:
                            void SetClientAuthentication(HttpClient client)
                                    {
                                        client.DefaultRequestHeaders.Authorization 
                                            = new AuthenticationHeaderValue("Bearer", _accessToken); 
                                    }
                            public async Task<IEnumerable<Company>> GetCompaniesAsync()
                                    {
                                        HttpResponseMessage response;
                            using(var client = new HttpClient())
                                        {
                                            SetClientAuthentication(client);
                                            response = await client.GetAsync(_baseRequestUri);
                                        }
                            return await response.Content.ReadAsAsync<IEnumerable<Company>>();
                                    }
                            public async Task<Company> GetCompanyAsync(int id)
                                    {
                                        HttpResponseMessage response;
                            using (var client = new HttpClient())
                                        {
                                            SetClientAuthentication(client);
                            // Combine base address URI and ID to new URI
                            // that looks like http://hosturl/api/companies/id
                                            response = await client.GetAsync(
                            new Uri(_baseRequestUri, id.ToString()));
                                        }
                                        var result = await response.Content.ReadAsAsync<Company>();
                            return result;
                                    }
                            public async Task<HttpStatusCode> AddCompanyAsync(Company company)
                                    {
                                        HttpResponseMessage response;
                            using(var client = new HttpClient())
                                        {
                                            SetClientAuthentication(client);
                                            response = await client.PostAsJsonAsync(
                                                _baseRequestUri, company);
                                        }
                            return response.StatusCode;
                                    }
                            public async Task<HttpStatusCode> UpdateCompanyAsync(Company company)
                                    {
                                        HttpResponseMessage response;
                            using (var client = new HttpClient())
                                        {
                                            SetClientAuthentication(client);
                                            response = await client.PutAsJsonAsync(
                                                _baseRequestUri, company);
                                        }
                            return response.StatusCode;
                                    }
                            public async Task<HttpStatusCode> DeleteCompanyAsync(int id)
                                    {
                                        HttpResponseMessage response;
                            using (var client = new HttpClient())
                                        {
                                            SetClientAuthentication(client);
                            // Combine base address URI and ID to new URI
                            // that looks like http://hosturl/api/companies/id
                                            response = await client.DeleteAsync(
                            new Uri(_baseRequestUri, id.ToString()));
                                        }
                            return response.StatusCode;
                                    }
                                }
                            }

                             

                            Now, we can update our Program class to call into CompanyClient to work with our API and output the results to the console. Basically, we'll expand the Run() method, and exercise each of the methods we defined on CompaniesController asynchronously. We also added a pair of convenience methods for writing to the console, WriteCompaniesList() and WriteStatusCodeResult() :

                            Update Program Class to Consume API and Write to Console:
                            static async Task Run()
                            {
                            // Create an http client provider:
                            string hostUriString = "http://localhost:8080";
                                var provider = new apiClientProvider(hostUriString);
                            string _accessToken;
                                Dictionary<string, string> _tokenDictionary;
                            try
                                {
                            // Pass in the credentials and retrieve a token dictionary:
                                    _tokenDictionary = 
                                        await provider.GetTokenDictionary("john@example.com", "password");
                                    _accessToken = _tokenDictionary["access_token"];
                            // Write the contents of the dictionary:
                            foreach (var kvp in _tokenDictionary)
                                    {
                                        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
                                        Console.WriteLine("");
                                    }
                            // Create a company client instance:
                                    var baseUri = new Uri(hostUriString);
                                    var companyClient = new CompanyClient(baseUri, _accessToken);
                            // Read initial companies:
                                    Console.WriteLine("Read all the companies...");
                                    var companies = await companyClient.GetCompaniesAsync();
                                    WriteCompaniesList(companies);
                            int nextId = (from c in companies select c.Id).Max() + 1;
                                    Console.WriteLine("Add a new company...");
                                    var result = await companyClient.AddCompanyAsync(
                            new Company { Name = string.Format("New Company #{0}", nextId) });
                                    WriteStatusCodeResult(result);
                                    Console.WriteLine("Updated List after Add:");
                                    companies = await companyClient.GetCompaniesAsync();
                                    WriteCompaniesList(companies);
                                    Console.WriteLine("Update a company...");
                                    var updateMe = await companyClient.GetCompanyAsync(nextId);
                                    updateMe.Name = string.Format("Updated company #{0}", updateMe.Id);
                                    result = await companyClient.UpdateCompanyAsync(updateMe);
                                    WriteStatusCodeResult(result);
                                    Console.WriteLine("Updated List after Update:");
                                    companies = await companyClient.GetCompaniesAsync();
                                    WriteCompaniesList(companies);
                                    Console.WriteLine("Delete a company...");
                                    result = await companyClient.DeleteCompanyAsync(nextId - 1);
                                    WriteStatusCodeResult(result);
                                    Console.WriteLine("Updated List after Delete:");
                                    companies = await companyClient.GetCompaniesAsync();
                                    WriteCompaniesList(companies);
                                }
                            catch (AggregateException ex)
                                {
                            // If it's an aggregate exception, an async error occurred:
                                    Console.WriteLine(ex.InnerExceptions[0].Message);
                                    Console.WriteLine("Press the Enter key to Exit...");
                                    Console.ReadLine();
                            return;
                                }
                            catch (Exception ex)
                                {
                            // Something else happened:
                                    Console.WriteLine(ex.Message);
                                    Console.WriteLine("Press the Enter key to Exit...");
                                    Console.ReadLine();
                            return;
                                }
                            }
                            staticvoid WriteCompaniesList(IEnumerable<Company> companies)
                            {
                            foreach (var company in companies)
                                {
                                    Console.WriteLine("Id: {0} Name: {1}", company.Id, company.Name);
                                }
                                Console.WriteLine("");
                            }
                            staticvoid WriteStatusCodeResult(System.Net.HttpStatusCode statusCode)
                            {
                            if (statusCode == System.Net.HttpStatusCode.OK)
                                {
                                    Console.WriteLine("Opreation Succeeded - status code {0}", statusCode);
                                }
                            else
                                {
                                    Console.WriteLine("Opreation Failed - status code {0}", statusCode);
                                }
                                Console.WriteLine("");
                            }

                             

                            Now that we are able to properly authenticate requests to our Web Api, we should be protected against unauthorized access, right?

                            Not so fast.

                            Protecting Resources With [Authorize] Attribute

                            If we fire up our Web Api Application now, open a browser, and type the URL routed to the GetCompanies() method on the CompaniesController, we find that we can still access the resource, even though the requests from the browser contains no authentication token:

                            Accessing the Companies Resource from the Browser without Authentication:

                            access-unprotected-resource-from-browser

                            This is because we haven't specified that the resources represented by CompaniesController should be protected. We can fix that easily, by decorating the CompaniesController class itself with an [Authorize] attribute:

                            Decorate CompaniesController with an [Authorize] Attribute:
                            [Authorize]
                            publicclass CompaniesController : ApiController
                            {
                            // ... Code for Companies Controller ...
                            }

                             

                            If we re-run the Web Api application now, and refresh our browser, we find:

                            Accessing the Protected Companies Resource from the Browser without Authentication:

                            access-protected-resource-from-browser

                            Since the browser request had no access token in the request body, the request for the protected resource was denied.

                            Accessing Protected Resources with Authenticated Client Requests

                            Now, we should be able to run our API Client application (don't forget to re-set the password to "password!"). If we run our client application now, we should see console output resembling the following:

                            Console Output from Authenticated Request for Protected Resource:

                            console-output-client-application-with-authenticated-api-calls

                            With that, we have implemented a very basic example of authenticating a user with our embedded authorization server, retrieved an access token from our client application, and successfully requested access to protected resources on the resource server.

                            Adding Roles as Claims

                            A deep look at claims-based authorization is beyond the scope of this article. However, we can use the [Authorize] attribute to ensure that only users with a specific role claim can access a protected resource:

                            Change the [Authorize] attribute on the CompanyController class to the following:

                            Add a specific Role to the [Authorize] Attribute on Company Controller:
                            [Authorize(Roles="Admin")]
                            publicclass CompaniesController : ApiController
                            {
                            // ... Code for Companies Controller ...
                            }

                             

                            If we run our Web Api application now, and then run our Api Client application, we find we have a problem:

                            Running the Api Client when Role Authorization is Required:

                            api-error-unauthorized-with-role-required

                            Given we have added the Role restriction for access to the CompaniesController resource, this is what we expect to see. Now let's see about authorizing access based on Role membership in our Web Api.

                            Add a Role Claim to Resource Owner Identity

                            At the simplest level, we can add a claim to the access token granted to the resource owner in the call to GrantResourceOwnerCredentials():

                            Add a Role Claim to the authenticated User in GrantResourceOwnerCredentials():
                            publicoverride async Task GrantResourceOwnerCredentials(
                                OAuthGrantResourceOwnerCredentialsContext context)
                            {
                            // DEMO ONLY: Pretend we are doing some sort of REAL checking here:
                            if (context.Password != "password")
                                {
                                    context.SetError(
                            "invalid_grant", "The user name or password is incorrect.");
                                    context.Rejected();
                            return;
                                }
                            // Create or retrieve a ClaimsIdentity to represent the 
                            // Authenticated user:
                                ClaimsIdentity identity = 
                            new ClaimsIdentity(context.Options.AuthenticationType);
                                identity.AddClaim(new Claim("user_name", context.UserName));
                            // Add a Role Claim:
                                identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
                            // Identity info will ultimatly be encoded into an Access Token
                            // as a result of this call:
                                context.Validated(identity);
                            }

                            With that simple change, we have now added a claim to the identity of the authenticated user. The claims will be encoded/encrypted as part of the access token. When the token is received by the resource server (in this case, our application), the decoded token will provide the identity of the authenticated user, as well as any additional claims, including the fact that the user is a member of the "Admin" role.

                            If we run both applications now, the console output from our Api Client application is what we would expect:

                            Console Output from Client with Authenticated User with Proper Admin Role Claim:

                            api-successful-access-with-role-required

                            We have once again successfully accessed a protected resource. Access to the CompaniesController is now restricted to authenticated users who also present a claim indicating they are a member of the Admin role.

                            What Next?

                            So far, we've seen in a very basic way how the Resource Owner Flow is implemented in the context of the OWIN/Katana pipeline. We have not yet examined where we might store our user information, how we get it there, or how our authorization framework might access that data.

                            In the next post, we'll look at persisting authorization information, and how we access it.

                            NEXT: ASP.NET Web Api: OWIN/Katana Authentication/Authorization Part II: Models and Persistence

                            Additional Resources and Items of Interest

                            Some very helpful articles I have referred to in learning this stuff:

                            ASP.NET Web Api: Understanding OWIN/Katana Authentication/Authorization Part II: Models and Persistence

                            $
                            0
                            0

                            authorized-personnel-only-320In the previous post in this series we learned how the most basic authentication and authorization elements fit together in an OWIN-based Web Api application. We have seen how to authenticate a user using an Authentication Server embedded within our application, and how to add an elementary claim to use with the [Authorize] attribute.

                            To this point, we have been avoiding using the ready-built Identity framework, and instead we have been focusing on understanding how these pieces interrelate. We will continue this approach (for now) here, by adding some concrete authorization models to our application, and a persistence layer to store important user data.

                            Image by clement127  |  Some Rights Reserved

                            Once again, we will be doing most of this "from scratch," in a pretty minimal fashion. I want to explore the relationships between project components without too many distractions. So we're not attempting to design the optimal auth system here or demonstrate the latest best practices. But hopefully we will come away with a better understanding of how a fully developed authentication/authorization system such as Identity works in the context of our application. Understanding THAT gives empowers us to utilize tools like Identity more effectively.

                            From the Ground Up

                            In this series of posts we started with concepts, and are building slowly build from there.

                            • Part I (last post) - We will examine the basic OAuth Resource Owner Flow model for authentication, and assemble to most basic components we need to implement authentication using this model. We will not be concerning ourselves with the cryptographic requirements of properly hashing passwords, or persisting user information to a database. We will also not be using Identity, instead implementing security using the basic components available in the Microsoft.Owin libraries.
                            • Part II (this post) - We will mock up some basic classes needed to model our user data, and a persistence model to see how storage of user data and other elements works at a fundamental level.
                            • Part III - We will replace our mock objects with Identity 2.0 components to provide the crypto and security features (because rolling your own crypto is not a good idea).

                            Source Code for Examples

                            We are building up a project over a series of posts here. In order that the source for each post make sense, I am setting up branches that illustrate the concepts for each post:

                            On Github, the branches of the Web Api repo so far look like this:

                            The code for the API client application is in a different repo, and the branches look like this:

                            • Branch: Master - Always the most current, includes all changes
                            • Branch: owin-auth - Added async methods, and token-based authentication calls to the Web Api application. This is where we left the code in the last post.

                            Adding Auth Models to the Minimal Web Api

                            We'll be starting from where we left off in the last post. Recall that We had set up a basic embedded authorization server in our application which would process HTTP POST requests made by a client to the token endpoint, validate the user credentials/password received, and return an access token. From there, the client could submit the access token with subsequent requests to authenticate, and access whichever resources are available for the given identity and/or role.

                            If we review our existing code for the ApplicationOAuthServerProvider, we see in the GrantOwnerResourceCredentials() method that we are performing a mock credentials check. In order to keep things simple, we just checked to see if the password submitted matched the string literal "password" and moved on:

                            The Existing GrantOwnerResourceCredentials Method:
                            publicoverride async Task GrantResourceOwnerCredentials(
                                OAuthGrantResourceOwnerCredentialsContext context)
                            {
                            // DEMO ONLY: Pretend we are doing some sort of REAL checking here:
                            if (context.Password != "password")
                                {
                                    context.SetError(
                            "invalid_grant", "The user name or password is incorrect.");
                                    context.Rejected();
                            return;
                                }
                            // Create or retrieve a ClaimsIdentity to represent the 
                            // Authenticated user:
                                ClaimsIdentity identity = 
                            new ClaimsIdentity(context.Options.AuthenticationType);
                                identity.AddClaim(new Claim("user_name", context.UserName));
                                identity.AddClaim(new Claim(ClaimTypes.Role, "Admin"));
                            // Identity info will ultimatly be encoded into an Access Token
                            // as a result of this call:
                                context.Validated(identity);
                            }

                             

                            In reality, we would most likely check to see if there was a user in our backing store which matched whatever credentials were submitted, and then also check to see if the password submitted was valid. But not by checking against a plain text representation from our backing store!

                            In order to flesh out this method, we need to model our authorization objects, and we need to persist some user data in our database.

                            First, let's add some basic models. Add a new code file to the Models folder in the project, and then add the following code:

                            The AuthModels.cs Code File:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add usings:
                            using System.Data.Entity;
                            using System.ComponentModel.DataAnnotations;
                            using System.Security.Claims;
                            namespace MinimalOwinWebApiSelfHost.Models
                            {
                            publicclass MyUser
                                {
                            public MyUser()
                                    {
                                        Id = Guid.NewGuid().ToString();
                                        Claims = new List<MyUserClaim>();
                                    }
                                    [Key]
                            publicstring Id { get; set; }
                            publicstring Email { get; set; }
                            publicstring PasswordHash { get; set; }
                            public ICollection<MyUserClaim> Claims { get; set; }
                                }
                            publicclass MyUserClaim
                                {
                            public MyUserClaim()
                                    {
                                        Id = Guid.NewGuid().ToString();
                                    }
                                    [Key]
                            publicstring Id { get; set; }
                            publicstring UserId { get; set; }
                            publicstring ClaimType { get; set; }
                            publicstring ClaimValue { get; set; }
                                }
                            publicclass MyPasswordHasher
                                {
                            publicstring CreateHash(string password)
                                    {
                            // FOR DEMO ONLY! Use a standard method or 
                            // crypto library to do this for real:
                            char[] chars = password.ToArray();
                            char[] hash = chars.Reverse().ToArray();
                            returnnewstring(hash);
                                    }
                                }
                            }

                             

                            Above, we see a few basic models. We expect to have a user representation, and we do, in the form of the MyUser class. While you may have been expecting to see a MyRole class, we have instead opted to carry on with the claims implementation we were using in our original project. Therefore, we have added a MyUserClaim class instead. We'll discuss this further shortly.

                            Finally, we have that odd-looking MyPasswordHasher class. As you may have guessed from the comment in the code, we are really only going to mock a proper hashing mechanism here. As before, we're going to keep things simple for our example. In reality, one would apply a proven crypto library to this task, and proven, tried and true methods for properly hashing a password. Or, of course, use a library for such things, like Identity.

                            Adding The Models to the ApplicationDbContext

                            Now that we have our auth-related entity models, we can add them to the existing ApplicationDbContext so that they can be modeled in the database, and we can access the data they represent from the context.

                            Recall that we set this particular example application up to use a local, file-based database (SQL CE) however, everything we are doing here would work just fine with SQL Server as well.

                            Add the Auth-Related Models to the ApplicationDbContext:
                            publicclass ApplicationDbContext : DbContext
                            {
                            public ApplicationDbContext()
                                    : base("MyDatabase")
                                {
                                }
                            static ApplicationDbContext()
                                {
                                    Database.SetInitializer(new ApplicationDbInitializer());
                                }
                            public IDbSet<Company> Companies { get; set; }
                            public IDbSet<MyUser> Users { get; set; }
                            public IDbSet<MyUserClaim> Claims { get; set; }
                            }

                             

                            Tying the Models Together - The User Store

                            For our simple model set, and to keep concept straightforward, we are going to implement a simple MyUserStore class, and add sufficient functionality to get our application working and no more.

                            Add the following class (I added this to the AuthModels.cs file, but you can add it in its own if you want):

                            The UserStore Class:
                            publicclass MyUserStore
                            {
                                ApplicationDbContext _db;
                            public MyUserStore(ApplicationDbContext context)
                                {
                                    _db = context;
                                }
                            public async Task AddUserAsync(MyUser user, string password)
                                {
                            if (await UserExists(user))
                                    {
                            thrownew Exception(
                            "A user with that Email address already exists");
                                    }
                                    var hasher = new MyPasswordHasher();
                                    user.PasswordHash = hasher.CreateHash(password).ToString();
                                    _db.Users.Add(user);
                                    await _db.SaveChangesAsync();
                                }
                            public async Task<MyUser> FindByEmailAsync(string email)
                                {
                                    var user = _db.Users
                                        .Include(c => c.Claims)
                                        .FirstOrDefaultAsync(u => u.Email == email);
                            return await _db.Users
                                        .FirstOrDefaultAsync(u => u.Email == email);
                                }
                            public async Task<MyUser> FindByIdAsync(string userId)
                                {
                            return await _db.Users
                                        .FirstOrDefaultAsync(u => u.Id == userId);
                                }
                            public async Task<bool> UserExists(MyUser user)
                                {
                            return await _db.Users
                                        .AnyAsync(u => u.Id == user.Id || u.Email == user.Email);
                                }
                            public async Task AddClaimAsync(string UserId, MyUserClaim claim)
                                {
                                    var user = await FindByIdAsync(UserId);
                            if(user == null)
                                    {
                            thrownew Exception("User does not exist");
                                    }
                                    user.Claims.Add(claim);
                                    await _db.SaveChangesAsync();
                                }
                            publicbool PasswordIsValid(MyUser user, string password)
                                {
                                    var hasher = new MyPasswordHasher();
                                    var hash = hasher.CreateHash(password);
                            return hash.Equals(user.PasswordHash);
                                }
                            }

                             

                            In the code above, we have assembled a few basic methods to deal with persisting and retrieving User information. Note in the AddUserAsync() method, we perform some minimal validation (make sure a user with the same email address does not already exist). Also, see that we use our super-secret, super-secure MyPasswordHasher to hash, salt, re-hash, etc. our user password, and then we persist the hashed value (NEVER the clear-text password). In other words, at no point are we saving the user-submitted clear-text password to disk, anywhere.

                            Similarly, we provide a simple PasswordIsValid() method which again uses the MyPasswordHasher class to compare the hash of the password submitted with that of a user record (which for now, would be submitted as an argument after being previously retrieved elsewhere in our code).

                            The MyUserStore class provides simplistic examples of how one might implement some of this. There is minimal validation and exception handling here. This class works well for our example, and to demonstrate the concepts we are dealing with, but is not likely how you would do this in a production application.

                            Initialize the Database with User Data

                            Now all we really need to do is update our ApplicationDbInitializer to seed the database with some initial user data. Recall, we had already set this up (in the same code file as the ApplicationDbContext) to seed our Company table with some starting data. Update the code as follows. You will also need to add System.Security.Claims to the using statements at the top of your code file:

                            Update ApplicationDbInitializer to Seed Application with Initial User Data:
                            publicclass ApplicationDbInitializer 
                                : DropCreateDatabaseAlways<ApplicationDbContext>
                            {
                            protected async overridevoid Seed(ApplicationDbContext context)
                                {
                                    context.Companies.Add(new Company { Name = "Microsoft" });
                                    context.Companies.Add(new Company { Name = "Apple" });
                                    context.Companies.Add(new Company { Name = "Google" });
                                    context.SaveChanges();
                            // Set up two initial users with different role claims:
                                    var john = new MyUser { Email = "john@example.com" };
                                    var jimi = new MyUser { Email = "jimi@Example.com" };
                                    john.Claims.Add(new MyUserClaim 
                                    { 
                                            ClaimType = ClaimTypes.Name, 
                                            UserId = john.Id, 
                                            ClaimValue = john.Email 
                                    });
                                    john.Claims.Add(new MyUserClaim 
                                    { 
                                            ClaimType = ClaimTypes.Role, 
                                            UserId = john.Id, 
                                            ClaimValue = "Admin" 
                                    });
                                    jimi.Claims.Add(new MyUserClaim 
                                    { 
                                        ClaimType = ClaimTypes.Name, 
                                        serId = jimi.Id, 
                                        ClaimValue = jimi.Email 
                                    });
                                    jimi.Claims.Add(new MyUserClaim 
                                    { 
                                        ClaimType = ClaimTypes.Role, 
                                        UserId = john.Id, 
                                        ClaimValue = "User" 
                                    });
                                    var store = new MyUserStore(context);
                                    await store.AddUserAsync(john, "JohnsPassword");
                                    await store.AddUserAsync(jimi, "JimisPassword");
                                }
                            }

                             

                            As we see above, we have taken advantage of the methods exposed on our new MyUserStore class to add two users, along with appropriate claims, to the database.

                            Also recall we are deriving our initializer from DropDatabaseCreateAlways so that the database will be re-created and re-seeded each time we run the application.

                            Find the User and Authenticate the Token Request

                            All that's left to do now is update our GrantResourceOwnerCredentials() method to avail itself of our new user entities and data to perform its function.

                            Validate and Authenticate a User in GrantResourceOwnerCredentials() Method:
                            publicoverride async Task GrantResourceOwnerCredentials(
                                OAuthGrantResourceOwnerCredentialsContext context)
                            {
                            // Retrieve user from database:
                                var store = new MyUserStore(new ApplicationDbContext());
                                var user = await store.FindByEmailAsync(context.UserName);
                            // Validate user/password:
                            if(user == null || !store.PasswordIsValid(user, context.Password))
                                {
                                    context.SetError(
                            "invalid_grant", "The user name or password is incorrect.");
                                    context.Rejected();
                            return;
                                }
                                var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                            foreach(var userClaim in user.Claims)
                                {
                                    identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
                                }
                                context.Validated(identity);
                            }

                             

                            Here, we retrieve a user record from our store (if there is a record for the user credentials in the request), and then we create a new ClaimsIdentity for that user, much the same as before. This time, however, we also have a record of the various claims for this user, and we add those as well.

                            In this case, we really only have the user's name, and the role(s) our application recognizes for the user, but we could implement a more complex claims model if we needed. For now, we will stick with user name and roles, because the default authorization scheme, using the [Authorize] attribute, is pre-configured to work with user names and roles. We will look at customizing this in a later post.

                            The Api Client Application

                            We can leave our Api Client application pretty much as-is at the moment. If you don't have the client application set up, you can pull down the source for the project from the Github repo. Make sure to checkout the branch owin-auth (not master!).

                            Recall that we has set up our application to request a token from our Api, and then make some Api calls to the CompaniesController:

                            Abbreviated Client Code Showing the Token Request:
                            static async Task Run()
                            {
                            // Create an http client provider:
                            string hostUriString = "http://localhost:8080";
                                var provider = new apiClientProvider(hostUriString);
                            string _accessToken;
                                Dictionary<string, string> _tokenDictionary;
                            try
                                {
                            // Pass in the credentials and retrieve a token dictionary:
                                    _tokenDictionary = await provider.GetTokenDictionary(
                            "john@example.com", "JohnsPassword");
                                    _accessToken = _tokenDictionary["access_token"];
                            // Write the contents of the dictionary:
                            foreach (var kvp in _tokenDictionary)
                                    {
                                        Console.WriteLine("{0}: {1}", kvp.Key, kvp.Value);
                                        Console.WriteLine("");
                                    }
                            // Create a company client instance:
                                    var baseUri = new Uri(hostUriString);
                                    var companyClient = new CompanyClient(baseUri, _accessToken);
                            // ... a bunch of code calling to API and writing to console...
                                }
                            catch (AggregateException ex)
                                {
                            // If it's an aggregate exception, an async error occurred:
                                    Console.WriteLine(ex.InnerExceptions[0].Message);
                                    Console.WriteLine("Press the Enter key to Exit...");
                                    Console.ReadLine();
                            return;
                                }
                            catch (Exception ex)
                                {
                            // Something else happened:
                                    Console.WriteLine(ex.Message);
                                    Console.WriteLine("Press the Enter key to Exit...");
                                    Console.ReadLine();
                            return;
                                }
                            }

                             

                            The only thing we have changed in the above code is the password we are passing in with the token request - we have changed it to match the password for the user record we created in our Seed() method.

                            Running the Application with an Authenticated User

                            If we run our Web Api application, and then run the client, everything should work swimmingly. The Web Api application spins up the same as it always has, and the client output should look familiar:

                            Console Output from Client Application:

                            client-with-authneticated-user

                            Everything looks the same as it did when we wrapped up the previous post, because we haven't changed anything the affects how the client application does its job. We've only changed the internals of our Web Api so that the embedded authorization server now knows how to retrieve user data from our database in order to authenticate a user, and perform a basic authorization check against the roles available to that user.

                            Let's see what happens when things go wrong.

                            Improper Authentication - Invalid Credentials

                            First, let's see what happens if we try to request a token with the wrong password. In the client application, change the password we are using in our token request to something other than "JohnsPassword":

                            Using Incorrect Password for Client Token Request:
                            // Pass in the credentials and retrieve a token dictionary:
                            _tokenDictionary = await provider.GetTokenDictionary(
                            "john@example.com", "SomePassword");
                            _accessToken = _tokenDictionary["access_token"];

                             

                            If we run the client again, we see all is not well:

                            Running the Client with Invalid Credentials:

                            client-with-invalid-password

                            In this case, were get back an "Invalid Grant" because the client could not properly authenticate with the credentials provided.

                            On the other hand, things look a little different is we request a token for a user which can be authenticated, but who is not authorized access to the resource requested.

                            Insufficient Authorization

                            Recall that in our Web Api application, we protected the CompaniesController resource using the [Authorize] attribute, and we restricted access to users in the role "Admin":

                            The CompaniesController is Protected Using [Authorize]:
                            [Authorize(Roles="Admin")]
                            publicclass CompaniesController : ApiController
                            {
                            // ... blah blah Controller Methods etc...
                            }

                             

                            Also recall that we seeded two users in our database. The user "jimi" does not have a claim for the "Admin" role, but instead claims the "User" role. Let's change the code in our client application to request an access token for "jimi" instead, and then see what happens.

                            Change Client Token Request for Alternate User:
                            // Pass in the credentials and retrieve a token dictionary:
                            _tokenDictionary = await provider.GetTokenDictionary(
                            "jimi@example.com", "JimisPassword");
                            _accessToken = _tokenDictionary["access_token"];

                             

                            Running the client application now produces a slightly different result:

                            Running the Client with Valid Credentials but Insufficient Authorization:

                            client-with-insufficient-authorization

                            Unlike previously, we did not receive an invalid grant error, because the user credentials were properly authenticated. However, the user does not possess the proper Role claim in our system to access the protected resource.

                            In reality, the default implementation of [Authorize] limits our ability to leverage claims to the fullest extent. [Authorize] recognizes claims for user names, and roles. What if we want more granular control over our application permissions?

                            We're not going to go into that in this post. However, keep this in mind, as leveraging Claims, and customizing authentication using claims instead of simple roles can become important for more complex application which require fine-grained control of permissions.

                            What Next?

                            In this post we created a "quick and dirty" implementation which performs some very basic authentication and authorization for our application.

                            In the real world, we would definitely tend to some critical details, such as proper crypto for hashing passwords. We would also probably want to beef up our design by applying some common patterns of abstraction. Notice, we have coded everything here directly to the implementation class. Also, we have rather tightly coupled our logical processing to our persistence model.

                            Lastly, we have put in place only the most rudimentary validation and exception handling.

                            We could go down a long road exploring how to better separate our persistence mechanism from our authentication logic, and more effectively handling exceptions and errors. However, those details are often application-specific, and/or require a long, long post.

                            Instead, we could now take everything we have learned, and pull in some ready-made components which already provide all of this, and more.

                            If the work we have done so far has been beginning to look a little familiar, that is no accident.

                            In the next post, we will implement our own authentication and authorization using the Identity 2.1 Framework.

                            NEXT:  Understanding OWIN/Katana Authentication/Authorization Part III: Adding Identity

                            Additional Resources and Items of Interest

                            Articles by others I have found invaluable:

                            ASP.NET Web API: Understanding OWIN/Katana Authentication/Authorization Part III: Adding Identity

                            $
                            0
                            0

                            eyball-500This is the third post in a series in which we have built up a minimal, self-hosted, OWIN-based Web Api application essentially from scratch. Our objective has been to develop a better understanding of how the various components fir together and interact in an OWIN-based environment, and to do so without creating any dependencies on IIS or the heavy weight System.Web.dll.

                            Up to this point, we have created a basic Web Api, and implemented our own authentication/authorization, using basic OWIN authorization, and our own set of models. What we have built so far represents a bare-bones model of how authentication and authorization work in an OWIN-based application. We have taken some architectural shortcuts in the name of maintaining a simple, easy to understand structure as again, our goal so far has emphasized concept over details.

                            Image by alles-schlumpf  |  Some Rights Reserved

                            Previous posts, in order:

                            In this post, we are going pull in the ASP.NET Identity framework, and ideally, we will again achieve a better understanding of how Identity fits in to a general Web Api application, and we will allow Identity to perform some of the heavy lifting for us when it comes to difficult, hard-to-get-right-even-for-the-experts details such as crypto and security details.

                            Source Code for Examples

                            We are building up a project over a series of posts here. In order that the source for each post make sense, I am setting up branches that illustrate the concepts for each post:

                            On Github, the branches of the Web Api repo so far look like this:

                            • Branch: Master - Always the most current, includes all changes
                            • Branch: auth-db - The code we build up in the course of the previous post, adding a persistence layer for our authentication system.
                            • Branch: auth-identity - the code we will build out in the course of this post. We will start where we left off in the previous post, and modify to bring in a minimal implementation using Identity Framework.

                            The code for the API client application is in a different repo, and the branches look like this:

                            • Branch: Master - Always the most current, includes all changes
                            • Branch: owin-auth - Added async methods, and token-based authentication calls to the Web Api application. The code for the client application remains unchanged, except when we need to switch out user credentials.

                            In the previous article, we created create the classes MyUser and MyUserClaim classes in order to implement our authorization and authentication mechanism in the OWIN/Katana environment, and which also became our code-first models for database persistence via Entity Framework. We also created the MyUserStore class, which contained the methods necessary to save and retreive user authentication data from our backing store.

                            We had assembled these very rudimentary classes into a functioning authentication and authorization framework of sorts, using them in our application to perform the basic functions needed to properly authenticate a user, and establish a minimal authorization mechanism based upon the role claims possessed by each user.

                            In this post, we are going to use ASP.NET Identity instead, and replace our crude, homebuilt mechanism with a fully-functioning, if basic, auth system.

                            Core Identity Framework

                            To understand how Identity will fit into our application, and the OWIN/Katana environment, it is useful to examine the structure of Identity framework itself.

                            The actual core Identity library is Microsoft.AspNet.Identity.Core. This library defines a host of interfaces upon which the function of Identity is based, and a smaller number of concrete implementation classes which are expressed in terms of these interfaces. We actually already have this library in our project, because we pulled in the Microsoft.AspNet.Identity.Owin library previously via Nuget. We haven't used any of the identity components to this point, but we made use of some items from dependent libraries included in that Nuget package, such as Microsoft.Owin.Security and Microsoft.Owin.OAuth

                            In general, the models which might need to be consumed in an application are expressed as interfaces, and the internals of the framework provide implementation for those interfaces. It is up to the application, and/or any other frameworks pulled in, to provide the concrete implementations for these model interfaces.

                            For example, the core Identity framework provides us with a pair of interfaces to represent a User:

                            Two Versions of the IUser Interface:
                            // Interface with generic type argument for the Key:
                            publicinterface IUser<out TKey>
                            {
                                TKey Id
                                {
                            get;
                                }
                            string UserName
                                {
                            get;
                            set;
                                }
                            }
                            // Interface derived from IUser<Tkey> Specifying string Key:
                            publicinterface IUser : IUser<string> { }

                             

                            In a similar manner, most of the interfaces defined in the core Identity framework to represent persistence models are expressed in a manner which allows us to specify the type for the key to be used.

                            Additionally, many of the Identity interfaces are dependent on other interfaces in the framework. In these cases, the interface is expressed in terms of a generic type argument representing the concrete implementation of the dependency. For example, core Identity framework provides two interfaces to represent a UserStore:

                            Two Versions of the IUserStore Interface:
                            // Interface with generic type arguments for User, and the User Key:
                            publicinterface IUserStore<TUser, in TKey> : IDisposable
                            where TUser : class, IUser<TKey>
                            {
                                Task CreateAsync(TUser user);
                                Task DeleteAsync(TUser user);
                                Task<TUser> FindByIdAsync(TKey userId);
                                Task<TUser> FindByNameAsync(string userName);
                                Task UpdateAsync(TUser user);
                            }
                            // Interface expressing IUserStore in terms of generic User type, 
                            // and specifying a string User Key
                            publicinterface IUserStore<TUser> : IUserStore<TUser, string>, IDisposable
                            where TUser : class, IUser<string>
                            {
                            }

                             

                            If you explore the Microsoft.AspNet.Identity.Core library using a free tool such as Telerik's fine Just Decompile, you can explore the various interfaces and concrete classes available, and develop an understanding of how they relate. However, a quick look using even the VS Object Browser will reveal that there are no concrete implementations of the basic model interfaces we need in order to implement Identity in our application. For this, we either need to roll our own, or pull in another library which provides ready-to-use implementations.

                            Since we are already using Entity Framework, in our case this is easy.

                            Identity and Entity Framework

                            The Microsoft.AspNet.Identity.EntityFramework library provides concrete implementation classes needed to use Identity from an application using Entity Framework. In this library we find some model classes we can use as-is, or which we can extend and customize as needed. For example, the IdentityUser class provides a concrete implementation for IUser<Tkey> :

                            The Base IdentityUser Class:
                            // Base implements IUser<TKey> and is expressed with generic type arguments
                            // for other model types required by Identity Framework:
                            publicclass IdentityUser<TKey, TLogin, TRole, TClaim> : IUser<TKey>
                                where TLogin : IdentityUserLogin<TKey>
                                where TRole : IdentityUserRole<TKey>
                                where TClaim : IdentityUserClaim<TKey>
                            {
                            public IdentityUser()
                                {
                            this.Claims = new List<TClaim>();
                            this.Roles = new List<TRole>();
                            this.Logins = new List<TLogin>();
                                }
                            publicvirtual TKey Id { get; set; }
                            publicvirtualstring UserName { get; set; }
                            publicvirtualstring Email { get; set; }
                            publicvirtualbool EmailConfirmed { get; set; }
                            publicvirtualstring PhoneNumber { get; set; }
                            publicvirtualbool PhoneNumberConfirmed { get; set; }
                            publicvirtualstring SecurityStamp { get; set; }
                            publicvirtualbool TwoFactorEnabled { get; set; }
                            publicvirtualstring PasswordHash { get; set; }
                            publicvirtualint AccessFailedCount { get; set; }
                            publicvirtualbool LockoutEnabled { get; set; }
                            publicvirtual DateTime? LockoutEndDateUtc { get; set; }
                            public ICollection<TLogin> Logins { get; set; }
                            public ICollection<TRole> Roles { get; set; }
                            public ICollection<TClaim> Claims { get; set; }
                            }
                            // Alternate implementation derives from Generic implementation, 
                            // and expresses Generic model types in terms of classes defined 
                            // within Identity.EntityFrameowrk Library: 
                            publicclass IdentityUser : IdentityUser<string, IdentityUserLogin, 
                                IdentityUserRole, IdentityUserClaim>, IUser, IUser<string>
                            {
                            public IdentityUser()
                                {
                            this.Id = Guid.NewGuid().ToString();
                                }
                            public IdentityUser(string userName) : this()
                                {
                            this.UserName = userName;
                                }
                            }

                             

                            We can see in the above example that there is a lot of functionality ready to go in the basic IdentityUser implementation. Also, note that the various generic type arguments provided in the base implementation are again provided such that we might extend our Identity model classes with custom implementations, for example, if we wanted to use integer keys instead of strings.

                            The Identity.EntityFramework library provides similar implementations for the other interfaces defined in Identity.Core. In addition, as we might expect, Identity.EntityFramework also includes the IdentityDbContext class, which knits together the various model classes, ready for use in a EF/Code-First application.

                            What is important here is understanding that the Identity.Core library provides the interfaces we need, and implements the interactions between those interfaces. It is up to us to provide the implementation for those interfaces, either by rolling our own, or by using a library specific to our persistence model such as Identity.EntityFramework.

                            Add Identity.EntityFramework Library Via Nuget

                            Since we are using Entity Framework in our minimal OWIN Web Api project, we will pull in the Identity.EntityFramework package we discussed above to take advantage of the ready-made Identity implementation afforded by the Identity team.

                            NOTE: This post assumes you are working with ASP.NET < 5.0, and Identity 2.1. As of this publication date, the newest package for this library is a pre-release of Identity 3.0 which targets ASP.NET 5. Unless you are working with ASP.NET 5.0 ("vNext") you want to make sure you are pulling in version 2.1

                            Add the Microsoft.AspNet.Identity.EntityFramework Nuget Package:
                            PM> Install-Package Microsoft.AspNet.Identity.EntityFramework -Version 2.1.0

                             

                            We already have the Identity.Core library in our example project, because it was included when we pulled in the Identity.Owin Nuget package in Part I of this series.

                            Add Identity to the Self-Hosted Web Api - Models and Stores

                            To get started, we will be picking up where we left off in the previous post. Recall that we had added an AuthModels.cs file, and coded up a MyUser class, a MyUserClaim class, a MyPasswordHasher class, and a MyUserStore class.

                            We can get rid of all that now, delete the AuthModels.cs file.

                            In order to add the (mostly) ready-to-use Identity framework to our project, let's add a new code file named IdentityModels.cs, and add the following code:

                            Add Identity Models:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add using statements:
                            using Microsoft.Owin;
                            using Microsoft.AspNet.Identity;
                            using Microsoft.AspNet.Identity.Owin;
                            using Microsoft.AspNet.Identity.EntityFramework;
                            namespace MinimalOwinWebApiSelfHost.Models
                            {
                            publicclass ApplicationUser : IdentityUser
                                {
                            // A default Constructor:
                            public ApplicationUser() { }
                            public ApplicationUser(string email) : base(email)
                                    {
                            // Use the email for both user name AND email:
                                        UserName = email;
                                    }
                                }
                            publicclass ApplicationUserManager 
                                    : UserManager<ApplicationUser>
                                {
                            public ApplicationUserManager(IUserStore<ApplicationUser> store) 
                                        : base(store) { }
                            publicstatic ApplicationUserManager Create(
                                        IdentityFactoryOptions<ApplicationUserManager> options,
                                        IOwinContext context)
                                    {
                            returnnew ApplicationUserManager(
                            new UserStore<ApplicationUser>(
                                                context.Get<ApplicationDbContext>()));
                                    }
                                }
                            }

                             

                            Now, let's take a good hard look at what's going on in the above code.

                            First, we have added an ApplicationUser class, which derives from IdentityUser. IdentityUser is a concrete implementation if the Identity.CoreIUser interface, and is provided by the Identity.EntityFramework library we discussed previously. We aren't doing much in this derived class at this point, but we will be adding to it later.

                            Next, we have the ApplicationUserManager class, which derives from UserManager. Unlike IdentityUser, the UserManager class is a part of the Identity.Core library. In other words, any application using the Identity framework can expect to have access to UserManager, or a derivation similar to what we have done above.

                            Notice that our ApplicationUserManager expects an argument of IUserStore as a constructor parameter. What's this?

                            We'll take a short detour to discuss UserManager and UserStore, and the purpose behind each.

                            UserManager and UserStore - What's the Difference?

                            The core Identity framework defines the UserManager class to implement various functionality required to, well, manage user information according to business rules and configuration established either by Identity framework itself, or as part of configuration options set up during development.

                            These framework "rules" and configuration items are independent of the specific persistence store used to save and retrieve the user identity data. In other words, the UserManager understands and works with Identity model objects, without concern for the concrete database underlying the application.

                            Examples of the sorts of functionality afforded by UserManager include methods such as:

                            • CreateAsync(TUser user, string Password)
                            • AddToRoleAsync(TKey userId, string role)
                            • AddClaimAsync(Tkey userId, Claim claim)

                            The UserManager class is defined in terms of various interfaces which represent abstractions over database-specific implementation models. As an example, the basic UserManager is defined with a generic type argument for the IUser implementation, which must be specified. The UserManager class also requires a constructor argument which implements the IUserStore interface.

                            A concrete implementation of IUserStore represents the underlying persistence layer of the application. In other words, a UserStore implementation knows how to "talk" to a specific data store (such as MongoDb, SQL Server, RavenDb, Etc.).

                            In our code, we are using the default UserStore implementation provided by EntityFramework (which is, itself, an abstraction over our SQL CE or SQL Server database…).

                            The idea behind defining a UserManager base class in Identity.Core in terms of an interface IUserStore is to achieve a clean separation between the business rules governing how authentication and authorization occurs between Identity model objects, and the details of the application's specific backing store.

                            Within out application proper, when we use Identity we should generally be using the UserManager (or a derived version of it) the work directly with our identity model objects. We rarely have need to consume an instance of UserStore directly, except for the purpose of injecting it as a constructor argument to UserManager.

                            UserManager, UserStore, and Identity:

                            usermanager-userstore

                            Also notice in our code, we have added a static method, Create(). We'll discuss this momentarily as well. But first, we will update the code for our database context.

                            Update the DbContext to Inherit from IdentityDbContext

                            When we finished the last article in this series, we had updated our ApplicationDbContext code file to look like this:

                            The Previous DbContext:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add using:
                            using System.Data.Entity;
                            using System.Security.Claims;
                            namespace MinimalOwinWebApiSelfHost.Models
                            {
                            publicclass ApplicationDbContext : DbContext
                                {
                            public ApplicationDbContext()
                                        : base("MyDatabase")
                                    {
                                    }
                            static ApplicationDbContext()
                                    {
                                        Database.SetInitializer(new ApplicationDbInitializer());
                                    }
                            public IDbSet<Company> Companies { get; set; }
                            public IDbSet<MyUser> Users { get; set; }
                            public IDbSet<MyUserClaim> Claims { get; set; }
                                }
                            publicclass ApplicationDbInitializer 
                                    : DropCreateDatabaseAlways<ApplicationDbContext>
                                {
                            protected async overridevoid Seed(ApplicationDbContext context)
                                    {
                                        context.Companies.Add(new Company { Name = "Microsoft" });
                                        context.Companies.Add(new Company { Name = "Apple" });
                                        context.Companies.Add(new Company { Name = "Google" });
                                        context.SaveChanges();
                            // Set up two initial users with different role claims:
                                        var john = new MyUser { Email = "john@example.com" };
                                        var jimi = new MyUser { Email = "jimi@Example.com" };
                                        john.Claims.Add(new MyUserClaim 
                                        { 
                                            ClaimType = ClaimTypes.Name, 
                                            UserId = john.Id, 
                                            ClaimValue = john.Email 
                                        });
                                        john.Claims.Add(new MyUserClaim 
                                        { 
                                            ClaimType = ClaimTypes.Role, 
                                            UserId = john.Id, 
                                            ClaimValue = "Admin" 
                                        });
                                        jimi.Claims.Add(new MyUserClaim 
                                        { 
                                            ClaimType = ClaimTypes.Name, 
                                            UserId = jimi.Id, 
                                            ClaimValue = jimi.Email 
                                        });
                                        jimi.Claims.Add(new MyUserClaim 
                                        { 
                                            ClaimType = ClaimTypes.Role, 
                                            UserId = john.Id, 
                                            ClaimValue = "User" 
                                        });
                                        var store = new MyUserStore(context);
                                        await store.AddUserAsync(john, "JohnsPassword");
                                        await store.AddUserAsync(jimi, "JimisPassword");
                                    }
                                }
                            }

                             

                            In the same code file, we had defined both our ApplicationDbContext, and a database initializer.

                            Now that we have access to the Identity.Core and Identity.EntityFramework libraries, we can simplify this somewhat.

                            First of all, Identity.EntityFramework provides us with IdentityDbContext, which, as its name implies, is an Identity-specific implementation of the DbContext. There is a little more going on under the hood than we will cover here, but essentially, IdentityDbContext provides us with a base class from which we can inherit, and which provides a DbContext implementation which works with the base Identity.EntityFramework models we will be working with.

                            First, we are going to modify the code for our ApplicationDbContext above to derive from IdentityDbContext. Then, we will update the ApplicationDbInitializer to work with our new DbContext and Identity models.

                            Modify DbContext to Derive from IdentityDbContext:
                            using System;
                            using System.Collections.Generic;
                            using System.Linq;
                            using System.Text;
                            using System.Threading.Tasks;
                            // Add using:
                            using System.Data.Entity;
                            using System.Security.Claims;
                            // Add THESE to use Identity and Entity Framework:
                            using Microsoft.AspNet.Identity;
                            using Microsoft.AspNet.Identity.EntityFramework;
                            namespace MinimalOwinWebApiSelfHost.Models
                            {
                            // Derive from IdentityDbContext:
                            publicclass ApplicationDbContext : IdentityDbContext<ApplicationUser>
                                {
                            public ApplicationDbContext()
                                        : base("MyDatabase") { }
                            static ApplicationDbContext()
                                    {
                                        Database.SetInitializer(
                            new ApplicationDbInitializer());
                                    }
                            // Add a static Create() method:
                            publicstatic ApplicationDbContext Create()
                                    {
                            returnnew ApplicationDbContext();
                                    }
                            // We still need a DbSet for our Companies 
                            // (and any other domain objects):
                            public IDbSet<Company> Companies { get; set; }
                                }
                            publicclass ApplicationDbInitializer 
                                    : DropCreateDatabaseAlways<ApplicationDbContext>
                                {
                            protected async overridevoid Seed(ApplicationDbContext context)
                                    {
                                        context.Companies.Add(new Company { Name = "Microsoft" });
                                        context.Companies.Add(new Company { Name = "Apple" });
                                        context.Companies.Add(new Company { Name = "Google" });
                                        context.SaveChanges();
                            // Set up two initial users with different role claims:
                                        var john = new ApplicationUser 
                                        { 
                                            Email = "john@example.com", 
                                            UserName = "john@example.com" 
                                        };
                                        var jimi = new ApplicationUser 
                                        { 
                                            Email = "jimi@Example.com", 
                                            UserName = "jimi@example.com" 
                                        };
                            // Introducing...the UserManager:
                                        var manager = new UserManager<ApplicationUser>(
                            new UserStore<ApplicationUser>(context));
                                        var result1 = await manager.CreateAsync(john, "JohnsPassword");
                                        var result2 = await manager.CreateAsync(jimi, "JimisPassword");
                            // Add claims for user #1:
                                        await manager.AddClaimAsync(john.Id, 
                            new Claim(ClaimTypes.Name, "john@example.com"));
                                        await manager.AddClaimAsync(john.Id, 
                            new Claim(ClaimTypes.Role, "Admin"));
                            // Add claims for User #2:
                                        await manager.AddClaimAsync(jimi.Id, 
                            new Claim(ClaimTypes.Name, "jimi@example.com"));
                                        await manager.AddClaimAsync(jimi.Id, 
                            new Claim(ClaimTypes.Role, "User"));
                                    }
                                }
                            }

                             

                            In the above code, notice that we have now implemented our ApplicationDbContext by deriving from IdentityDbContext<ApplicationUser> . In so doing, we have specified a DbContext implementation which will be ready to use, and already work with our ApplicationUser class.

                            We have also updated our ApplicationDbInitializer, making use of the handy interface afforded by our ApplicationUserManager to easily add our test users, and related user claims.

                            Pay close attention here. Remember previously, how we went ahead and create a mock password hasher, and all that nonsense about implementing a proper crypto mechanism for hashing passwords? here, Identity has taken care of all that for us. No mocking needed. Just the way we like it, we have left the details of the crypto to folks who know what they are doing. Remember, crypto is hard, even for the experts, and it is a solved problem.

                            Now, before we go much further, we are going to take another short detour. Notice how, like we did with ApplicationUserManager, we also defined a static Create() method on our ApplicationDbContext? We're going to take a look at why we did that now.

                            Context per Request and CreatePerOwinContext

                            From the standpoint of our data model, we want to make sure that we are always working with the same instance of our database context, and hence, with the same set of objects. For example, if two separate instances of ApplicationDbContext (or, similarly, UserStore or UserManager) are created while processing the same HTTP request, it is possible we could introduce changes to two instances of the same  user data.

                            We want to make sure that when we retreive a user object, it will always refer to the same instance of that user's data within the context of a single HTTP request.

                            The Microsoft.AspNet.Identity.Owin library provides an extension method by which we can ensure a single instance of an object is created per OwinContext. The CreatePerOwinContext() method allows us to pass in a generic type argument, and a function reference which returns an instance of the desired object. We set this up during the Owin Configuration() method. Then, when the OwinContext object is created for each incoming HTTP request, a discreet instance of the desired object will be created per OWIN context.

                            For a deeper look at this concept, see Per request lifetime management for UserManager class in ASP.NET Identity

                            In our application, we want to make sure that during request processing, we are only ever working against the same instance of ApplicationDbContext, as well as ApplicationUserManager. We achieve this by adding those state Create() methods on ApplicationDbContext and ApplicationUserManager respectively, and then passing references to them to CreatePerOwinContext() during the Owin Configuration() method.

                            We will want to add the following code to our ConfigureAuth() method in our Startup class:

                            Create ApplicationDbContext and ApplicationUserManager per Owin Context:
                            privatevoid ConfigureAuth(IAppBuilder app)
                            {
                            // Create per OWIN Context:
                                app.CreatePerOwinContext<ApplicationDbContext>(ApplicationDbContext.Create);
                                app.CreatePerOwinContext<ApplicationUserManager>(ApplicationUserManager.Create);
                                var OAuthOptions = new OAuthAuthorizationServerOptions
                                {
                                    TokenEndpointPath = new PathString("/Token"),
                                    Provider = new ApplicationOAuthServerProvider(),
                                    AccessTokenExpireTimeSpan = TimeSpan.FromDays(14),
                            // Only do this for demo!!
                                    AllowInsecureHttp = true
                                };
                                app.UseOAuthAuthorizationServer(OAuthOptions);
                                app.UseOAuthBearerAuthentication(new OAuthBearerAuthenticationOptions());

                             

                            Recall from our previous explorations of OWIN and Katana that when we pass function references like this, the function itself is not executed at this point in our code. Instead, a reference to the function is added to the Owin Environment Dictionary, which will then be Invoked each time a new Owin context is created in response to an incoming HTTP request.

                            We can see some of the logic to all this if we take a closer look at the static Create() method we defined on our ApplicationUserManager class:

                            The Create() Method from ApplicationUserManager:
                            publicstatic ApplicationUserManager Create(
                                IdentityFactoryOptions<ApplicationUserManager> options,
                                IOwinContext context)
                            {
                            returnnew ApplicationUserManager(
                            new UserStore<ApplicationUser>(
                                        context.Get<ApplicationDbContext>()));
                            }

                             

                            Notice how even here, we are initializing an instance of UserStore and passing in a reference to ApplicationDbContext by retrieving it from the OwinContext instance? This way we ensure that even here, we are using the single DbContext object instance created specifically for each request.

                            Update OAuth Server Provider for Identity

                            Now that we have implemented a very basic Identity model, we can modify our ApplicationOauthServerProvider. In the call to GrantResourceOwnerCredentials(), we can avail ourselves of our ApplicationUserManager and Identity models to simplify the grant process.

                            Add Microsoft.AspNet.Identity.Owin to the using statements at the top of the file, and then replace the existing code as follows:

                            Update the code for GrantResourceOwnerCredentials for Identity:
                            using System.Threading.Tasks;
                            // Add Usings:
                            using Microsoft.Owin.Security;
                            using Microsoft.Owin.Security.OAuth;
                            using System.Security.Claims;
                            using MinimalOwinWebApiSelfHost.Models;
                            // Add to use Identity:
                            using Microsoft.AspNet.Identity.Owin;
                            namespace MinimalOwinWebApiSelfHost.OAuthServerProvider
                            {
                            publicclass ApplicationOAuthServerProvider 
                                    : OAuthAuthorizationServerProvider
                                {
                            publicoverride async Task ValidateClientAuthentication(
                                        OAuthValidateClientAuthenticationContext context)
                                    {
                            // This call is required...
                            // but we're not using client authentication, so validate and move on...
                                        await Task.FromResult(context.Validated());
                                    }
                            publicoverride async Task GrantResourceOwnerCredentials(
                                        OAuthGrantResourceOwnerCredentialsContext context)
                                    {
                            // ** Use extension method to get a reference 
                            // to the user manager from the Owin Context:
                                        var manager = context.OwinContext.GetUserManager<ApplicationUserManager>();
                            // UserManager allows us to retrieve use with name/password combo:
                                        var user = await manager.FindAsync(context.UserName, context.Password);
                            if (user == null)
                                        {
                                            context.SetError(
                            "invalid_grant", "The user name or password is incorrect.");
                                            context.Rejected();
                            return;
                                        }
                            // Add claims associated with this user to the ClaimsIdentity object:
                                        var identity = new ClaimsIdentity(context.Options.AuthenticationType);
                            foreach (var userClaim in user.Claims)
                                        {
                                            identity.AddClaim(new Claim(userClaim.ClaimType, userClaim.ClaimValue));
                                        }
                                        context.Validated(identity);
                                    }
                                }
                            }

                             

                            Once again, see in the above how we made sure to grab a reference to the ApplicationUserManager instance from the context object? The context object helpfully provides a GetUserManager() extension method.

                            Also note how the ApplicationUserManager makes it very convenient to retrieve a user object with a user name and password. If the password fails to match, null will be returned, and the invalid grant error returned.

                            Update the CompaniesController to Use the DbContext per Request

                            We don't HAVE to do this, but we can. We might update our CompaniesController to take advantage of the Context-per-Request strategy afforded by Identity here.

                            Make sure to add Microsoft.AspNet.Identity.Owin to the using statements at the top of the CompaniesController file.

                            Update CompaniesController to Use Context per Request:
                            publicclass CompaniesController : ApiController
                            {
                            // Ditch THIS:
                            //ApplicationDbContext dbContext = new ApplicationDbContext();
                            // Replace with something like THIS:
                                ApplicationDbContext dbContext
                                {
                            get
                                    {
                            return Request.GetOwinContext().Get<ApplicationDbContext>();
                                    }
                                }
                                ... All the rest of the controller code....
                            }

                             

                            With that, we can give our new and improved application a test run, using the same Api Client application from our previous post.

                            Running the Application with Identity in Place

                            If we spin up our Web Api, all should look well:

                            Running the Web Api Application - All is Well:

                            run-web-api-application

                            Next, if we run the API Client application, making sure we use our valid user credentials (they should match the credentials for the Admin user in the Seed() method), everything should work as before:

                            Running the API Client Application:

                            run-api-client-application-with-identity

                            Similarly, if we modify the code in our client application and pass an invalid password, we get an invalid grant error:

                            Invalid Password Submitted by Client Returns Invalid Grant Error:

                            run-api-client-application-with-identity-invalid-grant

                            And, if we change the client credentials to those of the user in the plain old User role (which does NOT have authorization to access our CompaniesController), we receive a 401/Unauthorized error:

                            API Client with Insufficient Authorization:

                            run-api-client-application-with-identity-unauthorized

                            Summing it Up

                            In the course of the last four articles, we have hopefully developed a better idea of how the pieces fit together in an OWIN-based Web Api application. The lines between the various frameworks become blurry as an application grows, and my objective was to break things down in a manner that would bring some clarity to what happens where, and why.

                            The structure of our example application is crude, and if you were to take this a few steps further, you would definitely want to change some things, do some refactoring, and implement a great deal more exception and error handling.

                            Similarly, our console-based API Client application is sufficient only to the task of exercising our Web Api for demonstration purposes.

                            From here, we could go a long ways further in developing a claims-based authorization model. As it stands, our little sample application does use claims, but relies on the in-build ability of [Authorize] attribute to perform a role-based authorization check. We will explore claims more extensively in an upcoming post.

                            As always, feedback is most welcome, especially if you noticed me doing something stupid, or find outright errors in the code. Pull Requests are welcome against the sample repo, so long as they address improvements or bug fixes. For obvious reasons, I want to keep the code samples in sync with the articles.

                            Additional Resources and Items of Interest

                            DNVM, DNX, and DNU - Understanding the ASP.NET 5 Runtime Options

                            $
                            0
                            0

                            give-my-regards-to-mr-escher-240ASP.NET 5 introduces a new runtime model for the .NET framework which allows us to employ a "pay-as-you-go" approach, building composable applications using only those framework components our application needs, without relying upon a central, monolithic library repository present on the host machine.

                            This new model also provides us with command line tools for managing our .NET version selection, library packages, and execution environment outside of Visual Studio. It is now possible to develop cross-platform ASP.NET applications using a text editor and command line (either CMD or Powershell on Windows) without ever opening Visual Studio.

                            Image by César Astudillo  |  Some Rights Reserved

                            Understanding the relationship between the .NET Version Manager (DNVM), the .NET Execution Environment (DNX) and .NET Development Utilities (DNU) is fundamental to developing with ASP.NET 5. In this post we will look at installing and using DNVM, DNX, and DNU on to work with ASP.NET from the command line.

                            DNVM - The .NET Version Manager

                            DNVM is a version manager tool for the command line. As its name implies, DNVM provides the functionality needed to configure your .NET runtime. We can use DNVM to specify which version of the .NET Execution Environment to use at the process, user, or machine level.

                            DNX - The .NET Execution Environment

                            What is this DNX, anyway? From the ASP.NET Documentation site:

                            The .NET Execution Environment (DNX) is a software development kit (SDK) and runtime environment that has everything you need to build and run .NET applications for Windows, Mac and Linux. It provides a host process, CLR hosting logic and managed entry point discovery. DNX was built for running cross-platform ASP.NET Web applications, but it can run other types of .NET applications, too, such as cross-platform console apps.

                            Broadly speaking, different DNX runtime versions are available which reflect which .NET framework version you want to use in your application. At a basic level, there are different versions for:

                            • .NET Framework - The familiar .NET framework we all know and love.
                            • .NET Core - A subset of the .NET Framework which includes a modular runtime and library implementation and is managed via Nuget. .NET Core is cross-platform, open source, and includes the Core libraries in CoreFX, and a Core runtime in CoreCLR.
                            • Mono - Using Mono, we can create ASP.NET application which compile and run on OSX and Linux machines.

                            We can use the .NET Version Manager to select which DNX version we want to use with our application.

                            DNU - .NET Development Utilities

                            DNU is a command-line tool which provides a variety of utility functions to assist with development in ASP.NET. Most commonly, we will use DNU to install and manage library packages in our application, and/or to package and publish our own application.

                            DNU uses Nuget behind the scenes for package management and deployment.

                            Getting Started - Installing DNVM

                            If you have installed Visual Studio 2015 (currently available as a Release Candidate HERE), you already have the .NET Version Manager installed.

                            UPDATE: According to the ASP.NET team  (thanks Glenn!) DNX/DNVM isn't actually installed until you run File -> New after VS 2015 is installed, so if you have VS 2015 installed but have not cracked open a new file yet, you won't have it on your machine yet.

                            If you want to upgrade to the most recent version of DNVM, or if you want to work with ASP.NET, but don't want to install Visual Studio, you can download the DNVM script as follows from either the Windows Command prompt (CMD) or using Powershell:

                            Install or Upgrade DNVM Using CMD:
                            @powershell -NoProfile -ExecutionPolicy unrestricted -Command "&{$Branch='dev';iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}"

                             

                            Install or Upgrade DNVM Using Powershell:
                            &{$Branch='dev';iex ((new-object net.webclient).DownloadString('https://raw.githubusercontent.com/aspnet/Home/dev/dnvminstall.ps1'))}

                             

                            Once we have DNVM on our machine, we should be able to fire up the Windows command prompt, and get started.

                            At the command line (or Powershell prompt) run the following to see that DNVM is, in fact, installed on your machine:

                            Run DNVM without Arguments:
                            > dnvm

                             

                            If all has gone well to this point, you should see the following (we're going to stick with CMD for this post, to keep things simple):

                            Console Output from Running DNVM without Arguments:

                            run-dnvm-no-args

                            Now that we have DNVM installed and running, let's see which DNX versions we have available, and how to install DNX versions if we need.

                            Working with DNVM - List the Available .NET Runtimes

                            To examine the runtime options available to us, we can run the following command from the Console:

                            List Available DNX Runtimes Using DNVM List:
                            > dnvm list

                             

                            I had previously installed Visual Studio 2015 on my machine, which also installed a few DNX versions, so when I runt he above I see the following output:

                            Console Output from DNVM List:

                            run-dnvm-list

                            Because I had installed Visual Studio 2015 already, there are DNX versions available for .NET Framework (the beta4 clr in the image above) and also .NET Core (the coreclr above) for both 32 and 64 bit architectures.

                            If you have NOT installed Visual Studio 2015, your list is very likely empty. Installing DNVM does not, in and of itself, install any DNX versions on your machine. No worries, we'll take care of that next.

                            Working with DNVM - Installing DNX Runtime Versions

                            If you just installed DNVM fresh, or if you want to get the latest version of a particular DNX implementation, we can use the the dnvm install command with some appropriate arguments:

                            By default, DNVM will work with the basic .NET framework, and assume the x86 architecture. For example, if we do the following:

                            DNVM Install Latest:
                            > dnvm install latest

                             

                            DNVM will download and install the latest stable version of the regular .NET framework for the x86 architecture. If we run dnvm list again, we see the following:

                            Installed DNX Runtimes after Running DNVM Install Latest:

                            run-dnvm-install-latest-noargs

                            If we want to specify a different runtime (say, the CoreCLR instead of the .NET Framework, and/or specify the x64 version, we need to add the -r ( -runtime ) and/or -arch ( -architecture ) flags, and values:

                            DNVM Install Latest for Specific Runtime/Architecture:
                            > dnvm install latest -r coreclr -arch x64

                             

                            Once the above is finished running, we have now added the latest version of the full .NET Framework for the x86 architecture, and CoreCLR for the x64 architecture to our available runtimes list:

                            Installed DNX Runtimes:

                            run-dnvm-list-after-install

                            DNVM Upgrade VS. DNVM install

                            DNVM also has an upgrade command, which behaves just a little differently than Install.

                            DNVM Install fetches the specified version, and makes it active in the current Command process by adding it to the process PATH variable. The selection is "Active" is only for the duration of our terminal session. Once the current terminal session is closed, the active selection will revert to none, or whatever had been previously persisted in our User PATH variable as the default.

                            DNVM Upgrade does essentially the same thing, but also adds it to the User's PATH variable as the default active version, and updates the default alias. For example, if we used dnvm upgrade to install the latest 64 bit version of the .NET framework clr:

                            Upgrade .NET Framework CLR to Latest Version Using DNVM Upgrade:
                            > dnvm upgrade -r clr -arch x64

                             

                            After running the above, our Console output tells us that the latest version of dnx-clr-win-x64 has been added not only to the current process PATH, but also to our User PATH. In addition, the "default" alias has been updated to point to the just-installed version:

                            Console Output from DNVM Upgrade:

                            dnvm-upgrade

                            Note that dnvm upgrade pulls down the latest stable release from Nuget. If you want to work on the bleeding edge with the latest unstable (development) release, you can use:

                            Upgrading to Latest Unstable (development) Runtime Releases:
                            > dnvm upgrade -u

                             

                            In the above, you can specify runtime/architecture as previously using the -r and -arch flags.

                            5/17/2015 - NOTE: If you installed Visual Studio 2015, the system environment PATH variable likely points to C:\Program Files\Microsoft DNX\Dnvm\. As of this writing, the Visual Studio version of DNVM does not recognize the -u (-unstable ) flags. Even if you installed DNVM using the shell scripts at the beginning of this article, the Visual Studio variable will be found first. In order to use the -u flag, you will need to either change the order in which the PATH variables occur, or remove the Visual Studio PATH and add DNVM using one of the scripts above.

                            Working with DNVM - Selecting or Changing the Active DNX Runtime

                            Notice in the previous section the asterisk that appears in the "Active" column of the console output once we started installing new DNX runtime versions. When we use dnvm Install, DNVM makes the just-installed version the default active version for the current process (in other words, for the current terminal session only).

                            As noted previously, when we run dnvm upgrade, DNVM makes the just-installed version the default active version not only for the current process, but also at the User level.

                            We can switch to a different DNX runtime by using the dnvm use command. By default, dnvm use changes the active selection for the current Command process. For example, given the current active runtime in the console output from the previous section (1.0.0-beta4-11566 clr x64), we could decide we want to switch to the latest 64 bit coreclr version for our current terminal session instead:

                            Select or Switch to a Different Runtime for the Current Process:
                            > dnvm use 1.0.0-beta4-11566 -r coreclr -arch x64

                             

                            If we run the above command, and then run dnvm list again, we see our active version has changed:

                            New Active DNX Runtime Selected for Current Process:

                            switch-dnx-version-for-process-path

                            If we look closely at the console output above though, we see that the new version was added to the process PATH, meaning, the selection will persist for the current Console process only. If we close the console window, and open another, the default set in our User PATH will be selected again.

                            If we want to set our user default, we could run the command just like we did previously, but instead we can add the -p ( -persistent) flag, which will cause the selection to be added to our user path instead of the process path:

                            Select or Switch to a New DNX Runtime Default for User PATH:
                            > dnvm use 1.0.0-beta4-11566 -r coreclr -arch x64 -p

                             

                            Now, our selection will persist as the default between Command sessions. We can still select a different version per process just like we did previously, but until we make additional changes, the default active DNX runtime in a Command session will be the beta 4 CoreCLR from build 11566.

                            Remove Runtime References from PATH Variables

                            If we want to remove all runtime references from the process path (in other words, return to a state where no runtime is set as "Active" we can run:

                            Remove DNX Runtime References from Process PATH Variable:
                            > dnvm use none

                             

                            If we want to remove any defaults we have set in our User PATH variable, we can add the -p flag:

                            Remove DNX Runtime References from User PATH Variable:
                            > dnvm use none -p

                             

                            Use Aliases to Make Typing Easier

                            If you have been working through the examples so far, you may have noticed how painful it can be typing out the full, semantic version names each time you want to refer to a runtime version. DNVM affords us the ability to assign aliases to the different installed versions. We can do this during install or upgrade using the -a ( -alias ) flag, or we can set aliases for existing installed versions using the alias command.

                            For example, we already have an alias, default, which in my case was set up when I installed Visual Studio. It was originally assigned to the regular x86 .NET framework CLR, and then was re-assigned when we ran dnvm upgrade in the previous section. As of now, the alias default on my machine points to the latest (build 11566) x64 bit version of the .NET CLR.

                            I can set an alias for the latest x64 version of CoreCLR like so:

                            Assign an Alias to a DNX Runtime:
                            > dnvm alias core-64-latest 1.0.0-beta4-11566 -r coreclr -arch x64

                             

                            Having done that, I can now refer to that particular runtime by its alias, for example:

                            Select or Switch to a new DNX Runtime Using an Alias:
                            > dnvm use core-64-latest

                             

                            5/17/2015 - NOTE: There is currently a bug (see issue #175 / PR #248 at the DNVM Repo on Github) in which referring to a CoreClr runtime by alias does not work. As of this writing, the PR has not yet been merged, but things are supposed to work as described here. Until the issue is resolved, it is still necessary to refer to any CoreClr runtime by its full version name…

                            We can re-assign a previously set alias by simply using the dnvm alias command, and assigning the alias to a different DNX Runtime.

                            DNX and DNU - Working with an Example Project from the Command Line

                            To get a feel for how DNVM, DNU, and DNX work together, we'll put together a very basic example project, using only the Windows Command Prompt and a text editor (for this post, I'm going to use Sublime Text 3, but we could just as easily use Visual Studio Code, or Notepad).

                            First, let's create a project directory, and then open the folder in Sublime Text:

                            Create a Project Directory and Navigate into the Directory using CMD:
                            C:\Users\John> mkdir dnx_demo
                            C:\Users\John> cd dnx_demo

                             

                            Then, open the directory folder in Sublime text. First, we'll add a project.json file:

                            Add project.json File:
                            {
                            "version": "1.0.0-*",
                            "description": "Silly demo project",
                            "commands": {
                            "runme": "dnx_demo"
                              },
                            "frameworks": {
                            "dnx451": { },
                            "dnxcore50": {
                            "dependencies": {
                            "System.Console": "4.0.0-beta-22816",
                            "Microsoft.CSharp": "4.0.0-beta-22816"
                                  }
                                }
                              }
                            }

                             

                            In the above, note we have defined a command, "runme" which refers to the project name. We can invoke this command from the Command Line using dnx to run our project. Also note, we have specified both the traditional .NET Framework (dnx451) as well as the .NET Core (dnxcore50) as compilation targets, so our application wioll be cross-compiled for both DNX runtimes and frameworks.

                            Next, add a file named Program.cs and paste in the following code:

                            The Program.cs File:
                            using System;
                            namespace dnx_demo
                            {
                                public class Program
                                {
                                    public void Main(string[] args)
                                    {
                                        Console.WriteLine("No Visual Studio Here!!");
                                        Console.Read();
                                    }
                                }
                            }

                             

                            By simply adding these two files, we have (almost) everything we need to run a very basic, but complete, .NET Console application. Save the two files above, and return to the Command prompt.

                            Use DNU Restore to Restore Packages

                            Our project.json file specifies the target frameworks and dependencies our project requires. Note that for this project, there are no packages to be pulled down when we run against the standard .NET framework 4.5.1 - the required references are already present in the .NET framework itself.

                            We will need to restore packages before we can run against the .NET Core framework and CoreCLR. Remember, .NET Core is all about "pay as you go." In other words, We pull in only those libraries we need for our application to run, and leave out everything else.

                            We can restore library packages by simply running dnu restore from within our project directory:

                            Use DNU Restore to Restore Library Package Dependencies:
                            C:\Users\John\dnx_demo> dnu restore

                             

                            Run the Example Application Using DNX

                            With our package dependencies restored, we can run our application using DNX. We can now run the application, after we select which DNX runtime we want to use.

                            In my case, we set the default active runtime to the latest .NET Core CLR / x64 in a previous example, so we can run the application straight away from within our project directory:

                            Run the Example Application Using DNX:
                            C:\Users\John\dnx_demo> dnx . runme

                             

                            Take a close look there. Since I am already in the project directory, I can simply type dnx, and use a period to indicate the current directory. DNX will parse the command, runme, we set up in our project.json file, and use that to run the project.

                            dnx-run-example-using-command

                            We could also simply reference the project by name:

                            Run the Example by Referencing the Project Directory Name:
                            C:\Users\John\dnx_demo> dnx . dnx_demo

                             

                            Or, as long as we are in the project directory, we could keep it REAL SIMPLE and just use dnx . run

                            Run the Example Using dnx . run:
                            C:\Users\John\dnx_demo> dnx . run

                             

                            Now, let's switch runtimes from .NET Core to the traditional .NET Framework. Recall, we had previously used dnvm upgrade to install the latest x64 binaries for the .NET framework, and when we did that, our default alias was assigned to that runtime:

                            Switch to the .NET Framework Runtime Using DNVM Use:
                            C:\Users\John\dnx_demo> dnvm use default

                            We can check to make sure we are now targeting the .NET CLR instead of CoreCLR, and then run our application again:

                            Running the Example Using the .NET Framework and Standard CLR:

                            dnx-run-example-using-clr

                             

                            Summing Up

                            So far, we've examined the basics of using the .NET Version Manager, the .NET Development Utility (DNU), and the .NET Execution Environment in order to get a basic application up and running in the new ASP.NET environment.

                            In our simple example above, we compiled and executed our project in memory. There is no generation of binaries as part of the dnx run process. DNX, and DNU offer a wealth of additional features, such outputting binaries as a part of the build process (dnu build), creating Nuget packages (dnu pack) and other useful commands.

                            DNU, DNX, and DNVM are currently in active development, and things are changing daily. Keep your eye on the ASP.NET 5 repo, and watch for updates here and elsewhere.

                            We will explore more in upcoming posts

                            Additional Resources and Items of Interest

                            Viewing all 34 articles
                            Browse latest View live