Como criar um botão SSO – um tutorial de login do Flask

Publicados: 2022-03-11

Os aplicativos geralmente precisam da funcionalidade de login para que os usuários possam salvar dados, criar seus próprios perfis ou talvez apenas restringir o acesso a recursos confidenciais. Em um aplicativo moderno, os usuários esperam ter recursos padrão relacionados ao login, como verificação de e-mail, redefinição de senha ou autenticação multifator. Esses recursos, embora necessários, não são fáceis de acertar e geralmente não são o principal negócio do aplicativo.

Do lado do usuário, eles podem não querer passar pelo longo processo de registro, pois precisam criar e lembrar de outro par de e-mail e senha. Sem um gerenciador de senhas adequado, os usuários tendem a reutilizar a mesma senha, o que é terrível em termos de segurança.

O logon único (SSO), mais conhecido pelos usuários como login com botões de mídia social , foi inventado como uma solução para esse problema. Para os usuários, não passar por outro processo de registro doloroso foi fácil. Para as empresas, remover o atrito para os usuários é sempre uma grande vitória - e, para os desenvolvedores, todos os recursos relacionados ao login agora são delegados ao provedor de identidade (Facebook, Google, Twitter etc.), o que significa menos código! Seu aplicativo simplesmente confia no provedor de identidade para fazer seu trabalho de verificar a identidade do usuário.

O SSO geralmente é alimentado pelo protocolo OpenId Connect (OIDC) ou SAML. SAML é usado principalmente em aplicativos corporativos. O OIDC é construído em cima do OAuth2 e usado por provedores de identidade social como Facebook, Google, etc. Neste post, vamos nos concentrar no protocolo OIDC/OAuth2.

Neste tutorial de login do Flask, escreveremos um guia passo a passo para adicionar um botão de login SSO em um aplicativo Flask com SimpleLogin e Facebook como provedor de identidade. Isso pode ser feito sem usar nenhuma biblioteca externa, mas para simplificar os meandros do OAuth, usaremos Requests-OAuthlib, uma biblioteca para integrar provedores OAuth. Se você estiver interessado em implementar o SSO do zero, confira Implementar logon de SSO – o caminho bruto .

No final deste artigo, você deve ter um aplicativo Flask que tenha as seguintes páginas:

  • Página inicial com botões de login
  • Página de informações do usuário onde, após o login bem-sucedido, o usuário poderá ver informações como nome, e-mail e avatar

Todo o código para este tutorial pode ser encontrado no repositório flask-social-login-example.

Uma demonstração também está disponível aqui. Sinta-se à vontade para remixar o código no Glitch.

Etapa 1: aplicativo Bootstrap Flask

Instale o flask e Requests-OAuthlib . Você também pode usar virtualenv ou pipenv para isolar o ambiente.

pip instala o frasco requests_oauthlib

Crie app.py e a rota que exibe um botão de login na página inicial:

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

Vamos executar este aplicativo e verificar se tudo está funcionando bem:

 python app.py

Você deve ver esta página ao abrir http://localhost:5000. O código completo está em step1.py.

Entrar com SimpleLogin

Etapa 2: credencial do provedor de identidade

Atualmente, existem centenas (se não milhares) de provedores de identidade, sendo os mais populares Facebook, Google, GitHub e Instagram. Para este post, o SimpleLogin foi escolhido por ser amigável ao desenvolvedor. No entanto, o mesmo código funcionará com qualquer provedor de identidade OAuth2. (Isenção de responsabilidade: sou o cofundador do SimpleLogin, o que - ahem - pode ter sido um fator na minha decisão de usá-lo.)

Por favor, vá para SimpleLogin e crie uma conta se você ainda não tiver uma, então crie um novo aplicativo na guia Desenvolvedor.

Na página de detalhes do aplicativo, copie seu AppID e AppSecret e salve-os no ambiente variável. Na terminologia OAuth, cliente na verdade significa um aplicativo de terceiros, ou seja, seu aplicativo. Podemos colocar esses valores diretamente no código, mas é uma boa prática salvar credenciais em variáveis ​​de ambiente. Este também é o terceiro fator nos Doze Fatores.

Configurações OAuth2

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

Em app.py , adicione estas linhas no topo do arquivo para obter client id do client secret .

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

Adicione também esses URLs OAuth na parte superior de app.py que serão usados ​​na próxima etapa. Eles também podem ser copiados na página de endpoints 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 não queremos nos preocupar em configurar o SSL agora, digamos ao Requests-OAuthlib que não há problema em usar HTTP simples:

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

Como de costume, o código para esta etapa está em step2.py.

Etapa 3: redirecionamento de login

Quando um usuário clica no botão de login:

  1. O usuário será redirecionado para a página de autorização do provedor de login de identidade perguntando se o usuário deseja compartilhar suas informações com seu aplicativo.
  2. Após a aprovação do usuário, eles serão redirecionados de volta para uma página em seu aplicativo junto com um code na URL que seu aplicativo usará para trocar por um access token que permite que você obtenha informações do usuário do provedor de serviços posteriormente.

Precisamos, portanto, de duas rotas: uma rota de login que redireciona o usuário para o provedor de identidade e uma rota de callback de chamada que recebe o code e o troca por access token . A rota de retorno de chamada também é responsável por exibir as informações do usuário.

 @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> """

Clicar no botão de login deve levá-lo ao seguinte fluxo. O código completo pode ser encontrado no GitHub em step3.py.

Faça login com SimpleLogin para permitir informações do usuário

Entrar com o Facebook

A configuração do login do Facebook, Google e Twitter é um pouco complexa e requer etapas adicionais, como configurar o SSL ou escolher os escopos corretos. Estes estão além do escopo deste artigo.

Além de uma interface de usuário sofisticada, a parte mais difícil de integrar o Facebook pode ser encontrar uma maneira de servir seu aplicativo da Web em HTTPS localmente, pois a nova versão do SDK do Facebook não permite HTTP simples local. Eu recomendo usar o Ngrok, uma ferramenta gratuita para ter um URL HTTPS rápido.

Etapa 1: crie um aplicativo do Facebook

Acesse https://developers.facebook.com e crie um novo aplicativo:

Criar um novo ID de aplicativo

Em seguida, escolha “Integrar Login do Facebook” na próxima tela:

Integrar login do Facebook

Etapa 2: credencial OAuth do Facebook

Clique em “Settings/Basic” à esquerda e copie o App ID e App Secret . Na verdade, eles são client-id e client-secret OAuth.

Configurações básicas

Atualize o client-id e client-secret .

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

Atualize AUTHORIZATION_BASE_URL e TOKEN_URL:

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

A página inicial:

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

Etapa 3: pontos de extremidade de login e retorno de chamada

Se o aplicativo for servido por trás do ngrok usando o comando ngrok http 5000 , precisamos definir o URL atual para o URL do ngrok.

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

Certifique-se de adicionar o URL ao seu login/configurações do Facebook, configuração válida de URIs de redirecionamento OAuth:

URIs de redirecionamento OAuth válidos

Para ter acesso a um e-mail de usuário, você precisa adicionar o e- email ao 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)

A rota de callback de chamada é um pouco mais complexa, pois o Facebook exige uma correção de conformidade:

 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> """

Agora, ao clicar em Login com o Facebook, você poderá percorrer todo o fluxo.

Processo de login com o Facebook

O código completo está em facebook.py.

Conclusão

Parabéns — você integrou com sucesso o login SSO em um aplicativo Flask!

Para simplificar, este tutorial não menciona outros conceitos de OAuth, como escopo e estado, que são importantes para se defender contra ataques de falsificação de solicitação entre sites. Você provavelmente também precisaria armazenar as informações do usuário em um banco de dados que não é abordado neste artigo.

O aplicativo também precisa ser servido em https na produção, o que pode ser feito facilmente hoje com o Let's Encrypt.

Feliz OAuthing!