In this Part of ASP.NET Core Web API Tutorial, we will briefly explain Web API Security Architecture? Also, how to setup an authentication filter? as well as implement a Web API authentication filter with the help of an example.
ASP.NET provides a very well customizable framework in order to authenticate users and authorized the access of user. In order to go in deep, lets first take a look at the difference between the concept of authentication and authorization as following:
- Authentication is identifying the user. For example, John logs in to the system and the system ask for his password with his username in order to authenticate John. Therefore, authentication is the action of verifying the validity of the identity of the user.
- Authorization refers to the action of deciding whether a user is allowed to perform a certain action. This concept is more related to the access control mechanism. For example, John has permission to get a resource but not create a resource. Therefore, when John would try to create a resource, system would prevent that operation.
How Authentication is Performed?
Here are the steps that occur during the time of user authentication in ASP.NET
- In order to verify user with username and password, if the user is authenticated, host creates a principal, an instance of IPrincipal object, representing the security context.
- The principal object is then get attached to the current thread as following:
12345678private void SetPrincipal(IPrincipal principal){Thread.CurrentPrincipal = principal;if (HttpContext.Current != null){HttpContext.Current.User = principal;}} - Now in order to verify the user, system checks associated Identity object with the principal object. If the user is authenticated, the Identity.IsAuthenticated is true. Otherwise, Identity.IsAuthenticated is false.
How to Setup an Authentication Filter?
- Enable Basic Authentication: Create a authentication filter call ‘IdentityBasicAuthentication’ and then configure that for the controller.
1234567// Require authorization for all actions on the controller.[IdentityBasicAuthentication]public class HelloRequestController : ApiController{public HttpResponseMessage Get() { ... }public HttpResponseMessage Post() { ... }} - Using Authorize to the API controller class as following:
1234567// Require authorization for all actions on the controller.[Authorize]public class HelloRequestController : ApiController{public HttpResponseMessage Get() { ... }public HttpResponseMessage Post() { ... }} - Using custom Authorize to the API controller class as following:
1234567// Require authorization for all actions on the controller and BasicAuthAttribute is a custom Authorize[BasicAuthAttribute]public class HelloRequestController : ApiController{public HttpResponseMessage Get() { ... }public HttpResponseMessage Post() { ... }} - It is possible to make any method public in a web api controller even though the controller itself is restricted.
12345678// Require authorization for all actions on the controller.[Authorize]public class HelloRequestController : ApiController{[AllowAnonymous]public HttpResponseMessage Get() { ... }public HttpResponseMessage Post() { ... }} - Restricted to only a list of Users: Here in this example, the only allowed user are defined in a list of users.
1234567// Require authorization for all actions on the controller.[Authorize(Users="John,Smith")]public class HelloRequestController : ApiController{public HttpResponseMessage Get() { ... }public HttpResponseMessage Post() { ... }} - Restricted by role: Similar to user, it is also possible to make a controller restricted to only specific roles.
1234567// Require authorization for all actions on the controller.[Authorize(Roles="Administrators")]public class HelloRequestController : ApiController{public HttpResponseMessage Get() { ... }public HttpResponseMessage Post() { ... }} - It is also possible to implement method and define different block inside the method for different role as in following example:
123456789101112public HttpResponseMessage Get(){if (User.IsInRole("Administrators")){// this block would be executed for Administrator users}if (!User.IsInRole("Administrators")){// this block would be executed for Non-Administrator users}}
- Build a full-stack web app with ASP.NET Core, Entity Framework Core and Angular 2 & 4.
- Implement a Clean & Decouple Architecture.
- Properly implement the Repository and Unit of work patterns.
- Troubleshoot common runtime errors.
- Test APIs using PostMan.
- Integrate ASP.NET MVC/Core with AngularJS.
- Understand and apply the Dependency Inversion Principle (DIP).
- Use the new dependency injection feature in ASP.NET Core.
- Build APIs with ASP.NET Core.
- and more….
Implement a Web API Authentication Filter?
Here are the steps in order to implement an authentication filter.
- Start Visual Studio and create a new ASP.NET Web Application project. Select the Web API template. Under “Add folders and core references for”, select the Web API checkbox.
- Now create Web API controller as:
1234567891011121314151617181920212223242526272829303132using System.Net.Http;using System.Web.Http;namespace WebService.Controllers{public class HelloRequestController : ApiController{public HttpResponseMessage Get(){return new HttpResponseMessage(){Content = new StringContent("GET: Hello World!")};}public HttpResponseMessage Post(){return new HttpResponseMessage(){Content = new StringContent("POST: Hello World!")};}public HttpResponseMessage Put(){return new HttpResponseMessage(){Content = new StringContent("PUT: Test message")};}}} - Run the application locally.
- Open a browser and navigate to http://localhost/api/helloworld/,. It will show the response text, “GET: Hello World!”.
- Then select MVC for the ASP.NET project type.
- A custom authorization filter need to be extended from one of these following types:
- AuthorizeAttribute: This is a basic authorization attribute, it considers the current user and its role in order to imply the authorization logic.
- AuthorizationFilterAttribute: This attribute filter out synchronous authorization logic that is not aligned with current user or its role.
- IAuthorizationFilter: This interface contains all the methods in order to execute asynchronous authorization logic.
- Create a class and extends necessary authorization class, here in this example, we would define a filter for Basic authentication.
123public class BasicAuthAttribute: ActionFilterAttribute, IAuthenticationFilter {…. …. …. ….} - The next step is to implement the method from IAuthenticationFilter as following:
123456789101112public void OnAuthenticationChallenge(AuthenticationChallengeContext filterContext){var currentuser = filterContext.HttpContext.User;if (currentuser == null || ! currentuser.Identity.IsAuthenticated){filterContext.Result = new HttpUnauthorizedResult();}}public void OnAuthentication(AuthenticationContext filterContext){} - Now use this filter to the API controller class as following:
1234567namespace WebService.Controllers{[BasicAuthAttribute]public class HelloRequestController : ApiController{}}
Along with Basic Authentication, it is also possible to make any particular method of the controller to be accessible only by the particular role, for example:
1 2 3 4 5 6 7 8 9 10 11 |
[Authorize("books")] public IHttpActionResult Get () {} [Authorize(Roles="Admin")] [Route("user/{id:guid}", Name = "GetUserById")] public async Task<IHttpActionResult> Get(string Id) {} [Authorize(Roles="Admin")] [Route("user/{id:guid}")] public async Task<IHttpActionResult> Delete(string id) |
Here every method has the annotation, [Authorize(Roles=”Admin”)], which is making this method accessible only to the logged in user whose role is Admin.