example authorizeattribute asp.net-mvc oauth-2.0 asp.net-identity owin asp.net-web-api2

asp.net-mvc - authorizeattribute - web api rest authentication



Registro de inicios de sesión externos de Web API 2 desde múltiples clientes API con OWIN Identity (1)

Actualización: las cosas han cambiado desde que escribí esta publicación en enero : MSFT lanzó su middleware oficial de cliente de conexión OpenID y trabajé duro con @manfredsteyer para adaptar el servidor de autorización OAuth2 construido en Katana a OpenID Connect. Esta combinación da como resultado una solución mucho más fácil y mucho más poderosa que no requiere ningún código de cliente personalizado y es 100% compatible con los clientes de conexión estándar OAuth2 / OpenID. Los diferentes pasos que mencioné en enero ahora se pueden reemplazar por unas pocas líneas:

Servidor:

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

Cliente:

app.UseOpenIdConnectAuthentication(new OpenIdConnectAuthenticationOptions { Authority = "http://localhost:55985/", ClientId = "myClient", ClientSecret = "secret_secret_secret", RedirectUri = "http://localhost:56854/oidc" });

Puede encontrar todos los detalles (y diferentes muestras) en el repositorio de GitHub:

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

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

Josh, definitivamente estás en el camino correcto y tu implementación de autenticación delegada / federada parece bastante buena (imagino que has usado el middleware OWIN predefinido de Microsoft.Owin.Security.Facebook/Google/Twitter ).

Lo que debe hacer es crear su propio servidor de autorización OAuth2 personalizado. Tiene muchas opciones para lograrlo, pero la más fácil es probablemente conectar el OAuthAuthorizationServerMiddleware en su clase de inicio de OWIN. Lo encontrará en el paquete Microsoft.Owin.Security.OAuth Nuget.

Si bien la mejor práctica sería crear un proyecto separado (a menudo llamado "AuthorizationServer"), personalmente prefiero agregarlo a mi "proyecto API" cuando no está destinado a ser utilizado en múltiples API (aquí, tendría que insertarlo). en el alojamiento del proyecto "api.prettypictures.com").

Encontrará una gran muestra en el repositorio de 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, } });

No dude en navegar por todo el proyecto para ver cómo se ha implementado el formulario de consentimiento de autorización usando simples archivos Razor. Si prefiere un marco de nivel superior como ASP.NET MVC o NancyFX, cree su propio controlador AuthorizationController y Authorize métodos (asegúrese de aceptar tanto GET como POST) y utilice Attribute Routing para que coincida con AuthorizeEndpointPath definido en su servidor de autorización OAuth2 (es decir, . [Route("oauth2/authorize")] en mi muestra, donde he cambiado AuthorizeEndpointPath para usar oauth2/ como base de ruta).

La otra cosa que debe hacer es agregar un cliente de autorización OAuth2 en su aplicación web. Desafortunadamente, no hay soporte genérico para clientes OAuth2 en Katana, y tendrás que construir el tuyo propio. Personalmente, envié una propuesta al equipo de Katana, pero se rechazó. Pero no se asuste, es bastante fácil de hacer:

Copie los archivos apropiados del repositorio Microsoft.Owin.Security.Google ubicado allí: https://katanaproject.codeplex.com/SourceControl/latest#src/Microsoft.Owin.Security.Google/GoogleOAuth2AuthenticationHandler.cs

Necesitará GoogleOAuth2AuthenticationHandler , GoogleOAuth2AuthenticationMiddleware , GoogleOAuth2AuthenticationOptions , GoogleAuthenticationExtensions (tendrá que eliminar los primeros 2 métodos correspondientes a la implementación de Google OpenID), IGoogleOAuth2AuthenticationProvider , GoogleOAuth2ReturnEndpointContext , GoogleOAuth2AuthenticationProvider , GoogleOAuth2AuthenticatedContext y GoogleOAuth2ApplyRedirectContext . Una vez que haya insertado estos archivos en su proyecto de alojamiento "webpics.com", cámbiele el nombre correspondiente y cambie la autorización y acceda a la URL de los puntos finales de token en GoogleOAuth2AuthenticationHandler para que coincida con los que ha definido en su servidor de autorización OAuth2.

Luego, agregue el método de Uso de sus GoogleAuthenticationExtensions de GoogleAuthenticationExtensions de GoogleAuthenticationExtensions renombradas / personalizadas a su clase de inicio de OWIN. Sugiero usar AuthenticationMode.Active para que sus usuarios sean redirigidos directamente a su punto final de autorización API OAuth2. Por lo tanto, debe suprimir la ida y vuelta "api.prettypictures.com/Account/ExternalLogins" y dejar que el middleware del cliente OAuth2 modifique 401 respuestas para redirigir a los clientes a su API.

Buena suerte. Y no lo dudes si necesitas más información;)

Me gustaría la siguiente arquitectura (inventé el nombre del producto para este ejemplo):

Aplicación Web API 2 ejecutándose en un servidor http://api.prettypictures.com

Aplicación de cliente MVC 5 ejecutándose en otro servidor http://www.webpics.com

Me gustaría que la aplicación cliente de www.webpics.com use la API Pretty Pictures para:

  • Registre cuentas nuevas con nombre de usuario y contraseña
  • Registre nuevas cuentas con Facebook / Google / Twitter / Microsoft
  • Iniciar sesión
  • Recuperar imágenes

Todo lo anterior funciona excepto registrar cuentas externas con Facebook, Google, etc.

No puedo calcular el flujo correcto para crear una cuenta externa desde un usuario de cliente separado de la API.

Estudié la mayoría de los documentos disponibles en el flujo de autenticación, como este:

He leído casi todo lo que puedo sobre el nuevo modelo de Identidad en OWIN.

He examinado la plantilla SPA en Visual Studio 2013. Demuestra cómo hacer la mayor parte de lo que necesito, pero solo cuando el cliente y la API están en el mismo host; si quiero que varios clientes accedan a mi API y pueda permitir que los usuarios se registren a través de Google, etc., no funciona y, por lo que puedo decir, el flujo de autenticación de OWIN se rompe.

Aquí está el flujo hasta el momento:

  • El usuario navega a www.webpics.com/Login
  • www.webpics.com llama a api.prettypictures.com/Account/ExternalLogins (con un returnUrl configurado para regresar a una devolución de llamada en www.webpics.com ) y muestra los enlaces resultantes al usuario
  • El usuario hace clic en "Google"
  • El navegador redirige a api.prettypictures.com/Account/ExternalLogin con el nombre del proveedor, etc.
  • La acción ExternalLogin de la API crea un desafío para google.com
  • El navegador se redirige a google.com
  • El usuario ingresa su nombre de usuario y contraseña (si aún no ha iniciado sesión en google.com )
  • google.com ahora presenta la autorización de seguridad: "api.prettypictures.com" desea acceder a su dirección de correo electrónico, nombre, esposa, hijos, etc. ¿Esto está bien?
  • El usuario hace clic en "Sí" y vuelve a api.prettypictures.com/Account/ExternalLogin con una cookie que Google ha configurado.

Aquí es donde me tengo atascado. Lo que se supone que sucederá a continuación es que de alguna manera se debe notificar a la aplicación del cliente que el usuario se ha autenticado con éxito con google.com y se le debe dar un código de acceso de uso único para intercambiar un token de acceso más adelante. La aplicación cliente debe tener la oportunidad, si es necesario, de solicitar al usuario un nombre de usuario para asociar con su inicio de sesión de google.com .

No sé cómo facilitar esto.

De hecho, en este punto el navegador termina sentado en el punto final api.prettypictures.com/Account/ExternalLogin después de la devolución de llamada de Google. La API ha iniciado sesión en Google, pero el cliente no sabe cómo lidiar con eso. ¿Debo volver a conectar esa cookie a www.webpics.com ?

En la aplicación SPA, se realiza a través de AJAX y google.com devolverá un token como un fragmento de URL y todo funciona bien porque todo se ubica en un dominio. Pero eso desafía mucho el punto de tener una "API" que múltiples clientes pueden usar completamente.

¡Ayuda!