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 '歡迎!使用 Keycloak 登入'
@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', '使用者')}!
登出"
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)