Implémenter l'authentification HTTP dans l'API Web

Dans cet article, je présenterais une discussion sur la mise en œuvre de l'authentification HTTP dans l'API Web. Vous pouvez implémenter l'authentification HTTP dans votre API Web de deux manières. Ceux-ci inclus:

  • Authentification par formulaires
  • Authentification de base

Nous ne considérons pas l'authentification Windows comme une stratégie réalisable car vous ne pouvez pas exposer votre service sur Internet si vous tirez parti de l'authentification Windows.

Sécurisation de l'API Web à l'aide de l'authentification par formulaire

L'authentification par formulaire utilise le fournisseur d'appartenance ASP.Net et utilise des cookies HTTP standard au lieu de l'en-tête d'autorisation. L'authentification par formulaire n'est pas aussi conviviale que REST car elle utilise des cookies, et les clients devraient gérer les cookies pour consommer des services qui tirent parti de l'authentification par formulaire, qui est vulnérable aux attaques de falsification intersites. C'est pourquoi vous devez implémenter des mesures CSRF si vous utilisez l'authentification par formulaire. L'authentification par formulaire n'utilise pas le cryptage pour sécuriser les informations d'identification de l'utilisateur. Par conséquent, ce n'est pas une stratégie sécurisée, sauf si vous exécutez votre API Web via SSL.

API Web sécurisée à l'aide de l'authentification de base

L'authentification de base envoie les informations d'identification de l'utilisateur dans le texte de plainte sur le fil. Si vous utilisez une authentification de base, vous devez utiliser votre API Web sur un protocole SSL (Secure Socket Layer). Lors de l'utilisation de l'authentification de base, nous transmettons les informations d'identification de l'utilisateur ou le jeton d'authentification dans l'en-tête de la requête HTTP. Le service côté serveur aurait besoin d'analyser l'en-tête pour récupérer le jeton d'authentification. Si la requête n'est pas une requête valide, le serveur renvoie HTTP 401, ce qui signifie une réponse non autorisée.

Explorons comment nous pouvons effectuer une authentification de base à l'aide d'un filtre d'action. Pour ce faire, vous devez créer une classe qui dérive la System.Web.Http.Filters.ActionFilterAttributeclasse comme indiqué ci-dessous:

public class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute

    {

        private Boolean IsUserValid(Dictionary credentials)

        {

            if (credentials["UserName"].Equals("joydip") && credentials["Password"].Equals("joydip123"))

                return true;

            return false;

        }

         private Dictionary ParseRequestHeaders(System.Web.Http.Controllers.HttpActionContext actionContext)

        {

            Dictionary credentials = new Dictionary();

             var httpRequestHeader = actionContext.Request.Headers.GetValues("Authorization").FirstOrDefault();

            httpRequestHeader = httpRequestHeader.Substring("Authorization".Length);

             string[] httpRequestHeaderValues = httpRequestHeader.Split(':');

            string username = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[0]));

            string password = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[1]));

             credentials.Add("UserName", username);

            credentials.Add("Password", password);

             return credentials;

        }

         public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)

        {

            try

            {

                if (actionContext.Request.Headers.Authorization == null)

                {

                    actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                }

                else

                {

                     Dictionary credentials = ParseRequestHeaders(actionContext);

                     if (IsUserValid(credentials))

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.OK);

                    else

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                 }

            }

            catch

            {

                actionContext.Response = new System.Net.Http.HttpResponseMessage

(System.Net.HttpStatusCode.InternalServerError);

            }

        }

    }

Nous vérifions si l'en-tête d'autorisation est présent; sinon, une réponse HTTP 401 ou "non autorisée" est renvoyée.

L'étape suivante consiste à valider les informations d'identification de l'utilisateur transmises via l'en-tête de demande d'autorisation du client. Avant de faire cela, nous devons savoir comment l'API Web doit être appelée à partir du client. Pour cela, j'ai préparé une méthode de test. La méthode de test utilise la HttpClientclasse pour appeler l'API Web. Notez que les noms d'utilisateur sont convertis au format de chaîne Base64 avant d'être transmis. La méthode d'essai est donnée ci-dessous.

[TestMethod]

        public void BasicAuthenticationTest()

        {

            string username = Convert.ToBase64String(Encoding.UTF8.GetBytes("joydip"));

            string password = Convert.ToBase64String(Encoding.UTF8.GetBytes("joydip123"));

            HttpClient client = new HttpClient();

            client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Authorization", username + ":" + password);

            var result = client.GetAsync(new Uri("//localhost//api/default/")).Result;

           Assert.IsTrue(result.IsSuccessStatusCode);

        }

Comme vous pouvez le voir dans l'extrait de code ci-dessus, les informations d'identification de l'utilisateur sont transmises à l'aide de l'en-tête d'autorisation.

Maintenant que le client est prêt, terminons l'implémentation de la BasicAuthenicationFilterclasse. Dans la OnActionExecutingméthode, nous aurions besoin d'analyser la valeur d'en-tête de cette classe et de vérifier si les informations d'identification fournies par le client correspondent. Pour l'instant, supposons que le nom d'utilisateur et le mot de passe ont respectivement les valeurs joydipet joydip123(ils sont codés en dur). Voici le code complet de la BasicAuthenticationFilterclasse qui intègre la validation des informations d'identification de l'utilisateur.

public class BasicAuthenticationAttribute : System.Web.Http.Filters.ActionFilterAttribute

    {

        public override void OnActionExecuting(System.Web.Http.Controllers.HttpActionContext actionContext)

        {

            try

            {

                if (actionContext.Request.Headers.Authorization == null)

                {

                    actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                }

                else

                {

                    actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);

                    var httpRequestHeader = actionContext.Request.Headers.GetValues("Authorization").FirstOrDefault();

                    httpRequestHeader = httpRequestHeader.Substring("Authorization".Length);

                    string[] httpRequestHeaderValues = httpRequestHeader.Split(':');

                    string username = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[0]));

                    string password = Encoding.UTF8.GetString(Convert.FromBase64String(httpRequestHeaderValues[1]));

                    if (username.Equals("joydip") && password.Equals("joydip123"))

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.OK);

                    else

                        actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.Unauthorized);

                }

            }

            catch

            {

                actionContext.Response = new System.Net.Http.HttpResponseMessage(System.Net.HttpStatusCode.InternalServerError);

            }

        }

    }

Dans votre classe de contrôleur, vous devez spécifier l'attribut de manière appropriée. Notez que l' BasicAuthenticationattribut ici fait référence à la BasicAuthenticationAttributeclasse que nous avons implémentée.

    [BasicAuthentication]

    public class DefaultController : ApiController

    {

        public IEnumerable Get()

        {

            return new string[] { "Joydip", "Kanjilal" };

        }

    }

Maintenant, un peu de configuration --- vous devez configurer l'attribut afin que les appels à votre contrôleur soient filtrés de manière appropriée pour que l'authentification fonctionne.

 public static class WebApiConfig

    {

        public static void Register(HttpConfiguration config)

        {

            config.MapHttpAttributeRoutes();

            config.Routes.MapHttpRoute(

                name: "DefaultApi",

                routeTemplate: "api/{controller}/{id}",

                defaults: new { id = RouteParameter.Optional }

            );

            config.Formatters.Remove(config.Formatters.XmlFormatter);

            GlobalConfiguration.Configuration.Filters.Add(new BasicAuthenticationAttribute());

        }

    }

Et vous avez terminé! Lorsque vous exécutez le scénario de test, le test réussit.

Vous devez de toute façon vous assurer que les informations d'identification ne sont pas codées en dur; ils doivent plutôt être stockés dans une base de données et vous devez les récupérer et les valider dans la OnActionExecutingméthode de la BasicAuthenticationAttributeclasse.