.NET WebAPI centralized Authorization

2019-02-27 14:53发布

问题:

In .NET WebAPI, I've created a way to have all of the authorization rules in a central location, rather than scattered throughout controllers. I'm curious why this centralization isn't done more often; are there repercussions/security concerns?

My current approach is to create a Dictionary during App_Start that contains all of my Authorization data then using a DelegatingHandler to apply the restrictions (code below). The dictionary key is a Tuple of the Controller and Action, and the value is the authorized roles. The DelegatingHandler ties into WebAPI's routing config to get which controller is called, then uses the Dictionary to determine whether the request is allowed.

Dictionary:

var authorizations = new Dictionary<Tuple<string, string>, string>();
authorizations.Add(new Tuple<string, string>("values", "get"), "public");
authorizations.Add(new Tuple<string, string>("values", "put"), "private");

DelegatingHandler:

public class SecurityDelegateHandler : DelegatingHandler
{
    private readonly Dictionary<Tuple<string, string>, string> _authorizations;

    public SecurityDelegateHandler(Dictionary<Tuple<string, string>, string> auth)
    {
        _authorizations = auth;
    }

    protected override Task<HttpResponseMessage> SendAsync(HttpRequestMessage request, CancellationToken cancellationToken)
    {
        var config = GlobalConfiguration.Configuration;
        var controllerSelector = new DefaultHttpControllerSelector(config);
        var descriptor = controllerSelector.SelectController(request);

        string restrictions;

        if (!_authorizations.TryGetValue(
                new Tuple<string, string>(descriptor.ControllerName.ToLower(),
                request.Method.ToString().ToLower()), out restrictions))
        {
            return Task<HttpResponseMessage>.Factory.StartNew(() =>
                        request.CreateResponse(HttpStatusCode.Forbidden, 
                        "Access denied on unconfigured actions"), 
                        cancellationToken);
        }

        if (!(Roles.Provider).GetRolesForUser(
               HttpContext.Current.User.Identity.Name).Any(r => 
               restrictions.Contains(r)))
        {
            return Task<HttpResponseMessage>.Factory.StartNew(() => 
                        request.CreateResponse(HttpStatusCode.Forbidden, 
                        "Access Denied"), cancellationToken);
        }

        return base.SendAsync(request, cancellationToken);
    }
}

In summary, my questions are:

  • Are there any problems with implementing Role Based Authorization in this way?
  • Are there any good packages out there that handle centralizing authorization for WebAPI? I've looked into FluentSecurity, but that doesn't appear to support WebAPI.

Thanks!

回答1:

Your approach is a good one. You should separate concerns. This means separating business logic from non-functional logic/requirements (e.g. logging, authentication, and of course authorization).

The reason why this hasn't been done more broadly is because it's much easier to externalize authentication or logging than it is to externalize authorization which is more related to your business.

Different programming frameworks provide externalized authorization today. Microsoft has claims-based authorization, Java has several frameworks e.g. Spring Security, SunXACML... PHP has Yii, Ruby has CanCan... These frameworks let you implement role-based access control and even attribute-based access control. If you're not familiar with these terms, check out NIST's webpage:

  • NIST RBAC
  • NIST ABAC

If you want a solution that is technology-neutral, i.e. something you can use for Java, .NET, PHP... you can use XACML, the eXtensible Access Control Markup Language. It's an OASIS standard just like SAML is (SAML focuses on federated id and SSO; XACML focuses on fine-grained authorization). You can read more on XACML on the OASIS website and on Wikipedia where I try to maintain the page. In addition to externalizing authorization, XACML also defines a policy-based approach to authorization which makes a very scalable approach.

There are several open source options (JBoss, SunXACML, OpenAM...) for XACML as well as vendors such as the one I work for, Axiomatics.

HTH