Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
908 views
in Technique[技术] by (71.8m points)

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

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

1)     AuthorizationFilters

2)     Action Filters

3)     DelegatingHandler

The most obvious one is AuthorizationFilters , where I can decorate my actions/ controllers with my custom authorization attribute . say .. MyCustomAuthorizationAttribute .

Since HTTP message handlers are in the first stage in the processing pipeline. Does it make any sense to put it in there ?

Authorization for me right now simply means checking a token in the header which is given to the client after authentication.

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

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)
            );

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

2.1m questions

2.1m answers

60 comments

57.0k users

...