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')) if __name__ == '__main__': app.run(debug=True)