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.Providersnamespace.
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: