web-dev-qa-db-fra.com

API Web ASP.NET et OpenID Connect: comment obtenir un jeton d'accès à partir d'un code d'autorisation

J'essaie de faire fonctionner OpenID Connect ... Un utilisateur de mon API Web a réussi à obtenir un code d'autorisation d'un fournisseur OpenID Connect. Comment suis-je censé transmettre ce code à mon API Web ASP.NET? Comment dois-je configurer OWIN Middleware pour pouvoir obtenir un jeton d'accès à l'aide du code d'autorisation?

UPDATE: Un SPA utilise AJAX pour communiquer avec mon service Web (API Web ASP.NET). Dans mon service Web, utilisez le middleware OWIN. J'ai défini OpenIDConnect comme mécanisme d'authentification. Lorsque le service Web est appelé pour la première fois, il a correctement redirigé l'utilisateur vers la page de connexion du fournisseur OpenID Connect. L'utilisateur pouvait se connecter et obtenir un code d'autorisation à la suite. Autant que je sache, ce code peut maintenant être utilisé (par mon service Web) pour un jeton d'accès. Cependant, je ne sais pas comment renvoyer ce code sur mon service Web (cette opération est-elle effectuée à l'aide d'un en-tête?), Puis quoi configurer pour obtenir le jeton d'accès. Je suppose que je pourrais appeler le point de terminaison du jeton manuellement, mais j'aimerais plutôt tirer parti du composant OWIN.

13
Dunken

BenV a déjà répondu à la question, mais il y a plus à considérer.

class partial Startup
{
    public void ConfigureAuth(IAppBuilder app)
    {
        // ...

        app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
          {
            ClientId = clientId,
            Authority = authority,
            Notifications = new OpenIdConnectAuthenticationNotifications() {
                AuthorizationCodeReceived = (context) => {
                   string authorizationCode = context.Code;
                   // (tricky) the authorizationCode is available here to use, but...
                   return Task.FromResult(0);
                }
            }
          }
    }
}

Deux problèmes:

  • Tout d’abord, authorizationCode va expirer rapidement. Il n'y a aucun sens à le stocker.
  • Le deuxième problème est que l'événement AuthorizationCodeReceived ne sera déclenché pour aucun rechargement de page tant que authorisationCode n'est pas expirée et stockée dans la session.

Ce que vous devez faire est d'appeler AcquireTokenByAuthorizationCodeAsync qui le mettra en cache et gérera correctement à l'intérieur de TokenCache.DefaultShare:

AuthorizationCodeReceived = (context) => {
    string authorizationCode = context.Code;
    AuthenticationResult tokenResult = await context.AcquireTokenByAuthorizationCodeAsync(authorizationCode, new Uri(redirectUri), credential);
    return Task.FromResult(0);
}

Maintenant, avant tous les appels vers la ressource, appelez AcquireTokenSilentAsync pour obtenir le paramètre accessToken (il utilisera TokenCache ou utilisera silencieusement refreshToken). Si le jeton a expiré, il déclenchera une exception AdalSilentTokenAcquisitionException (invoque la procédure de renouvellement du code d'accès).

// currentUser for ClaimsPrincipal.Current.FindFirst("http://schemas.Microsoft.com/identity/claims/objectidentifier")
AuthenticationResult authResult = await context.AcquireTokenSilentAsync(resourceUri, credential, currentUser);

L'appel de AcquireTokenSilentAsync est très rapide si le jeton est mis en cache.

11
andrew.fox

L'approche recommandée consiste à utiliser l'événement AuthorizationCodeReceived pour échanger le code d'authentification contre un jeton d'accès. Vittorio a une entrée de blog qui décrit le flux global.

Voici un exemple de cet exemple d'application sur GitHub du code Startup.Auth.cs pour le configurer:

app.UseOpenIdConnectAuthentication(
    new OpenIdConnectAuthenticationOptions
    {
        ClientId = clientId,
        Authority = Authority,
        Notifications = new OpenIdConnectAuthenticationNotifications()
        {
            AuthorizationCodeReceived = (context) =>
           {
               var code = context.Code;
               ClientCredential credential = new ClientCredential(clientId, appKey);
               string tenantID = context.AuthenticationTicket.Identity.FindFirst("http://schemas.Microsoft.com/identity/claims/tenantid").Value;
               string signedInUserID = context.AuthenticationTicket.Identity.FindFirst(ClaimTypes.NameIdentifier).Value;
               AuthenticationContext authContext = new AuthenticationContext(string.Format("https://login.windows.net/{0}", tenantID), new EFADALTokenCache(signedInUserID));
               AuthenticationResult result = authContext.AcquireTokenByAuthorizationCode(
                           code, new Uri(HttpContext.Current.Request.Url.GetLeftPart(UriPartial.Path)), credential, graphResourceID);

               return Task.FromResult(0);
            },
            ...
    }

Remarque: L'événement AuthorizationCodeReceived n'est invoqué qu'une seule fois lorsque l'autorisation a réellement lieu. Si le code d'autorisation est déjà généré et stocké, cet événement n'est pas appelé. Vous devez vous déconnecter ou supprimer les cookies pour que cet événement se produise.

10
BenV

Vous devez contourner la validation owin par défaut pour créer une autorisation personnalisée:

           new OpenIdConnectAuthenticationOptions
            {
                ...,
                TokenValidationParameters = new System.IdentityModel.Tokens.TokenValidationParameters
                {
                    ValidateIssuer = false
                },
1
James