Image by alles-schlumpf | Some Rights Reserved
This 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.
Previous posts, in order:
- ASP.NET: Understanding OWIN, Katana, and the Middleware Pipeline
- ASP.NET Web Api 2.2: Create a Self-Hosted OWIN-Based Web Api from Scratch
- ASP.NET Web Api: Understanding OWIN/Katana Authentication/Authorization Part I: Concepts
- ASP.NET Web Api: Understanding OWIN/Katana Authentication/Authorization Part II: Models and Persistence
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.
- Core Identity Framework
- Add Identity.EntityFramework Library Via Nuget
- Add Identity to the Self-Hosted Web Api – Models and Stores
- UserManager and UserStore – What’s the Difference?
- Update the DbContext to Inherit from IdentityDbContext
- Context per Request and CreatePerOwinContext
- Update OAuth Server Provider for Identity
- Update the CompaniesController to Use the DbContext per Request
- Running the Application with Identity in Place
- Additional Resources and Items of Interest
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: public interface IUser<out TKey> { TKey Id { get; } string UserName { get; set; } } // Interface derived from IUser<Tkey> Specifying string Key: public interface 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: public interface 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 public interface 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: public class 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>(); } public virtual TKey Id { get; set; } public virtual string UserName { get; set; } public virtual string Email { get; set; } public virtual bool EmailConfirmed { get; set; } public virtual string PhoneNumber { get; set; } public virtual bool PhoneNumberConfirmed { get; set; } public virtual string SecurityStamp { get; set; } public virtual bool TwoFactorEnabled { get; set; } public virtual string PasswordHash { get; set; } public virtual int AccessFailedCount { get; set; } public virtual bool LockoutEnabled { get; set; } public virtual 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: public class 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 { public class ApplicationUser : IdentityUser { // A default Constructor: public ApplicationUser() { } public ApplicationUser(string email) : base(email) { // Use the email for both user name AND email: UserName = email; } } public class ApplicationUserManager : UserManager<ApplicationUser> { public ApplicationUserManager(IUserStore<ApplicationUser> store) : base(store) { } public static ApplicationUserManager Create( IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { return new 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.Core
IUser
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:
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 { public class 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; } } public class ApplicationDbInitializer : DropCreateDatabaseAlways<ApplicationDbContext> { protected async override void 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: public class ApplicationDbContext : IdentityDbContext<ApplicationUser> { public ApplicationDbContext() : base("MyDatabase") { } static ApplicationDbContext() { Database.SetInitializer( new ApplicationDbInitializer()); } // Add a static Create() method: public static ApplicationDbContext Create() { return new ApplicationDbContext(); } // We still need a DbSet for our Companies // (and any other domain objects): public IDbSet<Company> Companies { get; set; } } public class ApplicationDbInitializer : DropCreateDatabaseAlways<ApplicationDbContext> { protected async override void 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:
private void 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:
public static ApplicationUserManager Create( IdentityFactoryOptions<ApplicationUserManager> options, IOwinContext context) { return new 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 { public class ApplicationOAuthServerProvider : OAuthAuthorizationServerProvider { public override 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()); } public override 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:
public class 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:
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:
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:
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:
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
- Taiseer Joudeh’s blog is rich with excellent information (Congrats to Taiseer on the MVP!)
- Brock Allen and Dominic Baier both cover many relevant topics in their blogs, and in documenting their development of Identity Server (Congrats on Version 3!)
- To see where Identity is headed as it moves towards a Version 3 Release, see the development happen in the open on the Identity Github Repo (and, contribute!)
- ASP.NET Web Api: Understanding OWIN/Katana Authentication/Authorization Part II: Models and Persistence
- ASP.NET Web Api: Understanding OWIN/Katana Authentication/Authorization Part I: Concepts
- ASP.NET Web Api 2.2: Create a Self-Hosted OWIN-Based Web Api from Scratch
- ASP.NET: Understanding OWIN, Katana, and the Middleware Pipeline
Comments
Bharat Mishra
AuthorHi,
Below line throwing error:
var result1 = await manager.CreateAsync(john, “JohnsPassword”);
Error: The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.
I can’t find why ObjectContext getting disposed.
Chris
AuthorJust wanted to say thanks for going through the trouble of creating these walk-throughs / code samples. This was really helpful.
Alex
AuthorHi
Thanks for this series.
I keep having this error while seeding the database and I can’t find out why. I am pretty new to WebApi and EF so please bear with me.
“The ObjectContext instance has been disposed and can no longer be used for operations that require a connection.”
Any ideas on why?
Thanks in advance.
Alex
Bharat Mishra
AuthorHi Alex,
I am getting similar issue; Please let me know if you have got solution.
Williams
AuthorI think this is very insightful. I loved every bit of information. I was able to get what it all meant.
Thanks. Really appreciate the posts
I agree
AuthorRegards for helping out, good information.
Bernie
AuthorThanks for this insightful series!
alon
AuthorVery Good !!!
My wish for next series is to wrap the Owin authentication as full web api like you did in MVC "ASP.NET Identity 2.0: Customizing Users and Roles".
Im using Pure html pages in SPA with KnockoutJs to hold the Token when login
And then every call must be with that Token.
I'm building a Crm web application which contain groups of users,
What Im try to figure out is, when a user login – how do i check his info like for which group he is belong ?
Thanks
John Atten
AuthorI believe you want to jump whole hog into ASP.NET 5, MVC 6, Identity 3, and EF 7 instead of mixing and matching.
I haven;t messed with the"vNext" stuff much yet (that's next on my to-do list), but my understanding is that the pipeline is conceptually similar, but implemented differently.
I'll have to get onto that before I can give you an intelligent answer!
Bob
AuthorAbove I meant Identity 2.1
Also forgot to paste the Article URL I was referencing to,
http://www.asp.net/vnext/overview/aspnet-vnext/create-a-web-api-with-mvc-6
Bob
AuthorJohn, I'm still reviewing this great series of articles by you John, especially this last one.
I'm trying to prepare myself for how OWIN/Katana and the Middleware Pipeline will be integrated in ASP.NET 5.0, as you've mentioned that will likely be part of ASP.NET 5.0
[quote][i]One of the goals of ASP.NET 5.0 is to unify the MVC and Web API frameworks[/i][/quote]
The article gives the following code which seems to hint at that,
public class Startup
{
// Add this method:
public void ConfigureServices(IServiceCollection services)
{
services.AddMvc();
}
public void Configure(IApplicationBuilder app)
{
// New:
app.UseMvc();
app.UseWelcomePage();
}
}
How might I use the String Identity 1.1, Web API 2.2 and Entity Framework 7 into the above example using your great references?
Bob
AuthorJohn…a BiG Thanks for Part III.
If you want feedback I'll let you know how it goes.
Again, I like you're approach.
Bob