如何创建 SSO 按钮 – Flask 登录教程

已发表: 2022-03-11

应用程序通常需要登录功能,以便用户可以保存数据、创建自己的配置文件,或者可能只是限制对敏感资源的访问。 在现代应用程序中,用户希望拥有与登录相关的标准功能,例如电子邮件验证、密码重置或多因素身份验证。 这些功能虽然是必要的,但并不容易做好,而且通常不是应用程序的主要业务。

在用户方面,他们可能不想经历冗长的注册过程,因为他们需要创建并记住另一个电子邮件和密码对。 如果没有适当的密码管理器,用户往往会重复使用相同的密码,这在安全性方面很糟糕。

单点登录 (SSO),通常被用户称为使用社交媒体按钮登录,是为了解决这个问题而发明的。 对于用户来说,不用经历另一个痛苦的注册过程很容易。 对于企业来说,为用户消除摩擦总是一个巨大的胜利——对于开发人员来说,所有与登录相关的功能现在都委托给身份提供者(Facebook、Google、Twitter 等),这意味着更少的代码! 您的应用只是信任身份提供者来完成其验证用户身份的工作。

SSO 通常由 OpenId Connect (OIDC) 或 SAML 协议提供支持。 SAML 主要用于企业应用程序。 OIDC 建立在 OAuth2 之上,并被 Facebook、Google 等社交身份提供商使用。在这篇文章中,我们将重点介绍 OIDC/OAuth2 协议。

在这个 Flask 登录教程中,我们将编写一个分步指南,以将 SSO 登录按钮添加到使用 SimpleLogin 和 Facebook 作为身份提供者的 Flask 应用程序中。 这可以在不使用任何外部库的情况下完成,但为了简化 OAuth 的复杂性,我们将使用 Requests-OAuthlib,一个集成 OAuth 提供程序的库。 如果您有兴趣从头开始实施 SSO,请查看实施 SSO 登录 - 原始方式

在本文的最后,你应该有一个 Flask 应用程序,它具有以下页面:

  • 带有登录按钮的主页
  • 用户信息页面,成功登录后,用户将能够看到诸如姓名、电子邮件和头像等信息

本教程的所有代码都可以在 flask-social-login-example 存储库中找到。

此处还提供了演示。 随意在 Glitch 上重新混合代码。

第 1 步:引导 Flask 应用程序

安装flaskRequests-OAuthlib 。 您还可以使用virtualenvpipenv来隔离环境。

点安装烧瓶请求_oauthlib

创建app.py和在主页显示登录按钮的路由:

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

让我们运行这个应用程序并验证一切正常:

 python app.py

打开 http://localhost:5000 时应该会看到此页面。 完整的代码在 step1.py 上。

使用 SimpleLogin 登录

第 2 步:身份提供者凭证

目前有数百个(如果不是数千个)身份提供者,其中最受欢迎的是 Facebook、Google、GitHub 和 Instagram。 对于这篇文章,选择 SimpleLogin 是因为它对开发人员友好。 不过,相同的代码适用于任何 OAuth2 身份提供者。 (免责声明:我碰巧是 SimpleLogin 的联合创始人,这可能是我决定使用它的一个因素。)

如果您还没有帐户,请前往 SimpleLogin 并创建一个帐户,然后在“开发人员”选项卡中创建一个新应用程序。

在应用详情页面,请将您的 AppID 和 AppSecret 复制并保存到变量环境中。 在 OAuth 术语中,客户端实际上是指第三方应用程序,即您的应用程序。 我们可以将这些值直接放在代码中,但最好将凭据保存到环境变量中。 这也是十二因缘中的第三因缘。

OAuth2 设置

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

app.py中,请在文件顶部添加这些行以获取client idclient secret

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

还请在app.py顶部添加这些 OAuth URL,这些 URL 将在下一步中使用。 它们也可以在 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"

由于我们现在不想担心设置 SSL,让我们告诉Requests-OAuthlib使用纯 HTTP 是可以的:

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

像往常一样,这一步的代码在 step2.py 上。

第 3 步:登录重定向

当用户点击登录按钮时:

  1. 用户将被重定向到身份登录提供者授权页面,询问用户是否想与您的应用共享他们的信息。
  2. 在用户批准后,他们将被重定向回您的应用程序的页面以及 URL 中的code ,您的应用程序将使用该代码来交换access token ,以便您稍后从服务提供商处获取用户信息。

因此,我们需要两条路由:将用户重定向到身份提供者的login路由和接收code并将其交换为access tokencallback路由。 回调路由还负责显示用户信息。

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

单击登录按钮应该会带您完成以下流程。 完整代码可以在 GitHub 上的 step3.py 中找到。

使用 SimpleLogin 登录以允许访问用户信息

使用 Facebook 登录

Facebook、Google 和 Twitter 登录的设置有点复杂,需要设置 SSL 或选择正确的范围等额外步骤。 这些超出了本文的范围。

除了复杂的 UI 之外,集成 Facebook 最困难的部分可能是找到一种在本地通过 HTTPS 为您的 Web 应用程序提供服务的方法,因为新版本的 Facebook SDK 不允许本地纯 HTTP。 我推荐使用 Ngrok,这是一个免费工具,可以快速获取 HTTPS URL。

第 1 步:创建 Facebook 应用

请前往https://developers.facebook.com并创建一个新应用:

创建一个新的应用程序 ID

然后在下一个屏幕上选择“集成 Facebook 登录”:

集成 Facebook 登录

第 2 步:Facebook OAuth 凭据

点击左侧的“设置/基本”,复制App IDApp Secret 。 它们实际上是 OAuth client-idclient-secret

基本设置

更新client-idclient-secret

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

更新 AUTHORIZATION_BASE_URL 和 TOKEN_URL:

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

主页:

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

第 3 步:登录和回调端点

如果使用ngrok http 5000命令在ngrok后面提供应用程序,我们需要将当前 URL 设置为 ngrok URL。

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

请确保将 URL 添加到您的 Facebook 登录/设置、有效 OAuth 重定向 URI 设置:

有效的 OAuth 重定向 URI

为了访问用户电子邮件,您需要将email添加到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)

由于 Facebook 需要进行合规性修复,因此callback路由要复杂一些:

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

现在,当单击使用 Facebook 登录时,您应该能够完成整个流程。

使用 Facebook 流程登录

完整的代码在 facebook.py 上。

结论

恭喜——您已成功将 SSO 登录集成到 Flask 应用程序中!

为简单起见,本教程未提及范围和状态等其他 OAuth 概念,这些概念对于防御跨站点请求伪造攻击很重要。 您可能还需要将用户信息存储在本文未涉及的数据库中。

该应用程序还需要在生产环境中的 https 上提供服务,今天使用 Let's Encrypt 可以很容易地做到这一点。

快乐 OAuthing!