Cómo crear un botón SSO: un tutorial de inicio de sesión de Flask

Publicado: 2022-03-11

Las aplicaciones a menudo necesitan la funcionalidad de inicio de sesión para que los usuarios puedan guardar datos, crear sus propios perfiles o tal vez solo para restringir el acceso a recursos confidenciales. En una aplicación moderna, los usuarios esperan tener funciones estándar relacionadas con el inicio de sesión, como verificación de correo electrónico, restablecimiento de contraseña o autenticación de múltiples factores. Estas características, aunque necesarias, no son fáciles de hacer bien y, por lo general, no son el negocio principal de la aplicación.

Por el lado del usuario, es posible que tampoco deseen pasar por el largo proceso de registro, ya que necesitan crear y recordar otro par de correo electrónico y contraseña. Sin un administrador de contraseñas adecuado, los usuarios tienden a reutilizar la misma contraseña, lo cual es terrible en términos de seguridad.

El inicio de sesión único (SSO), conocido principalmente por los usuarios como inicio de sesión con botones de redes sociales , se inventó como una solución a este problema. Para los usuarios, no pasar por otro doloroso proceso de registro fue fácil. Para las empresas, eliminar la fricción para los usuarios siempre es una gran victoria y, para los desarrolladores, todas las funciones relacionadas con el inicio de sesión ahora se delegan al proveedor de identidad (Facebook, Google, Twitter, etc.), lo que significa menos código. Su aplicación simplemente confía en que el proveedor de identidad haga su trabajo de verificar la identidad del usuario.

SSO generalmente funciona con el protocolo OpenId Connect (OIDC) o SAML. SAML se usa principalmente en aplicaciones empresariales. OIDC se basa en OAuth2 y lo utilizan proveedores de identidad social como Facebook, Google, etc. En esta publicación, nos centraremos en el protocolo OIDC/OAuth2.

En este tutorial de inicio de sesión de Flask, escribiremos una guía paso a paso para agregar un botón de inicio de sesión SSO en una aplicación de Flask con SimpleLogin y Facebook como proveedor de identidad. Esto se puede hacer sin usar ninguna biblioteca externa, pero para simplificar las complejidades de OAuth, usaremos Requests-OAuthlib, una biblioteca para integrar proveedores de OAuth. Si está interesado en implementar SSO desde cero, consulte Implementar inicio de sesión de SSO: la forma original .

Al final de este artículo, debería tener una aplicación Flask que tenga las siguientes páginas:

  • Página de inicio con botones de inicio de sesión
  • Página de información del usuario donde, al iniciar sesión correctamente, el usuario podrá ver información como el nombre, el correo electrónico y el avatar

Todo el código de este tutorial se puede encontrar en el repositorio de Flass-social-login-example.

Una demostración también está disponible aquí. Siéntase libre de remezclar el código en Glitch.

Paso 1: Aplicación Bootstrap Flask

Instale el flask y Requests-OAuthlib . También puede usar virtualenv o pipenv para aislar el entorno.

pip install matraz request_oauthlib

Cree app.py y la ruta que muestra un botón de inicio de sesión en la página de inicio:

 import flask app = flask.Flask(__name__) @app.route("/") def index(): return """ <a href="/login">Login</a> """ if __name__ == '__main__': app.run(debug=True)

Ejecutemos esta aplicación y verifiquemos que todo funcione bien:

 python app.py

Debería ver esta página al abrir http://localhost:5000. El código completo está en step1.py.

Iniciar sesión con SimpleLogin

Paso 2: Credencial de proveedor de identidad

Actualmente hay cientos (si no miles) de proveedores de identidad, siendo los más populares Facebook, Google, GitHub e Instagram. Para esta publicación, se eligió SimpleLogin debido a su facilidad de uso para los desarrolladores. Sin embargo, el mismo código funcionará con cualquier proveedor de identidad OAuth2. (Descargo de responsabilidad: soy el cofundador de SimpleLogin, lo que, ejem, puede haber sido un factor en mi decisión de usarlo).

Diríjase a SimpleLogin y cree una cuenta si aún no tiene una, luego cree una nueva aplicación en la pestaña Desarrollador.

En la página de detalles de la aplicación, copie su AppID y AppSecret y guárdelos en el entorno variable. En la terminología de OAuth, cliente en realidad significa una aplicación de terceros, es decir, su aplicación. Podemos poner estos valores directamente en el código, pero es una buena práctica guardar las credenciales en las variables de entorno. Este es también el tercer factor en Los Doce Factores.

Configuración de OAuth2

 export CLIENT_ID={your AppID} export CLIENT_SECRET={your AppSecret}

En app.py , agregue estas líneas en la parte superior del archivo para obtener client id del client secret del cliente.

 import os CLIENT_ID = os.environ.get("CLIENT_ID") CLIENT_SECRET = os.environ.get("CLIENT_SECRET")

Agregue también estas URL de OAuth en la parte superior de app.py que se usarán en el siguiente paso. También se pueden copiar en la página de puntos finales de OAuth.

 AUTHORIZATION_BASE_URL = "https://app.simplelogin.io/oauth2/authorize" TOKEN_URL = "https://app.simplelogin.io/oauth2/token" USERINFO_URL = "https://app.simplelogin.io/oauth2/userinfo"

Como no queremos preocuparnos por configurar SSL ahora, digámosle a Requests-OAuthlib que está bien usar HTTP simple:

 # This allows us to use a plain HTTP callback os.environ["OAUTHLIB_INSECURE_TRANSPORT"] = "1"

Como de costumbre, el código para este paso está en step2.py.

Paso 3: redirección de inicio de sesión

Cuando un usuario hace clic en el botón de inicio de sesión:

  1. El usuario será redirigido a la página de autorización del proveedor de inicio de sesión de identidad y se le preguntará si desea compartir su información con su aplicación.
  2. Luego de la aprobación del usuario, serán redirigidos a una página en su aplicación junto con un code en la URL que su aplicación usará para intercambiar por un access token que le permitirá obtener información del usuario del proveedor de servicios.

Por lo tanto, necesitamos dos rutas: una ruta de inicio de login que redirige al usuario al proveedor de identidad y una ruta de callback de llamada que recibe el code y lo intercambia por el access token . La ruta de devolución de llamada también es responsable de mostrar la información del usuario.

 @app.route("/login") def login(): simplelogin = requests_oauthlib.OAuth2Session( CLIENT_ID, redirect_uri="http://localhost:5000/callback" ) authorization_url, _ = simplelogin.authorization_url(AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url) @app.route("/callback") def callback(): simplelogin = requests_oauthlib.OAuth2Session(CLIENT_ID) simplelogin.fetch_token( TOKEN_URL, client_secret=CLIENT_SECRET, authorization_response=flask.request.url ) user_info = simplelogin.get(USERINFO_URL).json() return f""" User information: <br> Name: {user_info["name"]} <br> Email: {user_info["email"]} <br> Avatar <img src="{user_info.get('avatar_url')}"> <br> <a href="/">Home</a> """

Al hacer clic en el botón de inicio de sesión debería pasar por el siguiente flujo. El código completo se puede encontrar en GitHub en step3.py.

Inicie sesión con SimpleLogin para permitir la información del usuario

Iniciar sesión con Facebook

La configuración del inicio de sesión de Facebook, Google y Twitter es un poco compleja y requiere pasos adicionales como configurar SSL o elegir los ámbitos correctos. Estos están más allá del alcance de este artículo.

Aparte de una interfaz de usuario sofisticada, la parte más difícil de integrar Facebook podría ser encontrar una manera de servir su aplicación web en HTTPS localmente, ya que la nueva versión del SDK de Facebook no permite HTTP simple local. Recomiendo usar Ngrok, una herramienta gratuita para tener una URL HTTPS rápida.

Paso 1: crea una aplicación de Facebook

Dirígete a https://developers.facebook.com y crea una nueva aplicación:

Crear una nueva ID de aplicación

Luego elija "Integrar inicio de sesión de Facebook" en la siguiente pantalla:

Integrar el inicio de sesión de Facebook

Paso 2: Credencial OAuth de Facebook

Haga clic en "Configuración/Básico" a la izquierda y copie el ID de la aplicación y el Secreto de la aplicación. En realidad, son OAuth client-id y client-secret .

Ajustes básicos

Actualice client-id y client-secret .

 export FB_CLIENT_ID={your facebook AppId} export FB_CLIENT_SECRET={your facebook AppSecret}

Actualice AUTHORIZATION_BASE_URL y TOKEN_URL:

 FB_AUTHORIZATION_BASE_URL = "https://www.facebook.com/dialog/oauth" FB_TOKEN_URL = "https://graph.facebook.com/oauth/access_token"

La página de inicio:

 @app.route("/") def index(): return """ <a href="/fb-login">Login with Facebook</a> """

Paso 3: Puntos finales de inicio de sesión y devolución de llamada

Si la aplicación se sirve detrás de ngrok usando el comando ngrok http 5000 , debemos establecer la URL actual en la URL de ngrok.

 # Your ngrok url, obtained after running "ngrok http 5000" URL = "https://abcdefgh.ngrok.io"

Asegúrese de agregar la URL a su inicio de sesión/configuración de Facebook, configuración de URI de redirección de OAuth válida:

URI de redireccionamiento de OAuth válidos

Para tener acceso al correo electrónico de un usuario, debe agregar el email al scope :

 FB_SCOPE = ["email"] @app.route("/fb-login") def login(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, redirect_uri=URL + "/fb-callback", scope=FB_SCOPE ) authorization_url, _ = facebook.authorization_url(FB_AUTHORIZATION_BASE_URL) return flask.redirect(authorization_url)

La ruta de callback de llamada es un poco más compleja ya que Facebook requiere una solución de cumplimiento:

 from requests_oauthlib.compliance_fixes import facebook_compliance_fix @app.route("/fb-callback") def callback(): facebook = requests_oauthlib.OAuth2Session( FB_CLIENT_ID, scope=FB_SCOPE, redirect_uri=URL + "/fb-callback" ) # we need to apply a fix for Facebook here facebook = facebook_compliance_fix(facebook) facebook.fetch_token( FB_TOKEN_URL, client_secret=FB_CLIENT_SECRET, authorization_response=flask.request.url, ) # Fetch a protected resource, ie user profile, via Graph API facebook_user_data = facebook.get( "https://graph.facebook.com/me?fields=id,name,email,picture{url}" ).json() email = facebook_user_data["email"] name = facebook_user_data["name"] picture_url = facebook_user_data.get("picture", {}).get("data", {}).get("url") return f""" User information: <br> Name: {name} <br> Email: {email} <br> Avatar <img src="{picture_url}"> <br> <a href="/">Home</a> """

Ahora, al hacer clic en Iniciar sesión con Facebook, debería poder seguir todo el proceso.

Iniciar sesión con el proceso de Facebook

El código completo está en facebook.py.

Conclusión

¡Felicitaciones, ha integrado con éxito el inicio de sesión SSO en una aplicación de Flask!

En aras de la simplicidad, este tutorial no menciona otros conceptos de OAuth como el alcance y el estado, que son importantes para defenderse de los ataques de falsificación de solicitudes entre sitios. Probablemente también necesite almacenar la información del usuario en una base de datos que no se trata en este artículo.

La aplicación también debe servirse en https en producción, lo que se puede hacer fácilmente hoy con Let's Encrypt.

¡Feliz OAuthing!