ASP. NET Web API security filter

Source: Internet
Author: User
Tags http authorization header

Original: Https://msdn.microsoft.com/zh-cn/magazine/dn781361.aspx

Authentication and authorization are the foundation of application security. Authentication determines the user's identity by verifying the credentials provided, and authorization determines whether the user is allowed to perform the requested action. Secure Web API authentication is based on determined identity requests and access to resources that are authorized by the user request.

You can use the extension points that are available in the ASP. NET Web API pipeline and use the options provided by the host to implement authentication. For the first version of the ASP. NET Web API, it is common practice to use an authorization filter or an action filter to achieve authentication. ASP. NET Web API 2 introduces a new authentication filter that is dedicated to this process. This new extensibility point allows authentication and authorization issues to be clearly separated. In this article, I'll introduce you to both security filters and use authentication and authorization as a stand-alone two aspect of the ASP. I'll show you how they can be used to implement authentication and authorization.

Options to implement security

Authentication and authorization in the ASP. NET Web API can be implemented by using the extension points provided by the host and the extension points provided by the ASP. Host-based options include HTTP modules and OWIN middleware components, while extended options for the ASP. NET Web API include message handlers, action filters, authorization filters, and authentication filters.

Host-based options are well integrated into the host pipeline and can reject invalid requests in the pipeline earlier. On the other hand, extended options for the ASP. NET Web API provide finer levels of control over the authentication process. In other words, you can set different authentication mechanisms for different controllers and even different ways of doing things. The tradeoff is better integrated with the host and rejected earlier for poor authentication granularity requests. In addition to these general features, each option has its own pros and cons, which I'll cover in a later section.

HTTP Module This is a Web API option that runs on IIS. As part of the IIS pipeline, the HTTP module allows security code to be executed earlier. The principals established from the HTTP module apply to all components, including the IIS components that run later in the pipeline. For example, if the principal was built by an HTTP module that responds to the AuthenticateRequest event, the principal's user name is correctly recorded in the Cs-username field of the IIS log. The biggest drawback of HTTP modules is the lack of granularity. The HTTP module responds to all requests that enter the application. For Web applications that have different capabilities, such as HTML markup generation, Web APIs, and so on, it is often not a flexible method to have an HTTP module enforce authentication in some way. In this case, another disadvantage of using the HTTP module is that it relies on host-iis.

OWIN Middleware This is another host-related option for OWIN hosts. ASP. NET Web API 2 fully supports OWIN. The most compelling reason to use OWIN middleware to ensure security is that the same middleware can work in different frameworks. This means that you can use multiple frameworks (such as ASP. NET Web API, SignalR, etc.) in your application, but with common security middleware. However, the minimum granularity of the OWIN middleware can be a disadvantage because the OWIN middleware runs in the OWIN pipeline and is typically called when processing individual requests. In addition, OWIN middleware can only be used with OWIN-compatible hosts, although this dependency is better than relying on a specific host/server (such as IIS), but this is the actual situation of the HTTP module. It is important to note that it is because of the MICROSOFT.OWIN.HOST.SYSTEMWEB package that the Owin middleware can be run in the (integrated IIS) ASP.

message handlers are extended options provided by the ASP. NET Web API, and the greatest benefit of using message handlers to ensure security is that it is not dependent on the underlying host or server as the concept of the ASP. In addition, the message handler runs only for Web API requests. The disadvantage of using message handlers is the lack of finer control. Message handlers can be configured to run on all requests or on a specific route as a global handler. For a given route, you can have multiple controllers. All of these controllers and the action methods they contain must share the same authentication that is enforced by the message handlers configured for this route. In other words, the minimum granularity of authentication performed by a message handler is at the routing level.

Another extended option provided by the action filter by the ASP. NET Web API is the action filter. However, from the point of view of performing authentication, it is not a viable option, simply because it does not start running until the authorization filter runs in the ASP. NET Web API pipeline. For authentication and authorization to work properly, authentication must run prior to authorization.

Authorization Filter However, another extended option provided by the ASP. NET Web API is an authorization filter. One of the most common ways to perform custom authentication is to use authorization filters for situations that require a higher granularity than the message handler can provide. The main problem with using authorization filters for authentication and authorization is that the ASP. NET Web API does not guarantee the order in which authentication filters are executed. Basically, this means that authorization filters that perform authorization run correctly until the authorization filter that performs the authentication is running, making the authorization filter option unsuitable for authentication as the action filter option.

Authentication Filters This is the focus of this article, which is the latest extension option available for ASP. NET Web API 2. The authentication filter runs after the message handler and is run before all other filter types. Therefore, they are a better choice for implementing authentication-related operations. Most importantly, the authentication filter is run before the authorization filter. By using a filter specifically for authentication or authorization, you can handle authentication and authorization-related issues separately.

In addition, authentication filters are particularly useful because they provide control or level of granularity. Take the example of a Web API designed to be used by native mobile applications and browser-based AJAX applications. A mobile application might display a token in the HTTP Authorization header, while an AJAX application might use an authentication Cookie as a credential. In addition, assuming that a subset of the API is sensitive and only applicable to native mobile applications, you want to ensure that the operation method can only be accessed by providing a token, rather than providing a cookie (the cookie is susceptible to cross-site request forgery [XSRF], while the HTTP The token in the Authorization header is not). In this case, authentication must be done at a finer level of granularity than the host-based option or even the message handler. The authentication filter is ideal for this use case. You can apply authentication filters based on all of these controllers ' tokens, or the action methods that must be used, as well as a Cookie based on other places. Suppose, in this case, you have some common ways of doing things that you want to access through tokens or cookies. You can apply both Cookie and token authentication filters to these common methods of action, and there is always a filter that can successfully authenticate. This control is the most valuable authentication filter that can be pushed up to the table. When precise control of authentication is required, it is a good practice to resolve authentication-related issues through an authentication filter and to resolve authorization-related issues through authorization filters.

It is worth mentioning that the out-of-the-box authentication filter (Hostauthenticationfilter) enables ASP. NET Web API authentication through the OWIN middleware. When OWIN authentication middleware runs in a pipeline and tries to "proactively" authenticate incoming requests, it can also be configured as "passive" authentication incoming requests, if needed. Hostauthenticationfilter allows the passive OWIN authentication middleware to run based on later names in the Web API pipeline. This approach enables authentication code that can be shared across multiple frameworks, including the OWIN authentication middleware provided by Microsoft, while still allowing the granularity of each operation to be used for authentication.

Although you can mix host-level authentication and authentication based on finer-grained Web API pipelines, you must also carefully consider how host-level authentication can affect WEB API authentication. For example, you can have cookie-based authentication middleware at the host level, which means you can work with other frameworks, such as ASP. NET MVC, but letting the Web API use Cookie-based principals makes it vulnerable to attacks such as XSRF. To help deal with this situation, the suppressdefaulthostauthentication extension method causes the Web API to ignore any authentication configured at the host level. The Default Web API Visual Studio template enables cookies at the host level and uses the hosting token at the Web API level. Because cookies are enabled at the host level and require XSRF mitigation, templates also use Suppressdefaulthostauthentication to block Web API pipelines from using Cookie-based principals. This way, the Web API will use only token-based principals, and you do not need to establish a mechanism for the Web API to withstand XSRF attacks.

Working together with authentication filters and authorization filters

In the ASP. NET Web API pipeline, the first reason for the authentication filter to run (and then run the authorization filter) is simple because authorization depends on the identified identity, which is the result of the authentication. Here's how you can design an authentication filter and authorization filter to work together to protect the ASP.

The basic principle of design is that the authentication filter is only responsible for validating credentials, rather than letting it handle other problems. For example, if you do not provide credentials, the authentication filter will not reject requests with 401 of unauthorized status codes. It does not identify an authenticated identity at all and leaves the authorization phase with the issue of how to handle anonymous requests. The authentication filter basically performs three types of operations:

    1. If the credential you are interested in does not exist in the request, the filter will not take any action.
    2. If there is a credential and the credential is valid, the filter determines an identity as an authenticated principal.
    3. If the credentials are present but the credentials are invalid, the filter notifies the ASP. NET Web API framework by setting an incorrect result, which can basically lead to an "unauthorized" response to the requestor.

If the authentication filter running in the pipeline cannot detect invalid credentials, the pipeline will continue to run even if the unidentified identity has not been verified. You can determine how to handle this anonymous request only if it is based on a component that later runs in the pipeline.

At the most basic level, authorization filters only check that the identified identity is authenticated. However, authorization filters can also ensure that:

    • The authenticated user name is on the Allowed users list.
    • At least one role that is associated with an authenticated identity is listed on the list of allowed roles.

Although the out-of-the-box authorization filter performs role-based access control only as described earlier, a custom authorization filter from the out-of-the-box authorization filter can perform claims-based access control by examining claims that belong to identities identified by the authentication filter.

If all the authorization filters are working properly, the pipeline will continue to execute, and the action method of the final API controller will generate a response for the request. If an identity is not identified, or if there is a mismatch in the user name or role requirements, the authorization filter rejects a request that has a 401 unauthorized response. Figure 1 illustrates the roles that two filters play in three scenarios: no credentials, invalid credentials, and valid credentials.

Figure 1 Security filters in the ASP. NET Web API pipeline

Create an authentication filter

The authentication filter is a class that implements the Iauthenticationfilter interface. This interface is available in two ways: Authenticateasync and Challengeasync, as follows:

public interface IAuthenticationFilter : IFilter{  Task AuthenticateAsync(HttpAuthenticationContext context,     CancellationToken cancellationToken);  Task ChallengeAsync(HttpAuthenticationChallengeContext context,    CancellationToken cancellationToken);}

The Authenticateasync method accepts Httpauthenticationcontext as a parameter. This context is how the Authenticateasync method feeds the results of the authentication to the ASP. NET Web API framework. If the request message contains real credentials, the Principal property of the incoming Httpauthenticationcontext object is set to the authenticated principal. If the credentials are not valid, the Errorresult property of the Httpauthenticationcontext parameter is set to Unauthorizedresult. If the request message does not contain credentials at all, the Authenticateasync method does nothing. The code in Figure 2 shows a typical implementation of the Authenticateasync method that covers these three scenarios. The authenticated principal used in this example is the only name and the ClaimsPrincipal of the role declaration.

Figure 2 Authenticateasync method

Public Task Authenticateasync (httpauthenticationcontext context,  cancellationtoken cancellationtoken) {  var req = context. request; //Get credential from the Authorization Header//(if present) and authenticate  if (req. Headers.authorization! = null &&    "Somescheme". Equals (req. headers.authorization.scheme,      stringcomparison.ordinalignorecase))   {     var creds = req. headers.authorization.parameter;    if (creds = = "Opensesame")//Replace with a real check  & nbsp {      var claims = new list<claim> ()       {         New Claim (Claimtypes.name, "Badri"),        new Claim (Claimtypes.role, "admin")      };      var id = new Claimsidentity (Claims, "Token");      var Principal = new ClaimsPrincipal (new[] {ID});     //The request message contains valid credential       context. Principal = principal;   }    else    {      The request message contains invalid credential      context. Errorresult = new Unauthorizedresult (        new authenticationheadervalue[0], Context. Request);   } }  return task.fromresult (0);}

You can use the Authenticateasync method to implement the core authentication logic for validating credentials in a request and to add an authentication challenge using the Challengeasync method. When the status code is 401 unauthorized, the authentication challenge is added to the response, and in order to check the status code, you need the response object. However, the Challengeasync method does not allow you to check for responses or set up a challenge directly. In fact, this approach is performed in the request Processing section of the Web API pipeline before the method is manipulated. However, the parameter httpauthenticationchallengecontext of the Challengeasync method allows the operation result object (Ihttpactionresult) to be assigned to the result property. The Executeasync method of the action result object waits for the task to generate a response, checks the response status code, and adds a www-authenticate response header. The code in Figure 3 shows a typical implementation of the Challengeasync method. In this example, I only add a hard-coded challenge. The Resultwithchallenge class is the result class that I created to add a challenge.

Figure 3 Challengeasync method

 public Task Challengeasync (Httpauthenticationchallengecontext context,  CancellationToken CancellationToken) {  context. Result = new Resultwithchallenge (context. Result);  return Task.fromresult (0);} public class resultwithchallenge:ihttpactionresult{  Private readonly ihttpactionresult next;  public Resultwithchallenge (Ihttpactionresult Next)   {    this.next = next; }  public Async Task <HttpResponseMessage> Executeasync (    cancellationtoken cancellationtoken)   {     var response = await next. Executeasync (CancellationToken);    if (response. StatusCode = = httpstatuscode.unauthorized)     {      response. HEADERS.WWWAUTHENTICATE.ADD (        new Authenticationheadervalue ("Somescheme "," Somechallenge "));   }    return response; }}  

The following code shows the complete filter class:

public class TokenAuthenticationAttribute :   Attribute, IAuthenticationFilter{  public bool AllowMultiple { get { return false; } }  // The AuthenticateAsync and ChallengeAsync methods go here}

In addition to implementing the Iauthenticationfilter interface, deriving from a property can use this class as a class (Controller) level or a method (action method) level property.

Therefore, you can create an authentication filter that is responsible only for authentication-specific credentials (false tokens in this case). The authentication filter does not have authorization logic; its sole purpose is to handle authentication: (if any when processing the request message) determine the identity (if any when processing the response message) to return the challenge. Authorization filters handle authorization issues, such as checking whether the identity is authenticated or listed in the list of allowed users or roles.

Using Authorization filters

The basic goal of using authorization filters is to perform authorization to determine whether users have access to the requested resource. The Web API provides the use of so-called Authorizeattribute authorization filters. Apply this filter to ensure that identities are authenticated. You can also configure authorization properties with a specific list of user names and roles that are allowed. The code in Figure 4 shows the authorization filters that are applied using different identity attributes, at different levels (in general, at the controller level and at the action method level). The filters in this example ensure that identities are authenticated as a whole. Filters used at the controller level ensure that identities are authenticated and at least one of the roles associated with that identity is "administrator." The filter used at the action method level ensures that the identity is authenticated and that the user name is "Badri". One thing to note here is that authorization filters at the action method level also inherit the controller-level and global-level filters. Therefore, to successfully complete the authorization, all filters must pass: The user name must be "Badri", one of the roles must be "Administrator" and the user must be authenticated.

Figure 4 Using an authorization filter at three different levels

public static class WebApiConfig{  public static void Register(HttpConfiguration config)  {    // Other Web API configuration code goes here    config.Filters.Add(new AuthorizeAttribute()); // Global level  }}[Authorize(Roles="admin")] // Controller levelpublic class EmployeesController : ApiController{  [Authorize(Users="badri")] // Action method level  public string Get(int id)  {    return “Hello World”;  }}

Out-of-the-box authorizeattribute is useful, but if you need more customization, you can subclass it to implement additional authorization behavior. The following code shows a custom authorization filter:

public class RequireAdminClaimAttribute : AuthorizeAttribute{  protected override bool IsAuthorized(HttpActionContext context)  {    var principal =      context.Request.GetRequestContext().Principal as ClaimsPrincipal;    return principal.Claims.Any(c => c.Type ==      "http://yourschema/identity/claims/admin"      && c.Value == "true");  }}

This filter only checks for "administrator" custom claims, but you can use the principals and other additional information in Httpactioncontext to customize the authorization here.

In the first version of the ASP., custom authorization filters are often mistakenly used for authentication, but for ASP. NET Web API 2, the authentication filter now has its own place in the pipeline, which helps develop clean, modular code Easily consider the issues of authentication and authorization separately.

Filter Overrides

As I explained earlier, authorization filters can be applied at the action method level, the controller level, or the global level. By specifying the authorization filter globally, you can enforce authorization for all action method calls within the scope of all controllers. If you want to avoid a global configuration check by some means, it is easy to do so using the AllowAnonymous property.

The code in Figure 5 shows the use of the AllowAnonymous property at the controller level. Although the authorization filter is applied globally, the AllowAnonymous property that is used with Publicresourcescontroller is exempt from authorization for requests that are passed in to this controller.

Figure 5 Using the AllowAnonymous property

public static class WebApiConfig{  public static void Register(HttpConfiguration config)  {    // Other Web API configuration code goes here    config.Filters.Add(new AuthorizeAttribute()); // Global level  }}[AllowAnonymous]public class PublicResourcesController : ApiController{  public string Get(int id)  {    return “Hello World”;  }}

The AllowAnonymous property provides a way for a specific operation to override the authorization configured by a higher-level authorization filter. However, allowanonymous only allows you to override the authorization. Suppose you most want to use HTTP Basic authentication to authenticate most operations, but one operation can only be authenticated with tokens. It is a good idea to globally configure token authentication and then override the authentication for this operation (similar to how allowanonymous overrides authorization).

ASP. NET Web API 2 introduces a new type of filter to resolve this situation, that is, overwrite the filter. Unlike the overlay filters introduced in Allowanonymous,asp.net Web API 2, you can work with any type of filter. overriding filters, as the name implies, can overwrite filters configured on a higher level. To override the authentication filters configured at a higher level, use the out-of-the-box property overrideauthentication. If you have an authentication filter that is appropriate for global use, and you want to prevent it from running a specific action method or controller, you can apply overrideauthentication only at the level you want.

Overriding filters are much more than blocking some filters from running. Suppose you have two authentication filters, one for verifying the security token, and another for validating the username/password in the HTTP basic scenario. Both of these filters are applied globally, making your API flexible enough to accept tokens or usernames/passwords. The following code shows the two authentication filters applied at the global scope:

public static class WebApiConfig{  public static void Register(HttpConfiguration config)  {    // Other Web API configuration code goes here    config.Filters.Add(new TokenAuthenticator());    config.Filters.Add(new HttpBasicAuthenticator(realm: "Magical"));  }}

Now, perhaps you want to make sure that only tokens are used to access the credentials of a particular action method. How does overrideauthentication enable you to meet this need, is it forbidden to run all filters? The following are important characteristics of overriding filters, which clear all filters specified at a higher level, but do not delete the filters that they specify at the same levels. This basically means that you can add one or more authentication filters at a particular level, while clearing all the other filters on the higher levels. Back to the requirement that only tokens be used as credentials to access a specific action method, you can simply specify the Overrideauthentication property and the Tokenauthenticator property at the action method level, as shown in the following code (this ensures that only Tokenauthenticator for the Operation Method Getallowedfortokenonly run):

public class EmployeesController : ApiController{  [OverrideAuthentication] // Removes all authentication filters  [TokenAuthenticator] // Puts back only the token authenticator  public string GetAllowedForTokenOnly(int id)  {    return “Hello World”;  }}

As a result, an overlay filter that introduces ASP. 2 provides a global scope for specifying filters, and at a lower level selectively offers greater flexibility in running filters on areas that must only be covered by global behavior.

In addition to the Overrideauthentication property, there is also an out-of-the-box property called Overrideauthorization, which removes the authorization filter specified at a higher level. The difference, compared to allowanonymous, is that overrideauthorization only removes authorization filters on the higher level. However, it does not delete the specified authorization filter at the same level. AllowAnonymous enables the ASP. NET Web API to skip the related authorization process, even if the authorization filter specified at the same level as allowanonymous is ignored.

Summarize

You can use the options provided by the host, as well as the extension points provided by the ASP. NET Web API pipeline, to perform authentication in the ASP. Host-based options are well integrated into the host pipeline and reject invalid requests in the pipeline early. The ASP. NET Web API extension Point provides a finer level of control over the authentication process. If you need more control over authentication, for example, to use different authentication mechanisms for different controllers and even different action methods, it is a good practice to resolve authentication-related issues through authentication filters and to resolve licensing-related issues through authorization filters.

ASP. NET Web API security filter

Related Article

Contact Us

The content source of this page is from Internet, which doesn't represent Alibaba Cloud's opinion; products and services mentioned on that page don't have any relationship with Alibaba Cloud. If the content of the page makes you feel confusing, please write us an email, we will handle the problem within 5 days after receiving your email.

If you find any instances of plagiarism from the community, please send an email to: info-contact@alibabacloud.com and provide relevant evidence. A staff member will contact you within 5 working days.

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.