Appeler un Web Service avec authentification et par méthode GET

Le web foisonne d’exemples d’appels à des Web Services avec authentification. Dans la grande majorité, la méthode utilisée est la méthode POST.

Nous allons voir ici comment appeler un Web Service de type « Generic Handler » (extension .ashx) avec la méthode GET et avec une authentification « Basic » en ASP.NET Web Forms.

On prendra l’exemple avec des échanges en JSON via la bibliothèque « Newtonsoft.Json ».

A noter également qu’on considérera que les échanges se font via HTTPS.

On va d’abord voir comment implémenter le Web Service de manière non-authentifiée côté serveur, dans un fichier MonWebService.ashx.cs par exemple :

public void ProcessRequest(HttpContext context)
{
    var list = MaListeDeResultats();
    string jsonResult = JsonConvert.SerializeObject(list);

    context.Response.ContentType = "application/json";
    context.Response.Write(jsonResult);
}

Quand on interroge le Web Service, on appelle une méthode qui nous retourne le résultat attendu (ici « list »), puis on le « sérialise » grâce aux outils proposés par Newtonsoft.Json. En l’occurrence, la fonction SerializeObject.

Maintenant, côté client, on appelle le Web Service :

private void CallWebService()
{
    string strUrl = ConfigurationManager.AppSettings["WebServiceUrl"];
 
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrl);
    request.ContentType = "application/x-www-form-urlencoded";

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
 
    lblResult.Text = responseString;
}

Pour un confort d’utilisation, on met l’URL du Web Service en paramètre dans le Web.config. Bien entendu, cela est adaptable (on pourrait mettre seulement la racine dans le Web.config, et le nom du handler en paramètre de la fonction, par exemple). On appelle ensuite le Web Service avec une requête classique (HttpWebRequest  et HttpWebResponse), puis on écrit le résultat dans un Label (puisqu’on est sur du Web Forms).

Désormais, nous allons voir comment sécuriser cet appel en plaçant un jeton d’authentification  (token en anglais) dans l’en-tête (header) de la requête.

Pour commencer, il faut générer une « clé » (qui fera office de jeton) à partir d’un site spécialisé tel que http://randomkeygen.com/ ou au hasard de votre imagination, puis le saisir dans le Web.config du client et du serveur.

Enfin, côté client, il suffit de rajouter une ligne permettant d’insérer le jeton dans l’attribut « Authorization » de l’en-tête de la requête :

request.Headers.Add("Authorization", "Basic " + CommonLib.HashPassword (ConfigurationManager.AppSettings["WebServiceKey"]));

CommonLib.HashPassword() est une fonction que vous pourrez implémenter, si vous le souhaiter, afin d’ajouter une couche de sécurité à votre échange (hachage SHA, etc.). Elle prend en paramètre la clé spécifiée dans Web.config. Sinon, passez directement la clé.

Ainsi, on obtient :

private void CallWebService()
{
    string strUrl = ConfigurationManager.AppSettings["WebServiceUrl"];
 
    HttpWebRequest request = (HttpWebRequest)WebRequest.Create(strUrl);
    request.Headers.Add("Authorization", "Basic " + CommonLib.HashPassword (ConfigurationManager.AppSettings["WebServiceKey"]));
    request.ContentType = "application/x-www-form-urlencoded";

    HttpWebResponse response = (HttpWebResponse)request.GetResponse();
    string responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
 
    lblResult.Text = responseString;
}

Côté serveur maintenant, on ajoute la vérification de l’authentification. On implémente pour cela une fonction qu’on nomme ici CheckIfIsAuthorized() et qui prend en paramètre la requête HTTP.

public void ProcessRequest(HttpContext context)
{
 
    if ((CheckIfIsAuthorized(context.Request)))
    {
        var list = SessionContext.MonService.MaListeDeResultats();
        string jsonResult = JsonConvert.SerializeObject(list);
 
        context.Response.ContentType = "application/json";
        context.Response.Write(jsonResult);
    }
    else
    {
        context.Response.Write(MESSAGE_NOT_AUTHORIZED);
    }
 
}

private bool CheckIfIsAuthorized(HttpRequest httpRequest)
{
    try
    {
        var request = HttpContext.Current.Request;
        var authHeader = request.Headers["Authorization"];
        if (authHeader != null)
        {
            var authHeaderVal = AuthenticationHeaderValue.Parse(authHeader);
 
            // cf. RFC 2617 sec 1.2
            if (authHeaderVal.Scheme.Equals("basic", StringComparison.OrdinalIgnoreCase) &&
                authHeaderVal.Parameter != null)
            {
                var key = authHeaderVal.Parameter;
                if (key.Equals(CommonLib.HashPassword(ConfigurationManager.AppSettings["WebServiceKey"])))
                {
                    return true;
                }
            }
        }
    }
    catch (Exception ex)
    {
	Log(ex);
        return false;
    }
 
    return false;
}

Vous noterez qu’on utilise ici à nouveau CommonLib.HashPassword() et la clé contenue dans le Web.config. Par ailleurs, on utilise des fonctions standardisées permettant de récupérer les information du header (AuthenticationHeaderValue.Parse(), etc.).

En parlant des Web.config, un petit résumer s’impose. Pour rappel, les deux protagonistes doivent partager la même clé (quitte à la changer de temps en temps). Et il faut veiller également à ne pas mettre de caractères interdits dans les balises, tel que « < ».

Web.config client :

  <appSettings>
    <add key="WebServiceUrl" value="https://monsite.net/MonWebService.ashx" />
    <add key="WebServiceKey" value="y^4$^v40d0b69X0;.-r2{]'D(cR90@" />
  </appSettings>

Web.config serveur :

  <appSettings>
    <add key="WebServiceKey" value="y^4$^v40d0b69X0;.-r2{]'D(cR90@" />
  </appSettings>

Cette approche des Web Services est plus rudimentaire que WCF ou d’autres, mais elle permet de faire des choses assez simplement et rapidement, tout en permettant de pouvoir tester de visu via le JSON.

Bon requête !

Laisser un commentaire

Votre adresse de messagerie ne sera pas publiée. Les champs obligatoires sont indiqués avec *

Captcha *

Ce site utilise Akismet pour réduire les indésirables. En savoir plus sur comment les données de vos commentaires sont utilisées.