如何創建 SSO 按鈕 – Flask 登錄教程
已發表: 2022-03-11應用程序通常需要登錄功能,以便用戶可以保存數據、創建自己的配置文件,或者可能只是限制對敏感資源的訪問。 在現代應用程序中,用戶希望擁有與登錄相關的標準功能,例如電子郵件驗證、密碼重置或多因素身份驗證。 這些功能雖然是必要的,但並不容易做好,而且通常不是應用程序的主要業務。
在用戶方面,他們可能不想經歷冗長的註冊過程,因為他們需要創建並記住另一個電子郵件和密碼對。 如果沒有適當的密碼管理器,用戶往往會重複使用相同的密碼,這在安全性方面很糟糕。
單點登錄 (SSO),通常被用戶稱為使用社交媒體按鈕登錄,是為了解決這個問題而發明的。 對於用戶來說,不用經歷另一個痛苦的註冊過程很容易。 對於企業來說,為用戶消除摩擦總是一個巨大的勝利——對於開發人員來說,所有與登錄相關的功能現在都委託給身份提供者(Facebook、谷歌、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 應用程序
安裝flask
和Requests-OAuthlib
。 您還可以使用virtualenv
或pipenv
來隔離環境。
點安裝燒瓶請求_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 上。
第 2 步:身份提供者憑證
目前有數百個(如果不是數千個)身份提供者,其中最受歡迎的是 Facebook、Google、GitHub 和 Instagram。 對於這篇文章,選擇 SimpleLogin 是因為它對開發人員友好。 不過,相同的代碼適用於任何 OAuth2 身份提供者。 (免責聲明:我碰巧是 SimpleLogin 的聯合創始人,這可能是我決定使用它的一個因素。)
如果您還沒有帳戶,請前往 SimpleLogin 並創建一個帳戶,然後在“開發人員”選項卡中創建一個新應用程序。
在應用詳情頁面,請將您的 AppID 和 AppSecret 複製並保存到變量環境中。 在 OAuth 術語中,客戶端實際上是指第三方應用程序,即您的應用程序。 我們可以將這些值直接放在代碼中,但最好將憑據保存到環境變量中。 這也是十二因緣中的第三因緣。
export CLIENT_ID={your AppID} export CLIENT_SECRET={your AppSecret}
在app.py
中,請在文件頂部添加這些行以獲取client id
和client 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 步:登錄重定向
當用戶點擊登錄按鈕時:
- 用戶將被重定向到身份登錄提供者授權頁面,詢問用戶是否想與您的應用共享他們的信息。
- 在用戶批准後,他們將被重定向回您的應用程序的頁面以及 URL 中的
code
,您的應用程序將使用該代碼來交換access token
,以便您稍後從服務提供商處獲取用戶信息。
因此,我們需要兩條路由:將用戶重定向到身份提供者的login
路由和接收code
並將其交換為access token
的callback
路由。 回調路由還負責顯示用戶信息。
@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 中找到。

使用 Facebook 登錄
Facebook、Google 和 Twitter 登錄的設置有點複雜,需要設置 SSL 或選擇正確的範圍等額外步驟。 這些超出了本文的範圍。
除了複雜的 UI 之外,集成 Facebook 最困難的部分可能是找到一種在本地通過 HTTPS 為您的 Web 應用程序提供服務的方法,因為新版本的 Facebook SDK 不允許本地純 HTTP。 我推薦使用 Ngrok,這是一個免費工具,可以快速獲取 HTTPS URL。
第 1 步:創建 Facebook 應用
請前往https://developers.facebook.com
並創建一個新應用:
然後在下一個屏幕上選擇“集成 Facebook 登錄”:
第 2 步:Facebook OAuth 憑據
點擊左側的“設置/基本”,複製App ID和App Secret 。 它們實際上是 OAuth client-id
和client-secret
。
更新client-id
和client-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 設置:
為了訪問用戶電子郵件,您需要將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.py 上。
結論
恭喜——您已成功將 SSO 登錄集成到 Flask 應用程序中!
為簡單起見,本教程未提及範圍和狀態等其他 OAuth 概念,這些概念對於防禦跨站點請求偽造攻擊很重要。 您可能還需要將用戶信息存儲在本文未涉及的數據庫中。
該應用程序還需要在生產環境中的 https 上提供服務,今天使用 Let's Encrypt 可以很容易地做到這一點。
快樂 OAuthing!