Apply [Authorize] attribute implicitly to all Web API controllers

28,281

Solution 1

You have two options

  1. Controller level by decorating your controller with authorize attribute.

    [Authorize]
    [RoutePrefix("api/account")]
    public class AccountController : ApiController
    {
    
  2. You can also set it global level to all routes, in Register method of WebApiConfig.cs file

     config.Filters.Add(new AuthorizeAttribute());
    

Solution 2

You can set the AuthorizeAttribute to the WebApiConfig file like below:

public static void Register(HttpConfiguration config)
{
  config.Routes.MapHttpRoute(
    name: "DefaultApi",
    routeTemplate: "api/{controller}/{id}",
    defaults: new { id = RouteParameter.Optional }
  );
  config.Filters.Add(new AuthorizeAttribute());
}

Now all methods from your Web Api controllers will need authorization. If you want to remove this authorization requirement for a method, you need to add the attribute [AllowAnonymous] like in the Login action method.

Solution 3

In ASP.NET Core Web API, it's like this:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers(o =>
    {
        var policy = new AuthorizationPolicyBuilder()
            .RequireAuthenticatedUser()
            .Build();

        o.Filters.Add(new AuthorizeFilter(policy));
    });
}

Source: https://joonasw.net/view/apply-authz-by-default

Solution 4

Since ASP.NET Core 3.0 there is a new way to do this without filters by using the Endpoint Routing middleware, see: https://docs.microsoft.com/en-gb/aspnet/core/migration/22-to-30?view=aspnetcore-5.0&tabs=visual-studio#authorization

You need to add the following if it's not already there:

services.UseAuthentication(); // with authentication scheme
app.UseAuthentication();
app.UseAuthorization(); // this is enough, because DefaultPolicy is to require authentication

and to the Endpoint middleware:

endpoints.MapControllers().RequireAuthorization();

An example with JWT authentication scheme:

public void ConfigureServices(IServiceCollection services)
{
    services.AddControllers();
    services.AddAuthentication(JwtBearerDefaults.AuthenticationScheme).AddJwtBearer(options =>
    {
        options.RequireHttpsMetadata = false;
        options.SaveToken = true;
        options.TokenValidationParameters = new TokenValidationParameters()
        {
            ValidateIssuer = true,
            ValidIssuer = Configuration["Jwt:Issuer"],
            ValidateAudience = false,
            ValidateIssuerSigningKey = true,
            IssuerSigningKey = new SymmetricSecurityKey(Encoding.UTF8.GetBytes(Configuration["Jwt:Key"]))
         };

    });
}
   

public void Configure(IApplicationBuilder app)
{
    app.UseRouting();
    
    app.UseAuthentication();
    
    app.UseAuthorization();
    
    app.UseEndpoints(endpoints =>
    {
        endpoints.MapControllers().RequireAuthorization();
    });
}

You can still allow anonymous access with [AllowAnonymous] on a controller or action (eg. for user login).

Solution 5

I just wanted to add something to other answers that if you use

 filters.Add(container.Resolve<AuthorizeAttribute>());

then you can also inject all dependencies into your attribute if there is a need

Share:
28,281
amcdnl
Author by

amcdnl

obsessed with the web / security / tech follow me on github or twitter: @amcdnl

Updated on August 06, 2022

Comments

  • amcdnl
    amcdnl over 1 year

    My application is setup where all requests except login must be 'authorized' using the authorization attribute in Web API. E.g.

     [Authorize]
     [HttpGet, Route("api/account/profile")]
     public ApplicationUser Profile()
     {
           return userModel;
     }
    

    and only the login needs to not authorize since thats where you get the token ;)

    [AllowAnonymous]
    [HttpPost, Route("api/account/login")]
    public async Task<IHttpActionResult> Login(LoginViewModel model)
    {
       ....
    }
    

    instead of having to add the [Authorize] attribute to ALL my routes, is there a way to set it globally?

  • ilans
    ilans almost 9 years
    I'd also recommend to put this inside a #if !DEBUG #endif block, so this could ease debugging without the need for authorization.
  • Piero Alberto
    Piero Alberto over 4 years
    I did this, but now I get ALWAYS 401, sure I'm missing something... what else I need to add?
  • Balagurunathan Marimuthu
    Balagurunathan Marimuthu about 3 years
    Side-note: recent version of .net core api, need to add Policy for AuthorizeAttribute as Matt Frear answered below.