Ce site utilise des cookies pour l'analyse, ainsi pour que les contenus et les publicités personnalisés. En continuant à naviguer sur ce site, vous acceptez cette utilisation. En savoir plus
Microsoft Logo
Gray Pipe
  • Developer Network
    • Téléchargements
      • Visual Studio
      • Kits de développement logiciel (SDK)
      • Logiciels d'évaluation
    • Programmes
      • Abonnements
      • Étudiants
      • ISV
      • Startups
      • Événements
    • Communauté
      • Magazine
      • Forums
      • Blogs
      • Channel 9
    • Documentation
      • API et référence
      • Centres de développement
      • Exemples
      • Retirelanding
Developer Network Developer
Abonnements MSDN
Obtenir des outils
magazine
  • Publications et téléchargements
    • Toutes les publications
    • 2018
      • Avril 2018
      • Mars 2018
      • Février 2018
      • Janvier 2018
    • 2017
      • Décembre 2017
      • Novembre 2017
      • Octobre 2017
      • Septembre 2017
      • Août 2017
      • Juin 2017
      • Mai 2017
      • Avril 2017
      • Mars 2017
      • Février 2017
      • Janvier 2017
    • 2016
      • Décembre 2016
      • Connect(); 2016
      • Novembre 2016
      • Octobre 2016
      • Septembre 2016
      • Août 2016
      • Juillet 2016
      • Juin 2016
      • Mai 2016
      • Avril 2016
      • Mars 2016
      • Février 2016
      • Janvier 2016
    • 2015
      • Décembre 2015
      • Novembre 2015
      • RUBRIQUE SPÉCIALE SUR WINDOWS 10 2015
      • Octobre 2015
      • Septembre 2015
      • Août 2015
      • Juillet 2015
      • Juin 2015
      • Mai 2015
      • Avril 2015
      • Mars 2015
      • Février 2015
      • Janvier 2015
    • 2014
      • MSDN Magazine Special 2014 Issue
      • MSDN Magazine Décembre 2014
      • MSDN Magazine Novembre 2014
      • MSDN Magazine Octobre 2014
      • MSDN Magazine Septembre 2014
      • MSDN Magazine Août 2014
      • MSDN Magazine Juillet 2014
      • MSDN Magazine Juin 2014
      • MSDN Magazine Mai 2014
      • MSDN Magazine Avril 2014
      • MSDN Magazine Mars 2014
      • MSDN Magazine février 2014
      • MSDN Magazine Janvier 2014
    • 2013
      • MSDN Magazine Décembre 2013
      • MSDN Magazine Novembre 2013
      • MSDN Magazine Octobre 2013
      • MSDN Magazine Septembre 2013
      • MSDN Magazine Août 2013
      • MSDN Magazine Juillet 2013
      • MSDN Magazine Juin 2013
      • MSDN Magazine Mai 2013
      • MSDN Magazine Avril 2013
      • MSDN Magazine Mars 2013
      • MSDN Magazine Février 2013
      • MSDN Magazine Janvier 2013
    • 2012
      • MSDN Magazine Décembre 2012
      • MSDN Magazine Novembre 2012
      • MSDN Magazine Octobre 2012
      • MSDN Magazine Édition spéciale Windows 8 2012
      • MSDN Magazine Septembre 2012
      • MSDN Magazine Août 2012
      • MSDN Magazine Juillet 2012
      • MSDN Magazine Juin 2012
      • MSDN Magazine Mai 2012
      • MSDN Magazine Avril 2012
      • MSDN Magazine Mars 2012
      • MSDN Magazine Février 2012
      • MSDN Magazine Janvier 2012
    • 2011
      • MSDN Magazine Décembre 2011
      • MSDN Magazine Novembre 2011
      • MSDN Magazine Octobre 2011
      • MSDN Magazine Septembre 2011
      • MSDN Magazine Août 2011
      • MSDN Magazine Juillet 2011
      • MSDN Magazine Juin 2011
      • MSDN Magazine Mai 2011
      • MSDN Magazine Avril 2011
      • MSDN Magazine Mars 2011
      • MSDN Magazine Février 2011
      • MSDN Magazine Janvier 2011
    • 2010
      • MSDN Magazine Décembre 2010
      • MSDN Magazine Novembre 2010
      • MSDN Magazine Octobre 2010
      • MSDN Magazine Septembre 2010
      • MSDN Magazine Août 2010
      • MSDN Magazine Juillet 2010
      • MSDN Magazine Juin 2010
      • MSDN Magazine Mai 2010
      • MSDN Magazine Avril 2010
      • MSDN Magazine Mars 2010
      • MSDN Magazine Février 2010
      • MSDN Magazine Janvier 2010
    • 2009
      • MSDN Magazine Décembre 2009
      • MSDN Magazine Novembre 2009
      • MSDN Magazine Octobre 2009
      • MSDN Magazine Septembre 2009
      • MSDN Magazine Août 2009
      • MSDN Magazine Juillet 2009
      • MSDN Magazine Juin 2009
      • MSDN Magazine Mai 2009
      • MSDN Magazine Avril 2009
      • MSDN Magazine Mars 2009
      • MSDN Magazine Février 2009
      • MSDN Magazine Janvier 2009
  • Subscribe
  • Soumettre un article
search clear
Nous sommes désolés. Le contenu que vous avez demandé a été supprimé. Vous allez être automatiquement redirigé dans 1 seconde.
Publications et téléchargements 2012 MSDN Magazine Octobre 2012 OData: OData, Entity Framework et Windows Azure Access Control

OData

OData, Entity Framework et Access Control (ACS) de Windows Azure

Sean Iannuzzi

Télécharger l'exemple de code

Dans cet article, je vais vous montrer comment implémenter Open Data Protocol (OData) avec Entity Framework étant exposé avec les services Windows Communication Foundation (WCF) RESTful et sécurisé avec le service Access Control (ACS) de Windows Azure.

Comme la plupart des développeurs, il m'arrive souvent d'essayer d'utiliser une combinaison de technologies de manières nouvelles et variées pour réaliser mon projet aussi efficacement que possible tout en apportant une solution souple et facile à gérer. Cet objectif peut être difficile à atteindre, notamment lorsque le projet nécessite des données à exposer rapidement et en toute sécurité.

J'ai été invité récemment à créer un service Web sécurisé pour une application de base de données et Web existante. Je ne voulais vraiment pas implémenter l'ensemble du code CRUD (Create, Read, Update, Delete – Créer, Lire, Mettre à jour, Supprimer). J'étais très tenté de ne créer que des contrats de service personnalisés, des contrats d'opération et des contrats de données afin de régir avec précision le mode d'exposition et de consommation des données via les services. Mais je savais qu'il y avait une voie plus avantageuse à suivre. J'ai commencé à rechercher les diverses manières dont je disposais pour réaliser mon objectif et ai jugé qu'il existait un potentiel avec OData (ou « Oh ! Data », comme je me plais à l'appeler). Le problème était qu'OData en lui-même n'était pas sécurisé de manière acceptable, selon moi. J'ai eu besoin d'ajouter une couche de sécurité supplémentaire au-dessus du service OData afin de m'assurer qu'il serait sécurisé correctement. Comme je commençais à assembler le tout, j'ai découvert ACS, qui est idéal pour implémenter une authentification fédérée et un service d'autorisation basés sur le cloud. C'était exactement ce dont j'avais besoin. Puis la révélation est arrivée. Je me suis rendu compte que j'obtenais la solution que je voulais en connectant ACS à OData.

Or, j'ai pensé à implémenter des contrats de service personnalisés, et il y a une place pour cette approche, notamment lorsqu'une couche d'abstraction est nécessaire devant un modèle de données et qu'elle doit protéger les entités de base de données contre une exposition directe aux utilisateurs d'un service. Toutefois, étant donné le temps que prend la création d'un document approprié sur le mode de consommation du service et son ajout aux tâches supplémentaires nécessaires à la configuration de la sécurité, (« MessageCredential » et « TransportWithMessageCredentials »), le projet peut rapidement devenir incontrôlable. Je m'inquiétais aussi du fait que des méthodes supplémentaires seraient nécessaires ou demandées, pour une raison ou une autre, afin de prendre en charge le mode d'utilisation des services, lesquels, à leur tour, nécessiteraient davantage de temps, de maintenance et de personnalisation. Même si l'implémentation du service utilisait directement Entity Framework au lieu d'ADO.NET, il pouvait encore être nécessaire de créer l'ensemble du code pour conserver la synchronisation de la couche de données. Étant donné la présence de quelques dizaines de tables, cette tâche pouvait être extrêmement pénible. De plus, la création et la mise à jour d'autres informations de documentation et d'implémentation nécessaires aux utilisateurs finaux pour utiliser mon service rendaient cette proposition beaucoup plus compliquée à gérer.

Un moyen plus simple

Après avoir identifié les technologies principales, j'ai cherché d'autres technologies pour combler les lacunes et créer une solution cohésive. L'objectif consistait à limiter la quantité de code nécessaire devant être écrite ou mise à jour, tout en activant en toute sécurité mes services OData WCF RESTful. Les technologies que j'ai associées sont les suivantes : ACS, OData, les modèles de données d'entité, les services de données WCF avec les autorisations d'entité et une implémentation de sécurité Windows Azure personnalisée. Chacune de ces technologies fournit déjà une valeur significative par elle-même, mais lorsque ces technologies sont combinées, leur valeur augmente de manière exponentielle. La Figure 1 montre une vue d'ensemble de la façon dont ces technologies fonctionneront lorsqu'elles seront implémentées.


Figure 1 Vue d'ensemble d'ACS avec une interception de sécurité

Avant de tenter de combiner toutes ces technologies, j'ai dû prendre du recul, bien comprendre chacune d'entre elles et la manière dont elles pouvaient influencer ce projet. Grâce à cette compréhension, j'ai pu déterminer comment les combiner et quels étaient les éléments nécessaires aux utilisateurs d'autres technologies pour consommer mes services.

Qu'est-ce qu'ACS ?

ACS est fourni sous la forme d'un composant de la plateforme Windows Azure. ACS me permet de configurer mon propre fournisseur basé sur le cloud pour les authentifications et autorisations fédérées. Je l'utilise pour sécuriser mes services OData WCF, mais il peut aussi servir à sécuriser une application. ACS est un service basé sur le cloud qui aide à combler la lacune de sécurité lorsqu'il est nécessaire d'implémenter une connexion unique (SSO) dans plusieurs applications, services ou produits prenant en charge diverses implémentations SSO multi-plateformes ou multi-domaines. Un compte Windows Azure permet d'accéder à beaucoup plus d'informations. Vous pouvez vous inscrire à une évaluation gratuite sur le site windowsazure.com. Pour en savoir plus sur ACS, consultez bit.ly/zLpIbw.

Qu'est-ce qu'OData et à quoi sert-il ?

OData est un protocole Web qui sert à interroger les données, à les mettre à jour, ainsi qu'à les exposer à l'aide d'une syntaxe normalisée. OData tire parti de technologies telles que HTTP, XML, JSON et Atom Publishing Protocol pour fournir un accès différent aux données. L'implémentation d'OData avec Entity Framework et les services de données WCF offre un grand nombre d'avantages intéressants.

J'ai commencé à me demander pourquoi je ne l'utiliserais pas à la place des contrats WCF personnalisés. La réponse a été très simple. La raison la plus pratique était l'utilisation de la documentation du service déjà disponible et d'une syntaxe normalisée prenant en charge le mode d'accès aux données depuis le service. Comme j'ai écrit des dizaines de services, j'ai l'impression d'avoir toujours besoin d'ajouter une autre méthode après avoir fourni des services personnalisés. De plus, les utilisateurs de services personnalisés ont tendance à demander de plus en plus de fonctionnalités.

 Pour plus d’informations sur OData et les conventions de l'URI pour OData, consultez les sites suivants :

  • Site principal OData : odata.org
  • Conventions de l'URI pour OData : bit.ly/NRalFb
  • Exemple de service OData de Netflix : bit.ly/9UZjRd

OData avec Entity Framework et les services de données WCF

L'utilisation d'OData avec les services de données WCF et Entity Framework expose les fonctionnalités standard pour prendre en charge la récupération et l'enregistrement des données grâce à une méthode déjà documentée avec peu de code d'implémentation. Lorsque j'ai commencé à créer mon modèle de données d'entité pour le format EDMX (Data Services Packaging Format) et que je l'ai lié à mon service WCF via les services de données, j'étais très sceptique. Mais cela a fonctionné parfaitement. Toutes les entités que j'avais incluses dans mon EDMX ont été automatiquement incluses et exposées dans mon service dans une implémentation RESTful. La figure 2 montre un exemple de code.

Figure 2. Implémentation des services de données OData WCF

C#
Copier
using System.Data.Services;
using System.Data.Services.Common;
namespace WCFDataServiceExample
{
  public class NorthwindService : DataService<NorthwindEntities>
  {
    // This method is called only once to initialize service-wide policies.
    public static void InitializeService(DataServiceConfiguration config)
    {
      // Give full access to all of the entities.
      config.SetEntitySetAccessRule("*", EntitySetRights.All);
      // Page size will change the max number of rows returned.
      config.SetEntitySetPageSize("*", 25);
      config.DataServiceBehavior.MaxProtocolVersion =
        DataServiceProtocolVersion.V2;
    }
  }
}

J'ai créé un EDMX et l'ai lié à quelques tables de ma base de données (Northwind Sample Database). J'ai ensuite lié mes entités de base de données à mon service de données WCF et exposé toutes les entités en utilisant la méthode « SetEntitySetAccessRule » avec un attribut caractère générique * pour désigner toutes les entités. Cela m'a permis de définir diverses autorisations sur mes entités pour l'accès en lecture, écriture et interrogation, ainsi que pour la définition de la taille de page, comme le montre la figure 2. Le code montré est l'implémentation intégrale du code des services de données OData WCF.

Les contrats de service, d'opération et de données sont contrôlés principalement via la configuration dans l'initialisation du service fourni. Dans la méthode d'initialisation, je peux définir diverses autorisations correspondant à la façon dont j'aimerais exposer mes entités et le niveau d'accès que j'aimerais fournir à ceux qui cherchent à utiliser mes services. Je pourrais même utiliser des modèles T4 pour créer une couche abstraite ou une couche de modèle au-dessus des entités avec des noms d'entité personnalisés. Cela rendrait les choses plus claires pour l'utilisateur de mes services. Je pourrais même définir les autorisations pour une table spécifique, ou je pourrais définir le nom de table avec les paramètres de sécurité appropriés pour une protection même moindre. Voici un exemple d'attribution d'un accès en lecture à la table Customer (Client) :

C#
Copier
config.SetEntitySetAccessRule("Customer",
  EntitySetRights.AllRead);

Beaucoup d'implémentations de sécurité diverses peuvent être activées avec OData et les services de données WCF, mais, pour le moment, je me préoccupe seulement de savoir comment protéger mes services WCF avec ACS associé avec les règles d'accès du service de données.

La figure 3 présente une liste rapide des technologies utilisées et des raisons pour lesquelles ces technologies peuvent être utilisées.

Figure 3. Technologies utilisées et raisons de leur emploi

TechnologieRaison de l'utiliser
ACSPermet de sécuriser les services à l'aide d'un module de sécurité fédéré basé sur le cloud pour l'authentification et l'autorisation
ODataFournit une syntaxe standard pour interroger et mettre à jour les données tout en exploitant des technologies courantes telles que HTTP, JSON, Atom Publishing Protocol et XML.
Modèles de données d'entitéPermettent de créer rapidement un accès aux données courantes pour un niveau de base de données tout en fournissant également des contrats de données de tables sérialisables dans une base de données
Services de données WCF avec autorisations d'entitéExposent le contrat de données Entity Framework avec le niveau d'autorisations approprié pour CRUD sous la forme d'un service WCF RESTful
Implémentation de sécurité Windows Azure personnaliséeProtège les services (ici les services OData) pour les empêcher d'être utilisés sans que le niveau de sécurité approprié, par exemple un jeton ou un certificat, ne leur soit appliqué.

Chacune de ces technologies s'accompagne toujours de compromis basés sur le projet, mais j'ai découvert que les combiner permettait d'économiser du temps dans la configuration initiale et de réduire les tâches de maintenance, tout en demandant moins de temps et en apportant des gains colossaux, notamment lorsque j'avais besoin d'exposer mes données en toute sécurité et de fournir des méthodes d'accès aux données courantes avec une syntaxe normalisée.

En résumé

Avec une assez bonne compréhension de l'utilisation combinée d'OData, d'Entity Framework et des services de données WCF, j'ai pu appliquer d'autres fonctionnalités de sécurité à cette technologie en exploitant ACS. Quelques options se présentaient pour protéger mon service contre les accès, notamment la définition de diverses autorisations sur les entités ou l'ajout d'intercepteurs de requête pour empêcher l'utilisation des services ou contrôler comment mon service pouvait être utilisé.

Toutefois, l'implémentation d'intercepteurs de requête ou la définition d'autorisations aurait été pénible et l'ajout d'une couche de sécurité au-dessus de mon service pour l'empêcher d'être utilisé a été préféré à l'écriture de code supplémentaire. Il serait idéal d'implémenter un mécanisme de sécurité courant permettant aux parties de confiance ou aux sociétés externes d'accéder à mes services. Ensuite, je pourrais utiliser une combinaison de cette sécurité de même qu'une protection d'entité pour offrir à mes services l'implémentation la mieux sécurisée et présentant la meilleure flexibilité.

L'utilisation de cette approche nécessiterait que les consommateurs de mon service commencent par s'authentifier via ACS et obtiennent un jeton d'accès valide. Sans ce jeton d'accès, les services seraient limités. Des jetons d'accès valides seraient nécessaires dans l'en-tête de demande pour permettre l'accès à mon service. Après que l'utilisateur de mon service ait reçu son autorisation, j'appliquerais une sécurité précise sur les entités pour n'établir qu'un accès autorisé aux données ou à mes entités.

Installation et configuration d'ACS

Des tâches d'installation et de configuration sont requises pour implémenter ACS. La figure 4 montre une liste des éléments que j'installe pour cet exemple.

Figure 4. Installation d'ACS

ConfigurationValeurs
Espace de noms ACSWCFoDataACS
Application de la partie qui répond

Nom : wcfodataacsexampleDevelopment

Mode : Conserver les valeurs par défaut (entrer les paramètres manuellement)

Domaine : http://localhost/WCFDataServiceExample/<nom du service>.svc

URL de retour : Conserver la valeur par défaut (vide)

URL d'erreur : Conserver la valeur par défaut (vide)

Format du jeton : SWT

Stratégie de chiffrement du jeton : Conserver la valeur par défaut (none)

Durée de vie du jeton : Conserver la valeur par défaut (600)

Paramètres d'authentification

Fournisseurs d'identité : Désactiver le Windows Live ID

Groupe de règles : Cliquer sur Créer un groupe de règles.

Remarque : j'ai créé différents paramètres pour le développement, les tests et la production.

Paramètres de signature des jetons

Cliquer sur le bouton Générer

Date d’entrée en vigueur : Conserver les valeurs par défaut

Date d’expiration : Conserver les valeurs par défaut

Groupe de règlesRemarque : Selon mes paramètres, le groupe de règles sera créé automatiquement, mais je dois encore ajouter la configuration des déclarations.
Configuration des réclamations

Section If :

Système de contrôle d'accès : Sélectionné

Type de la déclaration d'entrée : Conserver la valeur par défaut (any)

Valeur de la réclamation d'entrée : Conserver la valeur par défaut (any)

Section Then :

Type de la déclaration de sortie : Conserver la valeur par défaut (type de déclaration d'entrée relais)

Valeur de la déclaration de sortie : Conserver la valeur par défaut (valeur de la déclaration d'entrée relais)

Informations sur les règles :

Description : Conserver la valeur par défaut ou entrer une description

Identité de service dans Windows

Nom : le nom d'utilisateur à fournir aux autres (dans cet exemple, j'ai utilisé wcfodataacsDevUser)

Description : Conserver les valeurs par défaut (ou entrer une description pour l'utilisateur)

Domaine : http://localhost/WCFDataServiceExample/<nom du service>.svc

Paramètres des informations d'identification :

Type : Sélectionner le mot de passe

Mot de passe : Entrer le mot de passe voulu

Date d’entrée en vigueur : Conserver les valeurs par défaut

Date d’expiration : Conserver les valeurs par défaut

Remarque : Plusieurs options sont disponibles pour le mode d'authentification d'un utilisateur dans les services créés, mais, pour plus de commodité, j'ai utilisé une entrée de mot de passe comme type d'information d'identification. D'autres options sont disponibles, par exemple l'utilisation d'un certificat x509 ou d'une clé symétrique, qui peut assurer un niveau de sécurité supérieur, mais j'ai essayé d'utiliser une option de base pour cet exemple.

Après avoir installé ACS, j'ai pu sécuriser mes services OData WCF RESTful. Avant de pouvoir les sécuriser, j'ai d'abord dû implémenter un module de sécurité personnalisé pour intercepter les demandes et valider la sécurité pour empêcher les accès non autorisés.

Implémentation de la sécurité ACS

À titre d'exemple, j'ai implémenté la sécurité à l'aide d'un module HTTP personnalisé. Ce module intercepte les demandes effectuées à mon service et les valide si l'authentification et l'autorisation appropriées ont été obtenues. Sans ce module HTTP, mes services seraient sécurisés uniquement au niveau entité, en fonction des paramètres de la configuration du service de données.

Dans ce cas, j'ai sécurisé ces services avec ACS ; ainsi, les demandes ont été interceptées, puis le niveau de sécurité approprié a été recherché pour vérifier que l'utilisateur du service avait obtenu le niveau d'autorisation approprié. Comme indiqué précédemment, la sécurité affinée a pu être implémentée au niveau entité lorsque l'utilisateur du service a obtenu l'autorisation d'accès.

Lors de l'implémentation de l'interface IHTTPModule, j'ai choisi d'ajouter des fonctionnalités supplémentaires. J'ai donc exposé des parties des métadonnées du service afin de permettre aux utilisateurs du service de générer automatiquement des classes (comme pour l'ajout d'un autre service Web). J'ai ajouté ces sections de code sous la forme d'attributs configurables pouvant être activés ou désactivés pour plus de sécurité, pour les tests et pour faciliter la tâche d'intégration.

La figure 5 montre du code qui intercepte les demandes et effectue la validation de sécurité appropriée.

Figure 5. Validation de sécurité

C#
Copier
using System;
using System.Collections.Generic;
using System.Configuration;
using System.Web;
using Microsoft.AccessControl2.SDK;
namespace Azure.oAuth.SecurityModule
{
  internal class SWTModule : IHttpModule
  {
    // Service namespace setup in Windows Azure
    string _serviceNamespace = 
      ConfigurationManager.AppSettings["serviceNamespace"];
    // ACS name
    string _acsHostName = ConfigurationManager.AppSettings["acsHostname"];
    // The key for which the service was signed
    string _trustedSigningKey =
      ConfigurationManager.AppSettings["trustedSigningKey"];
    // The URL that was setup in the rely party in Windows Azure
    string _trustedAudience = 
      ConfigurationManager.AppSettings["trustedAudience"];
    // Setting to allow the metadata to be shown
    bool _enableMetaData =  
       Convert.ToBoolean(ConfigurationManager.AppSettings["enableMetadata"]);
    // Setting to disable or enable the security module
    bool _disableSecurity =
      Convert.ToBoolean(ConfigurationManager.AppSettings["disableSecurity"]);
    const string _metaData = "$metadata";
    private void context_BeginRequest(object sender, EventArgs e)
    {
      if (!_disableSecurity)
      {
        string tempAcceptableURLs = String.Empty;
        // Check if the audiencename has trailing slash
        tempAcceptableURLs = _trustedAudience.ToLower();
        if (tempAcceptableURLs.Substring(_trustedAudience.Length - 1, 1) == "/")
        {
          tempAcceptableURLs =
            tempAcceptableURLs.Substring(0, _trustedAudience.Length - 1);
        }
        // First check if the person is requesting the WSDL or .svc
        if (_enableMetaData != false
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs + _metaData
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs + "/"
          && HttpContext.Current.Request.Url.AbsoluteUri.ToLower() !=
          tempAcceptableURLs + "/" + _metaData)
        {
          // SWT Validation...
          // Get the authorization header
          string headerValue =
            ttpContext.Current.Request.Headers.Get("Authorization");
          // Check that a value is there
          if (string.IsNullOrEmpty(headerValue))
          {
            throw new ApplicationException("unauthorized-1.1");
          }
          // Check that it starts with 'WRAP'
          if (!headerValue.StartsWith("WRAP "))
          {
            throw new ApplicationException("unauthorized-1.2");
          }
          // ... <code truncated> ...
        }
      }
    }
  }
}

Windows Azure SDK

J'ai extrait une classe de Windows Azure SDK pour effectuer des validations de jetons pour cette implémentation. Le projet se trouve à l'adresse bit.ly/utQd3S. Après avoir installé le kit de développement logiciel, j'ai copié le fichier nommé « tokenvalidator.cs » dans un nouveau projet. Dans cette classe spécifique, j'ai appelé la méthode de validation pour déterminer si l'utilisateur était autorisé via les informations configurées dans ACS. Pour simplifier cette implémentation, j'ai créé une DLL personnalisée avec le seul mécanisme de sécurité nécessaire. Après avoir créé l'assembly, il suffisait d'avoir une référence à la DLL de sécurité avec mon service OData WCF. Résultat : une implémentation protégée et sécurisée.

Implémentation du service OData sécurisé

Avec l'amélioration de sécurité supplémentaire en place, la sécurisation du service OData WCF devenait simple. Il suffisait d'avoir une référence à l'assembly « Azure.AccessControl.SecurityModule » et de l'ajouter aux paramètres de configuration supplémentaires. Les fonctionnalités de sécurité seraient ensuite activées. La figure 6 illustre les paramètres de configuration de sécurité.

Figure 6. Paramètres de configuration de sécurité

XML
Copier
<appSettings>
  <add key="acsHostName" value="accesscontrol.windows.net" />
  <add key="serviceNamespace" value="Service Namespace" />
  <add key="trustedAudience"
    value="http://localhost/WCFDataServiceExample/NorthwindService.svc/" />
  <add key="trustedSigningKey" value="Trusted Signing Key" />
  <add key="enableMetadata" value="true" />
  <add key="disableSecurity" value="false"/>
</appSettings>
<system.webServer>
  <validation validateIntegratedModeConfiguration="false" />
  <modules runAllManagedModulesForAllRequests="true">
    <add name="SWTModule" type="Azure.AccessControl.SecurityModule.SWTModule,
      Azure.AccessControl.SecurityModule" preCondition="managedHandler" />
  </modules>
</system.webServer>

En fonction des paramètres de sécurité, les utilisateurs de mon service peuvent être contraints à n'afficher que les métadonnées. Cette condition est extrêmement avantageuse, car les utilisateurs peuvent encore référencer les objets et propriétés d'entité dans le code, ce qui simplifie l'implémentation. Pour désactiver les métadonnées, j'ai défini l'attribut « enableMetadata » sur false pour empêcher les utilisateurs de mon service d'accéder à celles-ci. Si les utilisateurs de mon service accédaient à celui-ci uniquement via le code côté client, je n'activerais pas les métadonnées, car cela serait inutile. Le service paraît similaire à un service Web normal lorsque les métadonnées sont activées, mais ceci sans la possibilité de l'utiliser, car aucune authentification ou autorisation appropriée n'existe, comme le montre la figure 7.


Figure 7. Service OData WCF avec les métadonnées exposées

Cela fonctionne quasiment comme si Entity Framework était utilisé directement pour le code d'implémentation, moyennant quelques différences mineures. Le segment de code clé à ajouter est le jeton requis dans l'en-tête de demande lors de l'envoi des données au service OData WCF. Je vais expliquer pour l'essentiel comment le mécanisme de sécurité fonctionne. Il recherche d'abord un jeton valide dans l'en-tête et vérifie si tous ses composants sont corrects, par exemple le public ciblé, la valeur d'expiration du jeton et la valeur du jeton. Ensuite, la demande est autorisée et l'appel du service réussit. L'interception de cette demande avant le retour des données à l'utilisateur du service garantit que l'appelant du service devait obtenir un jeton valide avant de pouvoir accéder aux données.

À ce stade, selon le niveau de sécurité requis sur les objets d'entité, l'utilisateur du service peut exécuter toute fonctionnalité exposée par le service en fonction des paramètres de sécurité définis. Lorsque la sécurité n'est pas activée, l'utilisateur du service reçoit une exception qui indique que l'action effectuée n'est pas autorisée.

À la différence du code Entity Framework traditionnel, une logique supplémentaire doit être implémentée avant d'appeler le service OData sécurisé par Windows Azure. Avec le module HTTP qui protège le service, je dois veiller à m'authentifier d'abord auprès de Windows Azure et à recevoir un jeton d'accès valide avant d'appeler le service OData. Le jeton envoyé par ACS sera transmis dans l'en-tête de demande pour chaque demande effectuée au service OData sécurisé. La figure 8 illustre un exemple de demande.

Figure 8. Exemple de demande de jeton

C#
Copier
// Request a token from ACS
using (WebClient client = new WebClient())
{
  client.BaseAddress = string.Format("https://{0}.{1}",
    _accessControlNamespace, _accessControlHostName);
  NameValueCollection values = new NameValueCollection();
  values.Add("wrap_name", wrapUsername);
  values.Add("wrap_password", wrapPassword);
  values.Add("wrap_scope", scope);
  byte[] responseBytes =
    client.UploadValues("WRAPv0.9/", "POST", values);
  response = Encoding.UTF8.GetString(responseBytes);
  Console.WriteLine("\nreceived token from ACS: {0}\n", response);
}

Lorsque le jeton a été reçu de Windows Azure et que l'utilisateur a été authentifié et autorisé correctement, ACS retourne un jeton à utiliser pour toutes les demandes futures jusqu'à l'expiration de ce jeton. À ce stade, l'implémentation d'Entity Framework ressemble aux conditions dans lesquelles je suis connecté à une base de données locale ou de mon réseau. La figure 9 illustre la consommation du service OData avec un jeton d'accès.

Figure 9. Consommation du service sécurisé OData avec un jeton d'accès Windows Azure

C#
Copier
// First things first: I obtain a token from Windows Azure
_token = GetTokenFromACS(_rootURL + "NorthwindService.svc");
// Now that I have a valid token, I can call the service as needed
Uri uri = new Uri(_rootURL + "NorthwindService.svc/");
try
{
  var northwindEntities = new ODataServiceClient.NorthwindEntities(uri);
  // Add the event handler to send the token in my request header
  northwindEntities.SendingRequest += new
    EventHandler<SendingRequestEventArgs>(OnSendingRequest);
  // Sample selecting data out ...
  var customersFound = from customers in northwindEntities.Customers
    select customers;
  foreach (var customer in customersFound)
  {
    // custom process ...
    // ... <code truncated> ...
    }
    // Add new data in ...
    var category = oDataServiceClient.Category.CreateCategory(0, "New category");
    northwindEntities.AddToCategories(category);
    northwindEntities.SaveChanges();
}
catch (DataServiceRequestException e)
{
  // Trap any data service exceptions such as a security error
  // In the event that the security does not allow an insert,
  // a forbidden error will be returned
  // ...
}

Implémenter du code via le script côté client est également aussi simple que de créer un appel AJAX de mon point de terminaison de service. La figure 10 illustre la consommation du service sécurisé OData à partir d'un script côté client.

Figure 10. Consommation du service sécurisé OData à partir d'un script côté client

C#
Copier
// Parse the entity object into JSON
var jsonEntity = window.JSON.stringify(entityObject);
$.support.cors = true;
// Asynchronous AJAX function to create a Cateogory using OData
$.ajax({
  type: "POST",
  contentType: "application/json; charset=utf-8",
  datatype: "jsonp",
  url: serverUrl + ODATA_ENDPOINT + "/" + odataSetName,
  data: jsonEntity,
  beforeSend: function (XMLHttpRequest) {
  // Specifying this header ensures that the results will be returned as JSON
  XMLHttpRequest.setRequestHeader("Accept", "application/json");
  XMLHttpRequest.setRequestHeader("Authorization", token);
  },
  success: function (data, textStatus, XmlHttpRequest) {
  if (successCallback) {
    successCallback(data.d, textStatus, XmlHttpRequest);
    }
  },
  error: function (XmlHttpRequest, textStatus, errorThrown) {
  if (errorCallback)
    errorCallback(XmlHttpRequest, textStatus, errorThrown);
  else
    errorHandler(XmlHttpRequest, textStatus, errorThrown);
  }
});

Un service RESTful offre une flexibilité d'implémentation accrue et s'utilise facilement via un script Java ou d'autres scripts ou API côté client. Une authentification et un jeton sont toujours requis pour consommer le service, mais OData est standard quelle que soit la plateforme en raison de la syntaxe de requête. La figure 11 illustre la consommation du service sécurisé OData avec un jeton d'accès Windows Azure dans Java.

Figure 11. Implémentation Java de la consommation du service sécurisé OData avec un jeton d'accès Windows Azure

C#
Copier
String serviceMethodUrl =  
  "http://localhost/WCFDataServiceExample/NorthwindService.svc/Categories?";
GetMethod method = new GetMethod(serviceMethodUrl + "$top=1");
method.addRequestHeader("Authorization", 
  "WRAP access_token=\"" + authToken + "\"");
try
{
  int returnCode = client.executeMethod(method);
  // ... <code truncated> ...
  br = new BufferedReader(new 
    InputStreamReader(method.getResponseBodyAsStream()));
  String readLine;
  while(((readLine = br.readLine()) != null))
  {
    //System.err.println(readLine);
    result += readLine;
  }
}

En résumé, j'éprouve souvent le besoin d'exposer les données d'une manière qui nécessite un certain niveau de sécurité pour empêcher tout accès non autorisé. L'utilisation d'ACS prend en charge cette nécessité en exploitant un service fédéré basé sur le cloud pour protéger non seulement mes services de données OData WCF mais également beaucoup d'autres applications.

Ceci dit, l'utilisation des services de données WCF seuls nécessiterait l'implémentation de contrats de données individuels et d'intercepteurs de requête pour les données à exposer. L'utilisation d'Entity Framework en association avec les services de données WCF permet d'exploiter les entités de base de données comme des contrats de données, et ces contrats sont fournis sous un format qui est déjà installé (objets sérialisables accessibles via OData). Le dernier gros morceau du casse-tête est de veiller à ce que mes services OData WCF RESTful soient protégés contre les accès non autorisés. ACS, OData et Entity Framework encapsulés par les services WCF RESTful m'offre un moyen rapide d'exposer mes données tout en utilisant une syntaxe de requête normalisée avec une couche de sécurité supplémentaire.

Sean Iannuzzi est un architecte de solutions pour The Agency Inside Harte-Hanks et tire parti des meilleures pratiques pour les solutions d'entreprise, les solutions système et les solutions logicielles. Il apprend de nouvelles technologies et recherche les moyens d'exploiter la technologie afin d'aider les entreprises et les développeurs à résoudre les problèmes. Il possède un blog sur weblogs.asp.net/seaniannuzzi et vous pouvez le suivre sur Twitter à l'adresse twitter.com/seaniannuzzi.

Merci à l'expert technique suivant d'avoir relu cet article : Danilo Diaz

MSDN Magazine Blog

14 Top Features of Visual Basic 14: The Q&A
Wednesday, janv. 7
Big Start to the New Year at MSDN Magazine
Friday, janv. 2

More MSDN Magazine Blog entries >


Current Issue


Avril 2018

Browse All MSDN Magazines


Subscribe to the MSDN Flash newsletter Subscribe to MSDN Flash newsletter


Receive the MSDN Flash e-mail newsletter every other week, with news and information personalized to your interests and areas of focus.

Suivez-nous
  • https://www.facebook.com/microsoftdeveloper
  • https://twitter.com/msdev
  • https://plus.google.com/111221966647232053570/
Subscribe to MSDN newsletter
Cette page est-elle utile ?
Votre avis sur ce contenu est important.
N'hésitez pas à nous faire part de vos commentaires.
Vous avez d'autres commentaires ?
1500 caractères restants
Merci !
Votre avis nous intéresse.

Centres de développement

  • Windows
  • Office
  • Visual Studio
  • Microsoft Azure
  • Other…

Ressources d'apprentissage

  • Microsoft Virtual Academy
  • Channel 9
  • MSDN Magazine

Communauté

  • Forums
  • Blogs
  • CodePlex

Support technique

  • Support libre-service

Programmes

  • BizSpark (pour les start-ups)
  • Imagine (for students)
Suisse (Français)
  • Newsletter
  • Privacy and Cookies
  • Terms of use
  • Trademarks
logo © 2018 Microsoft