web-dev-qa-db-fra.com

Enregistrement de connexions externes à Web API 2 à partir de plusieurs clients API avec OWIN Identity

J'aimerais l'architecture suivante (j'ai composé le nom du produit pour cet exemple):

Application Web API 2 exécutée sur un serveur http://api.prettypictures.com

Application client MVC 5 exécutée sur un autre serveur http://www.webpics.com

Je souhaite que www.webpics.com l'application cliente utilise l'API Pretty Pictures pour:

  • Enregistrer de nouveaux comptes avec nom d'utilisateur et mot de passe
  • Enregistrez de nouveaux comptes avec Facebook/Google/Twitter/Microsoft
  • S'identifier
  • Récupérer des photos

Tous les travaux ci-dessus, sauf l'enregistrement de comptes externes avec Facebook, Google, etc.

Je ne peux pas déterminer le flux correct pour créer un compte externe à partir d'un utilisateur client distinct de l'API.

J'ai étudié la plupart des documents disponibles sur le flux d'authentification, comme ceci: enter image description here

J'ai lu à peu près tout ce que je peux sur le nouveau modèle d'identité dans OWIN.

J'ai examiné le modèle SPA dans Visual Studio 2013. Il montre comment faire la plupart de ce dont j'ai besoin, mais uniquement lorsque le client et l'API sont sur le même hôte; si je veux que plusieurs clients accèdent à mon API et puissent permettre aux utilisateurs de s'inscrire via Google, etc. cela ne fonctionne pas et pour autant que je puisse dire les ruptures de flux d'authentification OWIN.

Voici le flux jusqu'à présent:

  • L'utilisateur accède à www.webpics.com/Login
  • www.webpics.com appels api.prettypictures.com/Account/ExternalLogins (avec un returnUrl défini pour revenir à un rappel sur www.webpics.com ) et affiche les liens résultants vers l'utilisateur
  • L'utilisateur clique sur "Google"
  • Le navigateur redirige vers api.prettypictures.com/Account/ExternalLogin avec le nom du fournisseur, etc.
  • L'action ExternalLogin de l'API instancie un défi à google.com
  • Le navigateur est redirigé vers google.com
  • L'utilisateur entre son nom d'utilisateur et son mot de passe (s'il n'est pas déjà connecté à google.com )
  • google.com présente désormais l'habilitation de sécurité: "api.prettypictures.com" souhaite accéder à votre adresse e-mail , nom, femme, enfants, etc. Est-ce correct?
  • L'utilisateur clique sur "Oui" et est redirigé vers api.prettypictures.com/Account/ExternalLogin avec un cookie que Google a défini.

C'est là que je suis coincé. Ce qui est censé se passer ensuite, c'est que l'application cliente devrait être informée que l'utilisateur s'est correctement authentifié avec google.com et recevoir un code d'accès à usage unique pour échanger un jeton d'accès plus tard. L'application cliente devrait avoir la possibilité, si nécessaire, de demander à l'utilisateur un nom d'utilisateur à associer à sa connexion google.com .

Je ne sais pas comment faciliter cela.

En fait, à ce stade, le navigateur se trouve au point d'extrémité api.prettypictures.com/Account/ExternalLogin après le rappel de Google. L'API est connectée à Google, mais le client ne sait pas comment gérer cela. Dois-je rediriger ce cookie vers www.webpics.com ?

Dans l'application SPA, cela se fait via AJAX et google.com renverra un jeton sous forme de fragment d'URL et tout fonctionne bien car il se trouve sur un seul domaine, mais cela défie en grande partie le fait d'avoir une "API" que plusieurs clients peuvent utiliser pleinement.

Aidez-moi!

74
joshcomley

Mise à jour: les choses ont changé depuis que j'ai écrit cet article en janvier : MSFT a publié son middleware client OpenID connect officiel et j'ai travaillé dur avec @manfredsteyer pour adapter OAuth2 serveur d'autorisation construit en Katana pour se connecter à OpenID. Cette combinaison se traduit par une solution beaucoup plus facile et beaucoup plus puissante qui ne nécessite aucun code client personnalisé et est 100% compatible avec les clients de connexion OAuth2/OpenID standard. Les différentes étapes que j'ai mentionnées en janvier peuvent maintenant être remplacées par seulement quelques lignes:

Serveur:

app.UseOpenIdConnectServer(options =>
{
    options.TokenEndpointPath = new PathString("/connect/token");
    options.SigningCredentials.AddCertificate(certificate);

    options.Provider = new CustomOpenIdConnectServerProvider();
});

Client:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions
{
    Authority = "http://localhost:55985/",

    ClientId = "myClient",
    ClientSecret = "secret_secret_secret",
    RedirectUri = "http://localhost:56854/oidc"
});

Vous pouvez trouver tous les détails (et différents exemples) sur le référentiel GitHub:

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server

https://github.com/aspnet-contrib/AspNet.Security.OpenIdConnect.Server/tree/dev/samples/Nancy


Josh, vous êtes définitivement sur la bonne voie et votre implémentation d'authentification déléguée/fédérée semble plutôt bonne (j'imagine que vous avez utilisé le middleware OWIN prédéfini de Microsoft.Owin.Security.Facebook/Google/Twitter).

Ce que vous devez faire est de créer votre propre serveur d'autorisation OAuth2 personnalisé . Vous disposez de nombreuses options pour y parvenir, mais la plus simple est probablement de brancher le OAuthAuthorizationServerMiddleware dans votre classe de démarrage OWIN. Vous le trouverez dans le package Nuget Microsoft.Owin.Security.OAuth.

Alors que la meilleure pratique serait de créer un projet distinct (souvent appelé "AuthorizationServer"), je préfère personnellement l'ajouter à mon "projet API" lorsqu'il n'est pas destiné à être utilisé sur plusieurs API (ici, vous devrez l'insérer dans le projet hébergeant "api.prettypictures.com").

Vous trouverez un excellent échantillon dans le référentiel Katana:

https://katanaproject.codeplex.com/SourceControl/latest#tests/Katana.Sandbox.WebServer/Startup.cs

app.UseOAuthAuthorizationServer(new OAuthAuthorizationServerOptions
{
    AuthorizeEndpointPath = new PathString("/oauth2/authorize"),
    TokenEndpointPath = new PathString("/oauth2/token"),
    ApplicationCanDisplayErrors = true,

    AllowInsecureHttp = true,

    Provider = new OAuthAuthorizationServerProvider
    {
        OnValidateClientRedirectUri = ValidateClientRedirectUri,
        OnValidateClientAuthentication = ValidateClientAuthentication,
        OnGrantResourceOwnerCredentials = GrantResourceOwnerCredentials,
    },
    AuthorizationCodeProvider = new AuthenticationTokenProvider
    {
        OnCreate = CreateAuthenticationCode,
        OnReceive = ReceiveAuthenticationCode,
    },
    RefreshTokenProvider = new AuthenticationTokenProvider
    {
        OnCreate = CreateRefreshToken,
        OnReceive = ReceiveRefreshToken,
    }
});

N'hésitez pas à parcourir l'ensemble du projet pour voir comment le formulaire de consentement d'autorisation a été mis en œuvre à l'aide de simples fichiers Razor. Si vous préférez un cadre de niveau supérieur comme ASP.NET MVC ou NancyFX, créez vos propres méthodes AuthorizationController controller et Authorize (assurez-vous d'accepter à la fois GET et POST) et utilisez le routage d'attributs pour faire correspondre le AuthorizeEndpointPath défini dans votre serveur d'autorisation OAuth2 (ie. [Route("oauth2/authorize")] dans mon exemple, où j'ai changé le AuthorizeEndpointPath pour utiliser oauth2/ comme base de chemin).

L'autre chose que vous devez faire est d'ajouter un client d'autorisation OAuth2 dans votre application Web. Malheureusement, il n'y a pas de support client OAuth2 générique dans Katana, et vous devrez créer le vôtre. J'ai personnellement soumis une proposition à l'équipe Katana, mais elle a été refusée. Mais pas de panique, c'est assez simple à faire:

Copiez les fichiers appropriés à partir du référentiel Microsoft.Owin.Security.Google qui s'y trouve: https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs =

Vous aurez besoin de GoogleOAuth2AuthenticationHandler, GoogleOAuth2AuthenticationMiddleware, GoogleOAuth2AuthenticationOptions, GoogleAuthenticationExtensions (vous devrez supprimer les 2 premières méthodes correspondant à l'implémentation de Google OpenID), IGoogleOAuth2AuthenticationProvider, GoogleOAuth2ReturnEndpointContext, GoogleOAuth2AuthenticationProvider, GoogleOAuth2AuthenticatedContext Et GoogleOAuth2ApplyRedirectContext. Une fois que vous avez inséré ces fichiers dans votre projet hébergeant "webpics.com", renommez-les en conséquence et modifiez l'URL des points de terminaison d'autorisation et d'accès dans GoogleOAuth2AuthenticationHandler Pour qu'ils correspondent à ceux que vous avez définis dans votre serveur d'autorisation OAuth2.

Ensuite, ajoutez la méthode Use de votre GoogleAuthenticationExtensions renommé/personnalisé à votre classe de démarrage OWIN. Je suggère d'utiliser AuthenticationMode.Active Pour que vos utilisateurs soient directement redirigés vers votre point de terminaison d'autorisation API OAuth2. Ainsi, vous devez supprimer l'aller-retour "api.prettypictures.com/Account/ExternalLogins" et laisser le middleware client OAuth2 modifier les réponses 401 pour rediriger les clients vers votre API.

Bonne chance. Et n'hésitez pas si vous avez besoin de plus d'informations;)

46
Pinpoint