Where should I plugin the Authorization in Asp.net WebAPI?

前端 未结 1 1641
无人及你
无人及你 2020-12-12 18:33

As I see I have 3 possible places to plug my stuff in the pipeline

1)     AuthorizationFilters

2)     Action Filters

3)     DelegatingHandler
相关标签:
1条回答
  • 2020-12-12 18:54

    Update July 2014

    My original answer covered WebApi 1. with WebApi 2 there were some changes i.e. there is now an IAuthenticationFilter meaning you can move authentication logic out of the DelegatingHandler which is a little more elegant.

    There is a Nuget project here that offers an implementation of IAuthenticationFilter and also explains some background to its introduction.

    OWIN middleware is now perhaps the best place to implement your authentication logic - there is an example of Certificate Authentication here and Basic Authentication OWIN Middleware here in this blog post the former example is the preferred one as it demonstrates the use of the base AuthenticationHandler class.

    The advice on AuthorizationFilters remains largely unchanged.

    End Update

    Typically...

    Use DelegatingHandler to carry out Authentication... i.e. who someone is. Use this to set the Principle of the Thread and User context, add claims etc. You can place authorisation logic here too but on a fairly global scale. I would personally always use AuthorizationFilters for authorisation.

    Use AuthorizationFilters to restrict controllers and actions to specific people. These are used when you can extrapolate their permission with the information in claims, principal, url or the http request parameters. The default authorisation filter can be used to restrict access to anonymous users or by roles (if set in something like a delegating handler) - obviously you can implement your own AuthorizationFilters too if you need it.

    Occasionally use ActionFilters when you need to make the decision over authorisation using the message content e.g. you need access to a property on the entity to decide whether they have access (obviously be careful with this(!)).

    Note:

    The AuthorizationFilters are called before the content of the body is read therefore they do not have access to the message body to make authorization decisions this is why the ActionFilters specifically the OnActionExecuting is used to occasional raise authentication errors.

    So

    In your scenario I would put a simple DelegatingHandler to take your header and set the principal.

    public class CustomAuthenticationMessageHandler : DelegatingHandler
    {
    
    
        public CustomAuthenticationMessageHandler ()
        {
    
        }
    
        protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request,
                                                               CancellationToken cancellationToken)
        {
            Authenticate(request);
    
            return base.SendAsync(request, cancellationToken);
        }
    
        protected virtual void Authenticate(HttpRequestMessage request)
        {
    
            var authorisationHeader = request.Headers.Authorization;
    
            if (authorisationHeader == null)
            {
                return;
            }
    
            //Ensure you are happy with the header contents then
    
            {
                var principal = new GenericPrincipal(//new Identity , //Roles);
                Thread.CurrentPrincipal = principal;
                HttpContext.Current.User = principal;
            }
    
        }
    }
    

    Then use AuthorizationFilters to restrict access:

        [Authorize]
        public string Get()
        {
    
        }
    
        [Authorize(Roles = "Admin")]
        public string GetAdminOnly()
        {
    
        }
    

    To register the global Authentication

    config.MessageHandlers.Add(new CustomAuthenticationMessageHandler());
    

    This will mean that in every request the principal will be set to either null or a valid identity. It won't handle authorisation i.e. wont deny access to any controllers or actions.

    To start protecting resources

    Either target protected controllers and actions with the standard or custom [Authorize] attributes. Or register globally:

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

    And only white list the controllers and actions you want unsecured using the [AllowAnonymous] attribute.

    If you only want authentication on some routes

    Then you can modify your DelegatingHandler a little to set the InnerHandler to route to the correct controller e.g.

    public CustomAuthenticationMessageHandler(HttpConfiguration configuration)
    {
           InnerHandler = new HttpRoutingDispatcher(configuration);
    }
    

    And then you can specify this handler on your routes like so:

    config.Routes.MapHttpRoute(
                name: "DefaultApi",
                routeTemplate: "myurl",
                defaults: new {},
                constraints: new {},
                handler: new CustomAuthenticationHandler(config)
                );
    
    0 讨论(0)
提交回复
热议问题