Last active 9 months ago

此程式碼展示如何在 Flask 應用中整合 Keycloak,實現使用者認證、登入及使用者資訊取得。

timmy revised this gist 9 months ago. Go to revision

2 files changed, 64 insertions

.env(file created)

@@ -0,0 +1,5 @@
1 + KEYCLOAK_BASE_URL=http://192.168.42.102:8080
2 + KEYCLOAK_REALM=MyRealm
3 + KEYCLOAK_CLIENT_ID=my-app
4 + KEYCLOAK_CLIENT_SECRET=DgL6JibOXWzMWvQ2hZOLoeOcg0IfSVsU
5 + FLASK_SECRET_KEY=your_flask_secret_key

app.py(file created)

@@ -0,0 +1,59 @@
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 + load_dotenv()
7 +
8 + app = Flask(__name__)
9 + app.secret_key = os.getenv("FLASK_SECRET_KEY") # 從環境變數讀取
10 +
11 + oauth = OAuth(app)
12 +
13 + # 建立 Keycloak 的 OIDC 設定
14 + # 透過 server_metadata_url 來自動取得 OIDC Discovery 設定
15 + keycloak = oauth.register(
16 + name='keycloak',
17 + client_id=os.getenv("KEYCLOAK_CLIENT_ID"),
18 + client_secret=os.getenv("KEYCLOAK_CLIENT_SECRET"),
19 + server_metadata_url=f"{os.getenv('KEYCLOAK_BASE_URL')}/realms/{os.getenv('KEYCLOAK_REALM')}/.well-known/openid-configuration",
20 + client_kwargs={
21 + 'scope': 'openid profile email', # 根據需求調整
22 + }
23 + )
24 +
25 + @app.route('/')
26 + def homepage():
27 + return '歡迎!<a href="/login">使用 Keycloak 登入</a>'
28 +
29 + @app.route('/login')
30 + def login():
31 + # 生成一個隨機 nonce,作為一次性驗證令牌
32 + nonce = os.urandom(16).hex()
33 + session['nonce'] = nonce
34 + return keycloak.authorize_redirect(
35 + redirect_uri=url_for('auth', _external=True),
36 + nonce=nonce
37 + )
38 +
39 + @app.route('/auth')
40 + def auth():
41 + # 取得 Keycloak 回傳的參數並換取 token
42 + token = keycloak.authorize_access_token()
43 + nonce = session.get('nonce')
44 + user_info = keycloak.parse_id_token(token, nonce=nonce)
45 + # 將使用者資訊存入 session,並清除 nonce,避免重複驗證
46 + session['user'] = user_info
47 + session.pop('nonce', None)
48 + # 重導到乾淨的頁面
49 + return redirect(url_for('profile'))
50 +
51 + @app.route('/profile')
52 + def profile():
53 + user_info = session.get('user')
54 + if user_info:
55 + return f"歡迎, {user_info.get('name', '使用者')}!"
56 + return redirect(url_for('homepage'))
57 +
58 + if __name__ == '__main__':
59 + app.run(debug=True)
Newer Older