AI <<
Previous Next >> Topics
Project
修課學員經由 @nfu.edu.tw 網域, 可利用"學號@nfu.edu.tw"經由 https://login.microsoftonline.com/ 登入 MS 365.
登入後, 使用者可以利用"應用程式註冊"建立應用程式.
所註冊的延伸應用程式則可以利用 Microsoft Online 主機所提供的 OAuth2 API 程式庫, 取得登入者的 profile.
經由上列步驟取得登入者的 profile 後, 延伸應用程式可設法讀取課程學員的作業倉儲與網站連結.
from flask import Flask, redirect, request, session, url_for
import requests
import json
app = Flask(__name__)
app.secret_key = 'your_secret_key' # 用於 Flask session 的秘密金鑰
# 替換成你的 Azure AD 應用程式資訊
'''
取得 CLIENT_ID(應用程式 (用戶端) 識別碼)
進入你的應用程式註冊細節頁面。
在「概觀」分頁中,找到「應用程式 (用戶端) 識別碼」(Application (client) ID)。
複製這個 GUID 字串,填入 CLIENT_ID = '這個字串'
建立 CLIENT_SECRET(用戶端密碼)
在應用程式註冊的左側欄選單選擇「憑證與秘密」(Certificates & secrets)。
點選「新增用戶端密碼」(New client secret)。
填寫描述與存續期限,按下「新增」。
建立後會出現一個「值」(Value),這才是 CLIENT_SECRET,只會顯示一次,請立即複製起來,填入 CLIENT_SECRET = '這個值'
取得 TENANT_ID(目錄 (租用戶) 識別碼)
同樣在「概觀」分頁中,找到「目錄 (租用戶) 識別碼」(Directory (tenant) ID)。
複製這個 GUID 字串,填入 TENANT_ID = '這個字串'
'''
CLIENT_ID = 'your_CLIENT_ID'
CLIENT_SECRET = 'your_CLIENT_SECRET'
TENANT_ID = 'your_TENANT_ID'
AUTHORITY = f'https://login.microsoftonline.com/{TENANT_ID}'
REDIRECT_URI = 'https://your_server_domain/callback'
SCOPE = 'User.Read'
# 用於登錄和取得授權碼
@app.route('/')
def index():
auth_url = (f'{AUTHORITY}/oauth2/v2.0/authorize'
f'?client_id={CLIENT_ID}'
f'&response_type=code'
f'&redirect_uri={REDIRECT_URI}'
f'&response_mode=query'
f'&scope={SCOPE}')
return redirect(auth_url)
# 處理回調和交換授權碼
@app.route('/callback')
def callback():
code = request.args.get('code')
token_url = f'{AUTHORITY}/oauth2/v2.0/token'
token_data = {
'grant_type': 'authorization_code',
'code': code,
'redirect_uri': REDIRECT_URI,
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'scope': SCOPE
}
token_r = requests.post(token_url, data=token_data)
token_r.raise_for_status()
tokens = token_r.json()
session['access_token'] = tokens['access_token']
return redirect(url_for('profile'))
# 使用訪問令牌呼叫 Microsoft Graph API 來獲取用戶資料
@app.route('/profile')
def profile():
access_token = session.get('access_token')
if not access_token:
return redirect(url_for('index'))
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
graph_url = 'https://graph.microsoft.com/v1.0/me'
graph_r = requests.get(graph_url, headers=headers)
graph_r.raise_for_status()
user_info = graph_r.json()
user_email = str(user_info["mail"])
user_id = user_email.split("@")[0]
session["user_id"] = user_id
# 登出 MS Online 並重定向回首頁
# 返回 HTML 及 JavaScript 以進行自動登出
return (f'Hello, {user_id} <br>'
f'<script type="text/javascript">'
f' window.location = "https://login.microsoftonline.com/common/oauth2/v2.0/logout";'
f'</script>')
@app.route('/userid')
def userid():
return session["user_id"]
# 登出功能
@app.route('/logout')
def logout():
# 清除 session 中的訪問令牌
session.pop('access_token', None)
# 重定向到 MS Online 登出 URL
return redirect('https://login.microsoftonline.com/common/oauth2/v2.0/logout')
if __name__ == '__main__':
context = (r'C:\Certbot\live\your_server_domain\cert.pem', r'C:\Certbot\live\your_server_domain\privkey.pem')
app.run(debug=True, host='your_server_domain', port=443, ssl_context=context)
啟動後, 以 https://your_server_domain 連線後, 系統導到 Office 365 登入.
以下則為寄信範例:
import requests
import json
# 替換為你的應用程式資訊
CLIENT_ID = 'your_client_id'
CLIENT_SECRET = 'your_client_secret'
TENANT_ID = 'your_tenant_id'
AUTHORITY = f'https://login.microsoftonline.com/{TENANT_ID}'
TOKEN_URL = f'{AUTHORITY}/oauth2/v2.0/token'
SCOPE = 'https://graph.microsoft.com/.default'
# 獲取 OAuth2 訪問令牌
def get_access_token():
token_data = {
'grant_type': 'client_credentials',
'client_id': CLIENT_ID,
'client_secret': CLIENT_SECRET,
'scope': SCOPE
}
token_r = requests.post(TOKEN_URL, data=token_data)
token_r.raise_for_status()
tokens = token_r.json()
return tokens['access_token']
# 發送電子郵件
def send_email(access_token, to_address, subject, body):
headers = {
'Authorization': f'Bearer {access_token}',
'Content-Type': 'application/json'
}
email_data = {
"message": {
"subject": subject,
"body": {
"contentType": "Text",
"content": body
},
"toRecipients": [
{
"emailAddress": {
"address": to_address
}
}
]
},
"saveToSentItems": "true"
}
email_url = 'https://graph.microsoft.com/v1.0/me/sendMail'
response = requests.post(email_url, headers=headers, json=email_data)
response.raise_for_status()
print("Email sent successfully!")
if __name__ == "__main__":
token = get_access_token()
send_email(token, 'recipient@example.com', 'Test Subject', 'This is the email body.')
以下利用 ChatGPT 進行對話:
問:
使用 python + flask 開發一個簡單的資料庫程式, 並使用 SQLite, 目前表單有使用者學號以及其 github 帳號, 還有一個備註欄位, 只需要 add, query, update 與 delete 功能, 該如何進行?
答:
安裝 Flask 和 SQLite
首先,確保你已經安裝了 Flask 和 SQLite。如果你還沒有安裝,請使用以下命令:
pip install Flask
SQLite 通常已經隨 Python 安裝,不需要額外安裝。如果你需要 SQLite 的 Python 模組,可以使用以下命令:
pip install sqlite3
建立 Flask 應用程式
應用程式結構:
flask_app/
│
├── app.py
├── schema.sql
└── templates/
├── index.html
├── add.html
├── update.html
└── query.html
schema.sql — 定義 SQLite 資料表
在 schema.sql 文件中,定義 SQLite 資料表結構:
CREATE TABLE IF NOT EXISTS users (
id INTEGER PRIMARY KEY AUTOINCREMENT,
student_id TEXT NOT NULL UNIQUE,
github_account TEXT NOT NULL,
notes TEXT
);
app.py — Flask 應用程式
在 app.py 中,設置 Flask 應用程式並建立 CRUD 功能:
from flask import Flask, request, redirect, url_for, render_template
import sqlite3
app = Flask(__name__)
DATABASE = 'database.db'
def get_db():
conn = sqlite3.connect(DATABASE)
conn.row_factory = sqlite3.Row
return conn
def init_db():
with app.app_context():
db = get_db()
with open('schema.sql', 'r') as f:
db.executescript(f.read())
db.commit()
@app.route('/')
def index():
return render_template('index.html')
@app.route('/add', methods=['GET', 'POST'])
def add_user():
if request.method == 'POST':
student_id = request.form['student_id']
github_account = request.form['github_account']
notes = request.form.get('notes', '')
db = get_db()
db.execute('INSERT INTO users (student_id, github_account, notes) VALUES (?, ?, ?)',
(student_id, github_account, notes))
db.commit()
return redirect(url_for('index'))
return render_template('add.html')
@app.route('/update/<int:user_id>', methods=['GET', 'POST'])
def update_user(user_id):
db = get_db()
if request.method == 'POST':
student_id = request.form['student_id']
github_account = request.form['github_account']
notes = request.form.get('notes', '')
db.execute('UPDATE users SET student_id = ?, github_account = ?, notes = ? WHERE id = ?',
(student_id, github_account, notes, user_id))
db.commit()
return redirect(url_for('index'))
user = db.execute('SELECT * FROM users WHERE id = ?', (user_id,)).fetchone()
return render_template('update.html', user=user)
@app.route('/delete/<int:user_id>')
def delete_user(user_id):
db = get_db()
db.execute('DELETE FROM users WHERE id = ?', (user_id,))
db.commit()
return redirect(url_for('index'))
@app.route('/query')
def query_users():
db = get_db()
users = db.execute('SELECT * FROM users').fetchall()
return render_template('query.html', users=users)
if __name__ == '__main__':
init_db()
app.run(debug=True)
templates/index.html:
<!DOCTYPE html>
<html>
<head>
<title>Index</title>
</head>
<body>
<h1>Welcome to User Management</h1>
<a href="{{ url_for('add_user') }}">Add User</a> |
<a href="{{ url_for('query_users') }}">Query Users</a>
</body>
</html>
templates/add.html:
<!DOCTYPE html>
<html>
<head>
<title>Add User</title>
</head>
<body>
<h1>Add User</h1>
<form action="{{ url_for('add_user') }}" method="post">
<label for="student_id">Student ID:</label>
<input type="text" id="student_id" name="student_id" required><br>
<label for="github_account">GitHub Account:</label>
<input type="text" id="github_account" name="github_account" required><br>
<label for="notes">Notes:</label>
<textarea id="notes" name="notes"></textarea><br>
<input type="submit" value="Add">
</form>
<a href="{{ url_for('index') }}">Back</a>
</body>
</html>
templates/update.html:
<!DOCTYPE html>
<html>
<head>
<title>Update User</title>
</head>
<body>
<h1>Update User</h1>
<form action="{{ url_for('update_user', user_id=user['id']) }}" method="post">
<label for="student_id">Student ID:</label>
<input type="text" id="student_id" name="student_id" value="{{ user['student_id'] }}" required><br>
<label for="github_account">GitHub Account:</label>
<input type="text" id="github_account" name="github_account" value="{{ user['github_account'] }}" required><br>
<label for="notes">Notes:</label>
<textarea id="notes" name="notes">{{ user['notes'] }}</textarea><br>
<input type="submit" value="Update">
</form>
<a href="{{ url_for('index') }}">Back</a>
</body>
</html>
templates/query.html:
<!DOCTYPE html>
<html>
<head>
<title>Query Users</title>
</head>
<body>
<h1>Users</h1>
<table>
<tr>
<th>ID</th>
<th>Student ID</th>
<th>GitHub Account</th>
<th>Notes</th>
<th>Actions</th>
</tr>
{% for user in users %}
<tr>
<td>{{ user['id'] }}</td>
<td>{{ user['student_id'] }}</td>
<td>{{ user['github_account'] }}</td>
<td>{{ user['notes'] }}</td>
<td>
<a href="{{ url_for('update_user', user_id=user['id']) }}">Update</a> |
<a href="{{ url_for('delete_user', user_id=user['id']) }}">Delete</a>
</td>
</tr>
{% endfor %}
</table>
<a href="{{ url_for('index') }}">Back</a>
</body>
</html>
啟動應用程式
確保你的 Flask 應用程式和模板文件已經正確配置,然後啟動應用程式:
python app.py
接下來, 可以在瀏覽器中訪問 http://127.0.0.1:5000/
來查看和管理你的資料。
AI <<
Previous Next >> Topics