Using Forms Authentication in ASP.NET Web API
ASP.NET developers commonly use forms authentication to secure their web
pages. Just like ASP.NET web forms and ASP.NET MVC applications, Web API can
take advantage of forms authentication to implement authentication and role
based security. I have already explained how forms authentication works in
web forms and
MVC applications. In
this post I explain how forms authentication can be used in Web API being
consumed in an MVC application. This example assumes that the Web API and the
View that consumes it using jQuery are parts of the same project (that is they
belong to the same origin).
The overall process of implementing forms authentication remains the same in
case of Web API also. However, there are a few points that you need to keep in
mind:
- Web API itself doesn't log-in or log-out a user. That is taken care by
the underlying web application - be it web forms application or MVC
application. Typically a user logs into the application using some web form
or a view designed for that purpose and then proceeds to call a Web API.
- The Web API action methods can check the authentication status of a
user, his membership information and also his role information.
- If an unauthenticated user tries to access a Web API that requires
authentication you typically get "undefined" error in the browser (you will
see this later).
Configure SQL Server
Membership features of ASP.NET require certain database tables and stored
procedures. To configure your SQL server database for enabling application
services (membership, roles, profiles) you use aspnet_regsql.exe command line
tool. We won't discuss this tool here because its usage is exactly the same as
in the case of web forms and MVC applications. You can also let ASP.NET
configure and create a new LocalDb database for you if you don't want to use an
existing database. If so, skip this step and move to the next.
Configure Web API project to use forms authentication
Now create a new ASP.NET MVC 4 project and select Web API as its project
template. Then open its web.config file and add the following markup to it:
<authentication mode="Forms">
<forms loginUrl="~/home/login" defaultUrl="~/home/index" ></forms>
</authentication>
The <authentication> section sets the mode of authentication and in this case
it is set to Forms. The <forms> tag configures the loginUrl and defaultUrl
attributes to ~/home/login and ~/home/index respectively. The loginUrl attribute
indicates URL of the login page whereas defaultUrl attribute indicates URL of
the default page.
If you haven't configured a database to store membership information and
don't want to use an existing database, select PROJECT > ASP.NET Configuration
to open Website Administration Tool. Click on the security tab of the tool and
create two roles - Administrator and Operator. Then create two users - user1 and
user2 - and associate them with Administrator and Operator roles respectively.
This will add a new LocalDb database to the App_Data folder and will also add
membership, roles and profile providers in the web.config as shown below:
<membership defaultProvider="DefaultMembershipProvider">
<providers>
<add name="DefaultMembershipProvider"
type="System.Web.Providers.DefaultMembershipProvider,... />
</providers>
</membership>
<roleManager enabled="true" defaultProvider="DefaultRoleProvider">
<providers>
<add name="DefaultRoleProvider"
type="System.Web.Providers.DefaultRoleProvider... />
</providers>
</roleManager>
<profile defaultProvider="DefaultProfileProvider">
<providers>
<add name="DefaultProfileProvider"
type="System.Web.Providers.DefaultProfileProvider... />
</providers>
</profile>
As you can see the membership, roles and profile providers are being picked
from
System.Web.Providers namespace.
Create Login and Logout views
Since we have created users through WAT tool as mentioned in the preceding
section there is no need to create registration page. You can directly create
Login and Logout actions and views. To do so, open the HomeController from the
controllers folder and add the following actions to it:
public ActionResult Login()
{
return View();
}
[HttpPost]
public ActionResult Login(string userid,string password)
{
if (Membership.ValidateUser(userid, password))
{
FormsAuthentication.SetAuthCookie(userid, false);
Response.Redirect(FormsAuthentication.DefaultUrl);
}
return View();
}
public ActionResult Logout()
{
return View();
}
[HttpPost]
public ActionResult DoLogout()
{
FormsAuthentication.SignOut();
Response.Redirect(FormsAuthentication.LoginUrl);
return View();
}
The Login(), Logout() and DoLogout() methods are easy to understand. The
second version of Logn() method accepts userid and password parameters. Inside,
it uses ValidateUser() method of Membership class to check whether a user has
supplied valid credentials. If so, a forms authentication cookie is set using
SetAuthCookie() method of FormsAuthentication class. The user is then redirected
to default page (/home/index in this case).
The DoLogout() method removes the forms authentication cookie using Signout()
method of FormsAuthentication class and takes the user to login page
(/home/login in this case).
The Login and Logout views are quite simple in nature and are shown below:
Create a Web API
Now let's create a simple Web API for testing purpose. One the default
ValuesController class and modify it as shown below:
public class ValuesController : ApiController
{
[Authorize]
public IEnumerable<string> Get()
{
if (User.Identity.IsAuthenticated)
{
MembershipUser user = Membership.GetUser();
if (Roles.IsUserInRole(user.UserName, "Administrator"))
{
return new string[] { "Blue", "Red" };
}
else
{
return new string[] { "Orange", "White" };
}
}
else
{
throw new Exception("You are not authorized to use this page!");
}
}
As you can see the ValuesController inherits from ApiController and contains
Get() method. The Get() method returns an IEnumerable of strings and responds to
GET requests. Notice that the Get() method is decorated with [Authorize]
attribute. Remember that this [Authorize] attribute comes from System.Web.Http
namespace whereas [Authorize] used in normal MVC controller comes from
System.Web.Mvc namespace. The [Authorize] attribute indicates that the Get()
method can be accessed only by authenticated users.
Inside the Get() method User.Identoty.IsAuthenticated is used as an
additional check to ensure that the desired code is executed only for an
authenticated user. Then the code implements role based security and checks
whether current user belongs to Administrator role or not. This is done using
IsUserInRole() method of Roles class. Accordingly a string array containing some
color values (Blue and Red for administrators and Orange and White for other
users) is returned to the caller. If a request is not authenticated an exception
is thrown.
Consume the Web API
The jQuery code that calls the Web API resides inside Index view and is shown
below:
$(document).ready(function () {
$("#button1").click(function () {
$.ajax({
url: '/api/values',
type: 'GET',
success: function (r) { alert('Success : ' + r); },
error: function (err) { alert('Error : ' + err.description); }
});
});
});
As you can see the click event handler of a button (button1) invokes values
web API using $.ajax() of jQuery. The success function displays the returned
array of colors in an alert dialog. Similarly, the error function displays the
error information in an alert dialog.
If you try to invoke the web API without first signing in to the system you
will get the following error:
If you log in to the system and then invoke the web API you will get the
color array as shown below: