Authentification des utilisateurs dans l'API Web ASP.NET

150

Ce sujet a été incroyablement déroutant pour moi. Je suis un débutant dans les applications HTTP mais j'ai besoin de développer un client iPhone qui consomme des données JSON de quelque part. J'ai choisi l'API Web de MS parce que cela me paraissait assez facile, mais quand il s'agit d'authentifier les utilisateurs, les choses deviennent assez frustrantes.

Je suis étonné de ne pas avoir été en mesure de trouver un exemple clair de la manière d'authentifier un utilisateur depuis l'écran de connexion jusqu'à l'utilisation de l' Authorizeattribut sur mes ApiControllerméthodes après plusieurs heures de recherche sur Google.

Ce n’est pas une question mais une demande d’exemple sur la manière de procéder exactement. J'ai regardé les pages suivantes:

Même si ceux-ci expliquent comment gérer les demandes non autorisées, ils ne démontrent pas clairement quelque chose comme un LoginControllerou quelque chose comme ça pour demander les informations d'identification de l'utilisateur et les valider.

Quelqu'un est-il prêt à écrire un bel exemple simple ou à me diriger dans la bonne direction, s'il vous plaît?

Merci.

Luis Aguilar
la source
1
J'ai répondu à la même question à ce sujet: stackoverflow.com/questions/11775594/…
cuongle
Pour Web Api avec asp.net, vous pouvez simplement utiliser le module d'authentification des cookies et des formulaires comme vous le feriez avec une application mvc (si vous le souhaitez). Ainsi, dans votre code API Web, vous pouvez ensuite vérifier le principal pour voir si l'utilisateur est connecté, par exemple (comme auparavant).
Elliot
Regardez aussi ma réponse pour stackoverflow.com/questions/11775594/…
Varun Chatterji
Je recommande fortement à beaucoup de gens de lire l' article asp.net/web-api/overview/security/… .
Youngjae

Réponses:

176

Je suis étonné de ne pas avoir été en mesure de trouver un exemple clair de la manière d'authentifier un utilisateur depuis l'écran de connexion jusqu'à l'utilisation de l'attribut Authorize sur mes méthodes ApiController après plusieurs heures de recherche sur Google.

C'est parce que vous êtes confus au sujet de ces deux concepts:

  • L'authentification est le mécanisme par lequel les systèmes peuvent identifier en toute sécurité leurs utilisateurs. Les systèmes d'authentification apportent des réponses aux questions:

    • Qui est l'utilisateur?
    • L'utilisateur est-il vraiment celui qu'il / elle se représente?
  • L'autorisation est le mécanisme par lequel un système détermine le niveau d'accès qu'un utilisateur authentifié particulier devrait avoir aux ressources sécurisées contrôlées par le système. Par exemple, un système de gestion de base de données pourrait être conçu de manière à fournir à certaines personnes spécifiées la possibilité de récupérer des informations à partir d'une base de données, mais pas la possibilité de modifier les données stockées dans la base de données, tout en donnant à d'autres personnes la possibilité de modifier les données. Les systèmes d'autorisation fournissent des réponses aux questions:

    • L'utilisateur X est-il autorisé à accéder à la ressource R?
    • L'utilisateur X est-il autorisé à effectuer l'opération P?
    • L'utilisateur X est-il autorisé à effectuer l'opération P sur la ressource R?

L' Authorizeattribut dans MVC est utilisé pour appliquer des règles d'accès, par exemple:

 [System.Web.Http.Authorize(Roles = "Admin, Super User")]
 public ActionResult AdministratorsOnly()
 {
     return View();
 }

La règle ci-dessus autorisera uniquement les utilisateurs des rôles Admin et Super User à accéder à la méthode

Ces règles peuvent également être définies dans le fichier web.config, à l'aide de l' locationélément. Exemple:

  <location path="Home/AdministratorsOnly">
    <system.web>
      <authorization>
        <allow roles="Administrators"/>
        <deny users="*"/>
      </authorization>
    </system.web>
  </location>

Cependant, avant que ces règles d'autorisation ne soient exécutées, vous devez être authentifié sur le site Web actuel .

Même si ceux-ci expliquent comment gérer les demandes non autorisées, ils ne démontrent pas clairement quelque chose comme un LoginController ou quelque chose comme ça pour demander les informations d'identification de l'utilisateur et les valider.

À partir de là, nous pourrions diviser le problème en deux:

  • Authentifier les utilisateurs lors de la consommation des services Web API dans la même application Web

    Ce serait l'approche la plus simple, car vous vous fiez à l' authentification dans ASP.Net

    Voici un exemple simple:

    Web.config

    <authentication mode="Forms">
      <forms
        protection="All"
        slidingExpiration="true"
        loginUrl="account/login"
        cookieless="UseCookies"
        enableCrossAppRedirects="false"
        name="cookieName"
      />
    </authentication>

    Les utilisateurs seront redirigés vers le compte / la route de connexion , vous y rendriez des contrôles personnalisés pour demander les informations d'identification de l'utilisateur, puis vous définiriez le cookie d'authentification en utilisant:

        if (ModelState.IsValid)
        {
            if (Membership.ValidateUser(model.UserName, model.Password))
            {
                FormsAuthentication.SetAuthCookie(model.UserName, model.RememberMe);
                return RedirectToAction("Index", "Home");
            }
            else
            {
                ModelState.AddModelError("", "The user name or password provided is incorrect.");
            }
        }
    
        // If we got this far, something failed, redisplay form
        return View(model);
  • Authentification multiplateforme

    Ce cas serait lorsque vous n'exposez que des services API Web dans l'application Web, par conséquent, vous auriez un autre client consommant les services, le client pourrait être une autre application Web ou toute application .Net (Win Forms, WPF, console, service Windows, etc)

    Par exemple, supposons que vous utiliserez le service API Web à partir d'une autre application Web sur le même domaine réseau (dans un intranet), dans ce cas, vous pouvez vous fier à l'authentification Windows fournie par ASP.Net.

    <authentication mode="Windows" />

    Si vos services sont exposés sur Internet, vous devez alors transmettre les jetons authentifiés à chaque service d'API Web.

    Pour plus d'informations, récupérez les articles suivants:

Jupaol
la source
3
Hou la la! C'est ce que j'appelle une réponse. Donc, pour conclure. Je prévois de faire ce qui suit: 1. Créez un contrôleur de compte avec une méthode de connexion qui reçoit le nom d'utilisateur et le mot de passe via HTTPS et renvoie le résultat de la connexion et le jeton. 2. Le client stocke le token et l'envoie comme en-tête (plus de HTTPS) dans la requête qui est validée par le serveur web. Est-ce une bonne approche? Ensuite, mon dernier doute est de savoir comment contrôler la falsification et l'expiration des jetons. Est-ce possible?
Luis Aguilar
6
@Jupaol Je pense que je parle au nom de nombreux développeurs d'API Web, je ne peux pas utiliser l'authentification par formulaire car je n'ai pas de site Web et les clients n'utilisent pas de navigateur, et je ne peux pas non plus utiliser l'authentification intégrée car les utilisateurs peuvent être n'importe où dans le monde sur n'importe quel appareil ( d'où l'API Web), alors qu'est-ce que j'utilise?
markmnl
21
Je ne comprends pas pourquoi cette réponse suscite autant de votes positifs. Il ne s'agit pas de l'API Web ASP.NET mais d'ASP.NET MVC.
Bastien Vandamme
3
Je voudrais réitérer le commentaire de B413 et souligner que cette question demande spécifiquement l'API Web
Julien
6
Est-ce la «mauvaise» réponse la plus votée sur SO? La réponse ne parle pas réellement de l'API Web qui est très différente d'une application Web mvc! Comme @ B413, je suis totalement choqué!
stt106
15

Si vous souhaitez vous authentifier par rapport à un nom d'utilisateur et un mot de passe et sans cookie d'autorisation , l' attribut MVC4 Authorize ne fonctionnera pas immédiatement . Cependant, vous pouvez ajouter la méthode d'assistance suivante à votre contrôleur pour accepter les en-têtes d'authentification de base. Appelez-le depuis le début des méthodes de votre contrôleur.

void EnsureAuthenticated(string role)
{
    string[] parts = UTF8Encoding.UTF8.GetString(Convert.FromBase64String(Request.Headers.Authorization.Parameter)).Split(':');
    if (parts.Length != 2 || !Membership.ValidateUser(parts[0], parts[1]))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "No account with that username and password"));
    if (role != null && !Roles.IsUserInRole(parts[0], role))
        throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Unauthorized, "An administrator account is required"));
}

Du côté client, cet assistant crée un HttpClientavec l'en-tête d'authentification en place:

static HttpClient CreateBasicAuthenticationHttpClient(string userName, string password)
{
    var client = new HttpClient();
    client.DefaultRequestHeaders.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(UTF8Encoding.UTF8.GetBytes(userName + ':' + password)));
    return client;
}
Edward Brey
la source
Je voulais juste commenter que je cherchais un moyen simple d'utiliser la norme de l'industrie pour transmettre les informations d'identification dans l'en-tête. Cet exemple a montré les bases du côté serveur et du côté client et était tout ce dont j'avais besoin.
da_jokker
9

Je travaille sur un projet MVC5 / API Web et je devais être en mesure d'obtenir l'autorisation pour les méthodes Web Api. Lorsque ma vue d'index est chargée pour la première fois, j'appelle la méthode API Web «token» qui, je crois, est créée automatiquement.

Le code côté client (CoffeeScript) pour obtenir le jeton est:

getAuthenticationToken = (username, password) ->
    dataToSend = "username=" + username + "&password=" + password
    dataToSend += "&grant_type=password"
    $.post("/token", dataToSend).success saveAccessToken

En cas de succès, le code suivant est appelé, ce qui enregistre le jeton d'authentification localement:

saveAccessToken = (response) ->
    window.authenticationToken = response.access_token

Ensuite, si j'ai besoin de faire un appel Ajax à une méthode API Web qui a la balise [Authorize], j'ajoute simplement l'en-tête suivant à mon appel Ajax:

{ "Authorization": "Bearer " + window.authenticationToken }
ProfNimrod
la source
D'où response.access_tokenvient-il. Le définissez-vous à partir du code c # ..?
shashwat
L'objet 'response' est retourné par la méthode 'token'.
ProfNimrod
Je n'ai pas examiné les rôles. Cette approche vous donne simplement un jeton d'accès afin que vous puissiez appeler des méthodes WebApi décorées avec la balise [Authorize]. Vraisemblablement, lorsque vous appelez l'une de ces méthodes, vous pouvez vérifier les rôles. stackoverflow.com/questions/19689570/mvc-5-check-user-role peut vous aider.
ProfNimrod
Et où dans cette solution authentifiez-vous réellement votre utilisateur?
Craig Brett
Le point de terminaison / token est créé automatiquement pour tout nouveau projet d'API Web. Le code derrière ceci est l'endroit où l'utilisateur est authentifié. C'est un peu plus compliqué si vous avez ajouté un contrôleur d'API Web à un projet MVC existant.
ProfNimrod