Step-6 Authentication Using Owin Authentication Middleware and ASP.NET Identity
This is step 6 of my blog series on Web Application Development in Fsharp using ASP.NET MVC
In the last blog post we have added an interactive feature to search phones and in this blog post we are going to add authentication to our PhoneCat application using Owin Authentication Middleware and ASP.NET identity.
In the first half of this blog post we are going to see how to implement a new user registration workflow
And in the second half, we are going to see how to do authentication using the registered login credentials
Owin Authentication Middleware in brief
In the Owin Specification, a middleware access the request before it reaches the underlying web framework. You can view the authentication middleware as gate keeper who checks the incoming request, if it is authenticated it let the request to go through the other middlewares in the pipeline else it bypasses the pipeline and take a different route (usually redirecting to the login page)
In the blog post we are going to use cookie based authentication middleware which is similar to the Asp.Net Forms Authentication and it also supports Claims.
Another appreciable feature in Owin it is upto us on how to validate the incoming user credentials. We can plug it to any external authentication providers like Google, Facebook, etc., or using Active Directory or Asp.Net Identity. Here we are going to validate the user credentials using Asp.Net Identity framework which provides the required interfaces for handling the authentication and Entity Framework Identity which provides the concrete implementations for this Identity interfaces.
Setting up the infrastructure
Create a new F# class library project with the name Identity
and install the Microsoft AspNet.Identity.EntityFramework nuget package which provides a pluggable data store for the user identity management using Entity Framework.
Then add a source file in the Identity
project with the name User
and update it as below
1 2 3 4 5 6 7 8 9 |
|
The IdentityUser
represents the default implementation of IUser interface which provides the basic properties for a user. We can extend it by adding our custom properties. Here we have added a custom property called Name
which represents the name of the user.
The AllowNullLiteral attribute is one of the feature in F# which explicitly make a type to allow null as one of its value. F# by default doesn’t support null value for its types and the beauty is you will get a compiler error if you assign null to an identifier! Pretty cool isn’t it? No Null Exception, No Billion Dollar Mistake! Then why we are allowing it explicitly here. Well, it has been added here for a reason and I will reveal it later in this blog post
The IdentityDbContext
represents the data store abstraction of Identity entities like Users, Roles, Claims and Logins. The UserDbContext
is just a subclass of IdentityDbContext
which tells Entity Framework to use the connection string name IdentityConnection
Setting up User Registration
With all the needed infrastructure in place its time to do the actual work and lets start with adding a provision for registering new user.
In the Web
project add the reference to the Identity
project and install the following nuget packages
1 2 3 |
|
Create a controller with the name AuthenticationController
in the Web
project and update it as below
1 2 3 4 5 6 7 8 9 10 |
|
The AuthenticationController
depends on UserManager
to take care of managing users. UserManager is an abstraction defined in the AspNet.Identity assembly. It provides various APIs to work with the underlying user datastore.
As the name indicates RegisterViewModel
represents the view model for Registration View. The CLIMutable attribute creates a default constructor and “getters and setters” for all the properties of a record type when it is compiled to IL and here it makes the RegisterViewModel
compatible with the Asp.Net DefaultModelBinder which expects the types to have default constructor to bind the incoming request.
The action method Register
simply renders the Register View. This view not created yet so lets add it. Create a cshtml file with the name Register.cshtml in the directory Views/Authentication.
This is a strongly typed view of type RegisterViewModel
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
|
Note: I’ve intentionally ignored the bootstrap css form styles here to keep the code snippet less noisy
It’s a typical razor view representing the registration screen. For the sake of simplicity I’ve ignored the retype password field.
The next step is handling the new user registration POST request.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
Add the above action method in the AuthenticationController
to create new user. It creates a User
object from the RegisterViewModel
and use it to create a new user via UserManager
. We are using Email
as the UserName
in the above code snippet
If the user creation is successful, we are redirecting the user to the home page else we are showing the error messages to the user. After we implemented the login we will modify the above logic to sign in after successful registration.
The next task is creation of AuthenticationController
instance. Open MvcInfrastructure
that we have created in the step-2 and update it as below.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
|
As we are using email as username we need to change the user validator in the UserManager
to allow the alphanumeric characters in the username.
The final step is providing the connection string to access the identity database. Open the Web.config file and add the following
1 2 3 4 5 |
|
As we are using Entity Framework’s Code First here, the schema will be generated dynamically when we run the code for the very first time.
That’s it. We have wired up everything to create a new user!
Setting up User Login
As we are going to use owin cookies based authentication middleware, the first step to tell the application startup pipeline to use cookie authentication.
Open Startup
and update it to support authentication
1 2 3 4 5 6 7 8 9 10 11 12 13 |
|
The AuthenticationType
is an identifier to distinguish between different authentication middlewares and the LoginPath
is the url to the Login Page which will be used to redirect the unauthorized requests.
After setting up cookie authentication, like we did for new user registration, we are going to create a view to enable the user to login.
Add the Login
action method in the AuthenticationController
and also create LoginViewModel
1 2 3 4 5 6 7 8 9 10 |
|
and create Login
view in the Authentication\Login directory
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
|
The next step is the crux of this blog post. Challenging the incoming user login credentials against its corresponding registered one.
We will be using UserManager
’s following methods to achieve it.
-
Find - Returns a user with the specified username and password or null if there is no match (C# needs Option type badly!). In the beginning of the blog post I’ve mentioned you that I will talk about why we are using
AllowNullLiteral
attribute for theUser
class. As you see hereFind
method returnsnull
if the user is not available! So, As per this definitionnull
is valid value forUser
class. -
CreateIdentity - Creates the Claim Identity representing the user. We need this claim identity to signin and also to pass around the claim details.
Both of the above methods are having their async counterparts. But for the sake of simplicity I’m ignoring it. May be it can be a exercise for you to figure it out!
Let’s add some utility function to handle finding the user and signing in
1 2 3 4 5 6 7 8 9 |
|
Since we are using Email as the UserName here in this example, we need to have a specific claim to pass around the Name of the user. That’s what we are doing in the signin
method. Later we will be using this claim to display the user name in the header of the page.
Great! Now its time to handle handle Login POST request.
1 2 3 4 5 6 7 8 9 10 |
|
The Login
action method just tries to find the user using given credentials. If the user is available, signin to the application using his credentials and redirect to the home page else show login error to the user.
We can add this same signin behavior after successful user registration too.
1 2 3 4 5 6 7 8 9 |
|
Since UserManager
is an IDisposable
. It’s good practices to dispose it after using. So, Override Dispose
method in AuthenticationController
and dispose it.
1 2 3 4 |
|
The final pending work is displaying the user name in the header after successful login. Open Layout.cshtml add the following lines
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 |
|
Adding Logout
Adding logout is very simple and straight forward. All we need to do is just invoke the Owin Authentication Manager’s SignOut
method. Create an action method in AuthenticationController
to handle it
1 2 3 4 |
|
Summary
The interoperability offered by F# to integrate with the existing C# libraries is very seamless and I hope you have got it too! You can find the source code in the github as usual. In the next blog post We will see how to add validations in the User Registration. Stay tuned!