| 1 | GOOGLE_CLIENT_ID=你的 Google Client ID |
| 2 | GOOGLE_CLIENT_SECRET=你的 Google Client Secret |
| 3 |
flask_google_oauth_example.py
· 2.3 KiB · Python
Brut
from flask import Flask, redirect, url_for, session, request
from authlib.integrations.flask_client import OAuth
import os
from dotenv import load_dotenv
# 載入環境變數
load_dotenv()
app = Flask(__name__)
app.secret_key = os.getenv("FLASK_SECRET_KEY") # 從環境變數讀取
oauth = OAuth(app)
# 建立 Keycloak 的 OIDC 設定
# 透過 server_metadata_url 自動取得 OIDC Discovery 設定
keycloak = oauth.register(
name='keycloak',
client_id=os.getenv("KEYCLOAK_CLIENT_ID"),
client_secret=os.getenv("KEYCLOAK_CLIENT_SECRET"),
server_metadata_url=f"{os.getenv('KEYCLOAK_BASE_URL')}/realms/{os.getenv('KEYCLOAK_REALM')}/.well-known/openid-configuration",
client_kwargs={
'scope': 'openid profile email', # 根據需求調整
}
)
@app.route('/')
def homepage():
return '歡迎!<a href="/login">使用 Keycloak 登入</a>'
@app.route('/login')
def login():
# 生成一個隨機 nonce 作為一次性驗證令牌
nonce = os.urandom(16).hex()
session['nonce'] = nonce
return keycloak.authorize_redirect(
redirect_uri=url_for('auth', _external=True),
nonce=nonce
)
@app.route('/auth')
def auth():
# 取得 Keycloak 回傳的參數並換取 token
token = keycloak.authorize_access_token()
nonce = session.get('nonce')
user_info = keycloak.parse_id_token(token, nonce=nonce)
# 將使用者資訊存入 session,並清除 nonce 避免重複驗證
session['user'] = user_info
session.pop('nonce', None)
# 重導到乾淨的頁面
return redirect(url_for('profile'))
@app.route('/profile')
def profile():
user_info = session.get('user')
if user_info:
return f"歡迎, {user_info.get('name', '使用者')}!<br><a href='/logout'>登出</a>"
return redirect(url_for('homepage'))
@app.route('/logout')
def logout():
# 清除 session 中的所有資料
session.clear()
# 組成 Keycloak 的登出 URL
logout_url = f"{os.getenv('KEYCLOAK_BASE_URL')}/realms/{os.getenv('KEYCLOAK_REALM')}/protocol/openid-connect/logout"
# 登出後重導回首頁
redirect_uri = url_for('homepage', _external=True)
# 將重導 URI 作為參數附加到 Keycloak 登出 URL 上
return redirect(f"{logout_url}?redirect_uri={redirect_uri}")
if __name__ == '__main__':
app.run(debug=True)
| 1 | from flask import Flask, redirect, url_for, session, request |
| 2 | from authlib.integrations.flask_client import OAuth |
| 3 | import os |
| 4 | from dotenv import load_dotenv |
| 5 | |
| 6 | # 載入環境變數 |
| 7 | load_dotenv() |
| 8 | |
| 9 | app = Flask(__name__) |
| 10 | app.secret_key = os.getenv("FLASK_SECRET_KEY") # 從環境變數讀取 |
| 11 | |
| 12 | oauth = OAuth(app) |
| 13 | |
| 14 | # 建立 Keycloak 的 OIDC 設定 |
| 15 | # 透過 server_metadata_url 自動取得 OIDC Discovery 設定 |
| 16 | keycloak = oauth.register( |
| 17 | name='keycloak', |
| 18 | client_id=os.getenv("KEYCLOAK_CLIENT_ID"), |
| 19 | client_secret=os.getenv("KEYCLOAK_CLIENT_SECRET"), |
| 20 | server_metadata_url=f"{os.getenv('KEYCLOAK_BASE_URL')}/realms/{os.getenv('KEYCLOAK_REALM')}/.well-known/openid-configuration", |
| 21 | client_kwargs={ |
| 22 | 'scope': 'openid profile email', # 根據需求調整 |
| 23 | } |
| 24 | ) |
| 25 | |
| 26 | @app.route('/') |
| 27 | def homepage(): |
| 28 | return '歡迎!<a href="/login">使用 Keycloak 登入</a>' |
| 29 | |
| 30 | @app.route('/login') |
| 31 | def login(): |
| 32 | # 生成一個隨機 nonce 作為一次性驗證令牌 |
| 33 | nonce = os.urandom(16).hex() |
| 34 | session['nonce'] = nonce |
| 35 | return keycloak.authorize_redirect( |
| 36 | redirect_uri=url_for('auth', _external=True), |
| 37 | nonce=nonce |
| 38 | ) |
| 39 | |
| 40 | @app.route('/auth') |
| 41 | def auth(): |
| 42 | # 取得 Keycloak 回傳的參數並換取 token |
| 43 | token = keycloak.authorize_access_token() |
| 44 | nonce = session.get('nonce') |
| 45 | user_info = keycloak.parse_id_token(token, nonce=nonce) |
| 46 | # 將使用者資訊存入 session,並清除 nonce 避免重複驗證 |
| 47 | session['user'] = user_info |
| 48 | session.pop('nonce', None) |
| 49 | # 重導到乾淨的頁面 |
| 50 | return redirect(url_for('profile')) |
| 51 | |
| 52 | @app.route('/profile') |
| 53 | def profile(): |
| 54 | user_info = session.get('user') |
| 55 | if user_info: |
| 56 | return f"歡迎, {user_info.get('name', '使用者')}!<br><a href='/logout'>登出</a>" |
| 57 | return redirect(url_for('homepage')) |
| 58 | |
| 59 | @app.route('/logout') |
| 60 | def logout(): |
| 61 | # 清除 session 中的所有資料 |
| 62 | session.clear() |
| 63 | |
| 64 | # 組成 Keycloak 的登出 URL |
| 65 | logout_url = f"{os.getenv('KEYCLOAK_BASE_URL')}/realms/{os.getenv('KEYCLOAK_REALM')}/protocol/openid-connect/logout" |
| 66 | |
| 67 | # 登出後重導回首頁 |
| 68 | redirect_uri = url_for('homepage', _external=True) |
| 69 | |
| 70 | # 將重導 URI 作為參數附加到 Keycloak 登出 URL 上 |
| 71 | return redirect(f"{logout_url}?redirect_uri={redirect_uri}") |
| 72 | |
| 73 | if __name__ == '__main__': |
| 74 | app.run(debug=True) |
| 75 | |
| 76 |