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)