由於現在整合 Facebook Login API 時必須強制使用 HTTPS 以確保 Facebook 使用者的安全性,所以在本機(localhost) 整合 Facebook Login 時稍微會麻煩一些。
本文記錄如何在本機的 Flask 專案整合 Facebook login 。
本文環境
- Python 3.6.5
- macOS 10.14.3
- Flask 1.0.2
申請 Facebook 應用程式
開始本文之前需先至 Facebook for developers 申請應用程式,以取得應用程式編號與應用程式密鑰。
目前整合網頁版的 Facebook login, 通常都會使用 Facebook 所提供的 Javascript 版的 SDK ,詳情請閱讀 搭配 JavaScript SDK 的網頁版「Facebook 登入」 ,故本文就不贅述如何撰寫 Facebook login 的 Javascript 程式碼,
設定有效的 OAuth 重新導向 URI
在網頁上設定好 Facebook login 的 Javascript 程式碼之後,還需要特別至 Facebook for developers 管理介面設定好 有效的 OAuth 重新導向 URI
,該 SDK 才能夠正常運作,這是由於 Facebook SDK 會自動偵測使用者的所在網址是否符合所設定的 URI 才能夠運作。
因為本文希望在本機環境載入 Facebook 登入頁時,由 Facebook 所提供的 Facebook SDK 時能夠正常運作,所以我們將 https://dev.localhost
設定為有效的 OAuth 重新導向 URI (當然各位也可以直接使用 https://localhost
,因為個人比較喜歡用 dev.localhost
區分開發環境,所以本文使用 dev.localhost
作為示範) 。
設定如下圖所示:
產生 dev.localhost 的 SSL 憑證
由於 HTTPS 需要 SSL 憑證,因此利用以下指令產生 dev.localhost
的憑證:
$ openssl req -x509 -out dev.localhost.crt -keyout dev.localhost.key \
-newkey rsa:2048 -nodes -sha256 \
-subj '/CN=dev.localhost' -extensions EXT -config <( \
printf "[dn]\nCN=dev.localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:dev.localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
如果是單純想使用 localhost
的人可以使用以下指令:
$ openssl req -x509 -out localhost.crt -keyout localhost.key \
-newkey rsa:2048 -nodes -sha256 \
-subj '/CN=localhost' -extensions EXT -config <( \
printf "[dn]\nCN=localhost\n[req]\ndistinguished_name = dn\n[EXT]\nsubjectAltName=DNS:localhost\nkeyUsage=digitalSignature\nextendedKeyUsage=serverAuth")
p.s. CN
指的是 Common Name
, 由 host name 加 domain name 所組成。
成功之後會有 2 個檔案產生( dev.localhost.crt
& dev.localhost.key
),這就是建立 HTTPS 環境所需要的憑證與私鑰。
編輯 /etc/hosts
接著編輯 /ect/hosts
添加以下內容:
127.0.0.1 dev.localhost
上述設定的用意是將 dev.localhost
指向 IP 位址 127.0.0.1
,因此當我們在瀏覽器輸入 https://dev.localhost
時,我們就會向本機發出 HTTP 請求。
p.s. 由於 /etc/hosts
原本就有 127.0.0.1 localhost
的設定,因此不需額外添加
架設 Flask server
設定完 Facebook 管理介面與產生 HTTPS 環境所需的憑證之後,最後就輪到 Flask 出場執行 Web sever 囉!
以下是本文的資料夾與檔案結構:
.
├── app/
│ ├── app.py
│ └── templates/
│ └── index.html
├── dev.localhost.crt
└── dev.localhost.key
app/
資料夾內 app.py 是簡單的 Flask 程式,主要用來執行 Web server 並載入 templates/
資料夾內的 index.html
以顯示 Facebook 登入頁給使用者。
app.py
內容如下:
# -*- coding: utf-8 -*-
from flask import Flask
from flask import render_template
def create_app(app_env=None):
flask_app = Flask(__name__)
return flask_app
app = create_app()
@app.route('/')
def index():
return render_template('index.html')
index.html
內容如下(請將 your_app_id
替換成你的應用程式編號):
<html>
<head>
<title>Sign in</title>
</head>
<body>
<script>
(function(d, s, id){
var js, fjs = d.getElementsByTagName(s)[0];
if (d.getElementById(id)) {return;}
js = d.createElement(s); js.id = id;
js.src = "https://connect.facebook.net/en_US/sdk.js";
fjs.parentNode.insertBefore(js, fjs);
}(document, 'script', 'facebook-jssdk'));
function statusChangeCallback(response) {
console.log(response);
}
function checkLoginState() {
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
}
window.fbAsyncInit = function() {
FB.init({
appId : 'your_app_id',
cookie : true,
xfbml : true,
version : 'v3.2'
});
FB.AppEvents.logPageView();
FB.getLoginStatus(function(response) {
statusChangeCallback(response);
});
};
</script>
<fb:login-button
scope="public_profile,email"
onlogin="checkLoginState();">
</fb:login-button>
</body>
</html>
準備好環境之後就能夠用以下指令執行支援 HTTPS 的 Flask server:
$ sudo env FLASK_APP=app.app flask run --cert=dev.localhost.crt --key=dev.localhost.key --port=443
Password:
* Serving Flask app "app.app"
* Environment: production
WARNING: Do not use the development server in a production environment.
Use a production WSGI server instead.
* Debug mode: off
* Running on https://127.0.0.1:443/ (Press CTRL+C to quit)
執行成功後就能夠用瀏覽器打開 https://dev.localhost
看到 Facebook 的登入按鈕,並且能夠進行登入:
最後只要修改 index.html
內的 statusChangeCallback
函式,利用從 Facebook 拿到的 access token 呼叫 Facebook API 達成你所需要的目標。
以上就是在本機利用 Flask 整合 Facebook login 的過程! Happy Coding!
References
https://letsencrypt.org/docs/certificates-for-localhost/