49 votes

API Web OData Sécurité par entité

Arrière-plan:
J'ai une très grande OData modèle qui est en train d'utiliser des Services de Données WCF (OData) pour l'exposer. Cependant, Microsoft a déclaré que les Services de Données WCF est morte et que l'API Web OData est la façon dont ils vont.

Donc, je suis à la recherche de façons d'obtenir de l'API Web OData pour le travail ainsi que les Services de Données WCF.

Problème D'Installation:
Certaines parties du modèle n'ont pas besoin d'être sécurisé, mais certains le font. Par exemple, la liste de Clients a besoin de sécurité permettant de limiter le lire, mais j'ai d'autres listes, comme la liste des Produits, que chacun peut consulter.

Les Clients de l'entité a de nombreuses de nombreuses associations qui peuvent l'atteindre. Si vous comptez 2+ niveau des associations, ce sont plusieurs centaines de façons que les Clients peuvent être atteint (à travers les associations). Par exemple Prodcuts.First().Orders.First().Customer. Étant donné que les Clients sont au cœur de mon système, vous pouvez commencer avec n'importe quelle entité et, éventuellement associé à votre façon à la liste de Clients.

Les Services de Données WCF a une façon pour moi de mettre la sécurité sur une entité spécifique, par l'intermédiaire d'une méthode comme ceci:

[QueryInterceptor("Customers")]
public Expression<Func<Customer, bool>> CheckCustomerAccess()
{
     return DoesCurrentUserHaveAccessToCustomers();
}

Comme je regarde l'API Web OData, je ne suis pas le voir quelque chose comme cela. En Plus je suis très inquiet parce que les contrôleurs que je fais ne semblent pas être appelé lorsqu'une association est suivie. (Ce qui signifie que je ne peux pas mettre de sécurité dans l' CustomersController.)

Je suis inquiet que je vais avoir essayer en quelque sorte énumérer toutes les façons que les associations peuvent certains de la façon de faire pour les clients et les mettre à la sécurité de chacun.

Question:
Est-il un moyen de mettre la sécurité sur une entité spécifique à l'API Web OData? (Sans avoir à énumérer toutes les associations qui pourraient en quelque sorte développer jusqu'à cette entité?)

46voto

SKleanthous Points 1440

Ce que vous devez faire est de créer un nouvel Attribut héritant de EnableQueryAttribute pour OData 4 (ou QuerableAttribute selon la version de l'API Web\OData à qui vous parlez) et remplacer la ValidateQuery (c'est la même méthode que lors de l'héritage de QuerableAttribute) pour vérifier l'existence d'un SelectExpand attribut.

Installation d'un nouveau projet pour tester cette procédez de la manière suivante:

  1. Créer un nouveau ASP.Net projet avec l'API Web 2
  2. Créez votre entité cadre de contexte de données.
  3. Ajouter un nouveau "Web API 2 OData Contrôleur de ..." contrôleur.
  4. Dans le WebApiConfigRegister(...) la méthode ajouter le ci-dessous:

Code:

ODataConventionModelBuilder builder = new ODataConventionModelBuilder();

builder.EntitySet<Customer>("Customers");
builder.EntitySet<Order>("Orders");
builder.EntitySet<OrderDetail>("OrderDetails");

config.Routes.MapODataServiceRoute("odata", "odata", builder.GetEdmModel());

//config.AddODataQueryFilter();
config.AddODataQueryFilter(new SecureAccessAttribute());

Ci-dessus, le Client, l'Ordre et la OrderDetail sont mes entity framework entités. Le fichier de configuration.AddODataQueryFilter(nouveau SecureAccessAttribute()) enregistre mon SecureAccessAttribute pour les utiliser.

  1. SecureAccessAttribute est mis en œuvre comme ci-dessous:

Code:

public class SecureAccessAttribute : EnableQueryAttribute
{
    public override void ValidateQuery(HttpRequestMessage request, ODataQueryOptions queryOptions)
    {
        if(queryOptions.SelectExpand != null
            && queryOptions.SelectExpand.RawExpand != null
            && queryOptions.SelectExpand.RawExpand.Contains("Orders"))
        {
            //Check here if user is allowed to view orders.
            throw new InvalidOperationException();
        }

        base.ValidateQuery(request, queryOptions);
    }
}

Veuillez noter que je autoriser l'accès pour les Clients de contrôleur, mais j'ai limite l'accès aux Commandes. La seule commande que j'ai mis en place est celui ci-dessous:

public class CustomersController : ODataController
{
    private Entities db = new Entities();

    [SecureAccess(MaxExpansionDepth=2)]
    public IQueryable<Customer> GetCustomers()
    {
        return db.Customers;
    }

    // GET: odata/Customers(5)
    [EnableQuery]
    public SingleResult<Customer> GetCustomer([FromODataUri] int key)
    {
        return SingleResult.Create(db.Customers.Where(customer => customer.Id == key));
    }
}
  1. Appliquer l'attribut dans TOUTES les actions que vous souhaitez sécuriser. Il fonctionne exactement comme le EnableQueryAttribute. Un exemple complet (y compris les packages Nuget fin de tout, ce qui en fait un 50 mo à télécharger) peut être trouvé ici: http://1drv.ms/1zRmmVj

Je veux juste commenter un peu sur certains autres solutions:

  1. Leyenda de la solution ne fonctionne pas tout simplement parce que c'est l'inverse, mais dans le cas contraire était super proche!!!! La vérité est que le constructeur dans le cadre de l'entité d'étendre les propriétés et ne sera pas frapper les Clients contrôleur à tous! Je n'ai même pas un, et si vous supprimez l'attribut de sécurité, il sera toujours récupérer les commandes très bien si vous ajoutez la commande expand à votre requête.
  2. Fixant le modèle générateur d'interdire l'accès aux entités vous avez supprimé à l'échelle mondiale et de tout le monde, de sorte qu'il n'est pas une bonne solution.
  3. Feng Zhao solution pourrait fonctionner, mais vous devez supprimer manuellement les éléments que vous avez voulu assurer dans chaque requête, partout, ce qui n'est pas une bonne solution.

18voto

Vaccano Points 18515

J'ai eu cette réponse quand j'ai demandé de l'API du Web OData équipe. Il semble très similaire à la réponse que j'ai accepté, mais il utilise un IAuthorizationFilter.

Dans l'intérêt de l'exhaustivité j'ai pensé que je pourrais le poster ici:


Pour l'ensemble entité ou à une propriété de navigation apparaît dans le chemin, nous pourrions définir un gestionnaire de message ou de l'autorisation de filtre, et de vérifier que l'entité cible définie demandé par l'utilisateur. E. g., quelques extrait de code:

public class CustomAuthorizationFilter : IAuthorizationFilter
{
    public bool AllowMultiple { get { return false; } }

    public Task<HttpResponseMessage> ExecuteAuthorizationFilterAsync(
        HttpActionContext actionContext,
        CancellationToken cancellationToken,
        Func<Task<HttpResponseMessage>> continuation)
    {
        // check the auth
        var request = actionContext.Request;
        var odataPath = request.ODataProperties().Path;
        if (odataPath != null && odataPath.NavigationSource != null &&
            odataPath.NavigationSource.Name == "Products")
        {
            // only allow admin access
            IEnumerable<string> users;
            request.Headers.TryGetValues("user", out users);
            if (users == null || users.FirstOrDefault() != "admin")
            {
                throw new HttpResponseException(HttpStatusCode.Unauthorized);
            }
        }

        return continuation();
    }
}

public static class WebApiConfig
{
    public static void Register(HttpConfiguration config)
    {
        config.Filters.Add(new CustomAuthorizationFilter());

Pour $étendre l'autorisation option de requête, un échantillon.

Ou à créer par l'utilisateur ou par groupe edm modèle. Un échantillon.

1voto

phish_bulb Points 11

Vous pouvez supprimer certaines propriétés de l'EDM par programme:

 var employees = modelBuilder.EntitySet<Employee>("Employees");
employees.EntityType.Ignore(emp => emp.Salary);
 

de http://www.asp.net/web-api/overview/odata-support-in-aspnet-web-api/odata-security-guidance

0voto

kidshaw Points 1700

Serait-il possible de déplacer ce à votre base de données? En supposant que vous êtes à l'aide de SQL server, de définir les utilisateurs qui correspondent aux profils dont vous avez besoin pour chaque profil de client. Garder les choses simples, un compte avec un accès client et l'autre sans.

Si vous puis la carte à l'utilisateur de faire une demande de données à l'un de ces profils et de modifier la chaîne de connexion contiennent des informations d'identification. Alors si ils font une demande à une entité qu'ils ne sont pas autorisés à, ils recevront une exception.

Tout d'abord, désolé si c'est une mauvaise compréhension du problème. Même si je dis ça, je peux voir un certain nombre de pièges plus immédiate étant les données supplémentaires de contrôle d'accès et d'entretien à l'intérieur de votre base de données.

Aussi, je me demandais si quelque chose peut être fait dans le modèle T4 qui génère votre modèle d'entité. Lorsque l'association est défini, il peut être possible d'injecter une dose d'autorisation de contrôle. Encore une fois ce serait placer la commande dans un calque différent - je viens juste de le mettre dans cas quelqu'un qui sait T4 mieux que moi peut voir une façon de faire ce travail.

-2voto

Leyenda Points 33

Vous pouvez définir votre propre attribut Queryable sur Customers.Get () ou selon la méthode utilisée pour accéder à l'entité Customers (directement ou par le biais d'une propriété de navigation). Dans l'implémentation de votre attribut, vous pouvez remplacer la méthode ValidateQuery pour vérifier les droits d'accès, comme ceci:

 public class MyQueryableAttribute : QueryableAttribute
{
    public override void ValidateQuery(HttpRequestMessage request, 
    ODataQueryOptions queryOptions)
    {
        if (!DoesCurrentUserHaveAccessToCustomers)
        {
            throw new ODataException("User cannot access Customer data");
        }

        base.ValidateQuery(request, queryOptions);
    }
}
 

Je ne sais pas pourquoi votre contrôleur n'est pas appelé dans les propriétés de navigation. CA devrait etre...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X