User
詳細解釋一下API中client和server所扮演的角色和功能
ChatGPT
當談到API時,通常涉及到兩個主要組成部分:客戶端(Client)和伺服器(Server)。它們各自扮演不同的角色並執行特定的功能。
客戶端(Client):
發出請求: 客戶端是對API的使用者。它可以是應用程式、網站、行動應用、甚至其他伺服器。客戶端通常發送請求給伺服器,要求資源或執行特定操作。
處理回應: 客戶端負責處理從伺服器返回的響應。這可能包括解析資料、顯示在使用者介面上或者進行進一步的處理。
傳送請求: 發送不同類型的請求,比如GET(獲取資料)、POST(新增資料)、PUT(更新資料)、DELETE(刪除資料)等,根據所需的操作。
伺服器(Server):
接收請求: 伺服器是API的提供者。它接收來自客戶端的請求,並根據這些請求針對資料庫、其他系統或資源進行操作。
處理請求: 根據請求的類型和內容,伺服器會執行相應的操作,比如檢索資料、更新資料庫、發送通知等。
回覆響應: 伺服器會向客戶端發送回應,這可能是請求的結果、錯誤訊息或其他相關的資訊。
功能關聯:
客戶端和伺服器的關係是相互的,它們透過互相的請求和響應來實現特定的功能。客戶端需要發送明確的請求以獲取所需的資訊或執行操作,而伺服器則回應這些請求並提供相應的資訊或服務。
例如,假設您使用一個社交媒體平台的API,您的應用程式(客戶端)可以發送請求以獲取特定用戶的資料。伺服器接收這個請求,從資料庫中檢索用戶資料,然後回傳這些資料作為響應,最後由您的應用程式處理和顯示這些資訊給使用者。
總的來說,客戶端和伺服器在API中扮演不同但互相依賴的角色,共同協作以實現資訊交換和服務提供。
User
兩者的程式碼填寫有哪裡不同
ChatGPT
在API客戶端和伺服器端的程式碼中,主要的不同點在於它們執行的功能和相應的操作。下面會列舉一些主要的差異:
客戶端程式碼:
主要功能:
發送請求: 客戶端主要負責向伺服器發送請求。
處理回應: 接收並處理從伺服器返回的響應。
操作應用程序界面(UI): 將從伺服器獲取的資訊顯示在應用程式的介面上,例如網頁、應用程式界面等。
程式碼區別:
使用HTTP請求庫(如Python中的requests)來建立和發送請求。
設置所需的標頭(例如授權憑證、內容類型)以及其他參數。
接收和解析伺服器的響應,通常以JSON或其他格式。
伺服器端程式碼:
主要功能:
接收請求: 接收來自客戶端的請求。
處理請求: 根據請求的類型和內容執行相應的操作,例如從資料庫中檢索、更新資料等。
回覆響應: 向客戶端發送回應,包括所需的資訊或操作的結果。
程式碼區別:
監聽和處理來自客戶端的請求。
實現API端點(endpoint)以接收特定類型的請求(GET、POST、PUT、DELETE等)。
執行相應的邏輯操作並生成適當的響應。
基本上,客戶端程式碼主要集中在向伺服器發送請求和處理回應,而伺服器端則專注於接收、處理請求並提供相應的回應。兩者的重點和功能不同,但它們需要彼此配合以實現完整的API功能。
sudo apt-get install python3 python3-pip
pip3 install Flask
pip install pymysql==0.9.3
sudo apt-get install python3-pymysql
pip install flask-cors
pip3 install
python3 api.py
Traceback (most recent call last):
File "/home/jimmy/.local/lib/python3.6/site-packages/pymysql/connections.py", line 614, in connect
(self.host, self.port), self.connect_timeout, **kwargs
File "/usr/lib/python3.6/socket.py", line 724, in create_connection
raise err
File "/usr/lib/python3.6/socket.py", line 713, in create_connection
sock.connect(sa)
ConnectionRefusedError: [Errno 111] Connection refused
During handling of the above exception, another exception occurred:
Traceback (most recent call last):
File "api.py", line 15, in <module>
connection = pymysql.connect(**db_config)
File "/home/jimmy/.local/lib/python3.6/site-packages/pymysql/connections.py", line 353, in __init__
self.connect()
File "/home/jimmy/.local/lib/python3.6/site-packages/pymysql/connections.py", line 664, in connect
raise exc
pymysql.err.OperationalError: (2003, "Can't connect to MySQL server on '127.0.0.1' ([Errno 111] Connection refused)")
sudo apt update && sudo apt install mysql-server
sudo mysql
ALTER USER 'root'@'localhost' IDENTIFIED WITH mysql_native_password by 'rtlab111';
sudo mysql -u root -p
CREATE DATABASE db_1;
USE db_1;
CREATE TABLE IF NOT EXISTS table_1 (
id INT AUTO_INCREMENT PRIMARY KEY,
...
);
/*
1. INT (整數)
2. CHAR (1~255字元字串)
3. VARCHAR (不超過255字元不定長度字串)
4. TEXT (不定長度字串最多65535字元)
*/
SELECT * FROM table_1;
INSERT INTO your_table_name (column1, column2, column3) VALUES ('value1', 'value2', 'value3');
show <databases,tables>;
drop databases, table;
describe table_2;
truncate table table_2;
alter table table_account change time_register time_register timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
exit
telnet 127.0.0.1 5000
curl -X POST -H "Content-Type: application/json" -d '{"dt_infotime": "2023-11-17 12:00:00", "s_attemp": 25, "s_cpu": 80, "s_disk": "", "s_diskin": 100, "s_diskout": 50, "s_error": "No errors", "s_load": 3.5, "s_loss": 0.5, "s_memory": 70, "s_nf": 10, "s_size": 1024, "s_system": "Linux", "s_traffic": 1000, "s_transfer": 500}' http://192.168.0.2:5000/nfs/resource
// Back message
{
"message": "JSON received successfully"
}
Result
http://192.168.0.2:5000/
http://140.118.121.93:1112/
CREATE TABLE IF NOT EXISTS table_2 (
id INT AUTO_INCREMENT PRIMARY KEY,
dt_infotime VARCHAR(255),
s_attemp VARCHAR(255),
s_cpu VARCHAR(255),
s_disk VARCHAR(255),
s_diskin VARCHAR(255),
s_diskout VARCHAR(255),
s_error VARCHAR(255),
s_load VARCHAR(255),
s_loss VARCHAR(255),
s_memory VARCHAR(255),
s_nf VARCHAR(255),
s_size VARCHAR(255),
s_system VARCHAR(255),
s_traffic VARCHAR(255),
s_transfer VARCHAR(255)
);
from flask import Flask, jsonify, request
import pymysql
from flask_cors import cross_origin
app = Flask(__name__)
# MySQL 連接資訊
db_config = {
'host': '127.0.0.1',
'user': 'root',
'password': 'rtlab111',
'database': 'db_1',
#'port': 3306
}
# 處理 404 錯誤
@app.errorhandler(404)
def not_found_error(error):
return jsonify({'error': 'Not Found'}), 404
# 創建 MySQL 連接
connection = pymysql.connect(**db_config)
# 創建游標
cursor = connection.cursor()
# 新的端點,用於接收 POST 請求並添加新的 log
@app.route('/nfs/resource', methods=['POST'])
@cross_origin() # 使用 @cross_origin 裝飾器啟用 CORS
def add_log():
try:
json_data = request.get_json()
# 檢查是否包含所需的標題
required_titles = ['dt_infotime', 's_attemp', 's_cpu', 's_disk', 's_diskin', 's_diskout',
's_error', 's_load', 's_loss', 's_memory', 's_nf', 's_size',
's_system', 's_traffic', 's_transfer']
# 準備用於插入的標題和值
insert_titles = []
insert_values = []
for title in required_titles:
if title in json_data:
insert_titles.append(title)
insert_values.append(json_data[title])
elif title not in json_data:
return jsonify({'error': f'Missing title: {title}'}), 404
# 檢查是否有任何可插入的標題
#if not insert_titles:
# return jsonify({'error': 'No valid data to insert'}), 400
# 插入資料到 MySQL 表格
insert_query = f"INSERT INTO table_2 ({', '.join(insert_titles)}) VALUES ({', '.join(['%s']*len(insert_titles))})"
cursor.execute(insert_query, insert_values)
connection.commit()
# 加入 print 語句以記錄成功接收並插入資料
print(f"Received JSON: {json_data}")
return jsonify({'message': 'JSON received successfully'}), 200
except Exception as e:
return jsonify({'error': str(e)}), 404
# 新的端點,用於接收 GET 請求
@app.route('/nfs/resource', methods=['GET'])
@cross_origin() # 使用 @cross_origin 裝飾器啟用 CORS
def get_s_nf():
try:
# 從 GET 參數中獲取 s_nf 的值
s_nf_value = request.args.get('s_nf')
# 檢查是否有 s_nf 參數
if s_nf_value is None:
return jsonify({'error': 'Missing s_nf parameter'}), 404
# 執行 SELECT 查詢,找到最後一筆 s_nf=amf 的資料按照 id 降序排序
select_query = "SELECT * FROM table_2 WHERE s_nf = %s ORDER BY id DESC LIMIT 1"
cursor.execute(select_query, (s_nf_value,))
# 獲取查詢結果
result = cursor.fetchone()
# 將結果轉換為 JSON 格式並返回
data = {"dt_infotime": result[0], "s_attemp": result[1], "s_cpu": result[2], "s_disk": result[3], "s_diskin": result[4], "s_diskout": result[5]
, "s_error": result[6], "s_load": result[7], "s_loss": result[8], "s_memory": result[9] #, "s_nf": result[10]
, "s_size": result[11], "s_system": result[12], "s_traffic": result[13], "s_transfer": result[14]} # 根據實際情況修改列名
return jsonify({'data': data}), 200
except Exception as e:
return jsonify({'error': str(e)}), 404
(400->404)
http://192.168.0.2:5000/nfs/resource
http://140.118.121.93:1112/nfs/resource
{
"dt_infotime": "2023-11-17 12:00:00",
"s_attemp": 25,
"s_cpu": 80,
"s_disk": "",
"s_diskin": 100,
"s_diskout": 50,
"s_error": "No errors",
"s_load": 3.5,
"s_loss": 0.5,
"s_memory": 70,
"s_nf": 10,
"s_size": 1024,
"s_system": "Linux",
"s_traffic": 1000,
"s_transfer": 500
}
http://192.168.0.2:5000/nfs/resource
http://140.118.121.93:1112/nfs/resource
{
"dt_infotime": "2023-11-17 12:00:00",
"s_attemp": 25,
"s_cpu": 80,
"s_disk": "",
"s_diskin": 100,
"s_diskout": 50,
"s_error": "No errors",
"s_load": 3.5,
"s_loss": 0.5,
"s_memory": 70,
"s_nf": 10,
"s_size": 1024,
"s_system": "Linux",
"s_traffic": 1000,
}
CREATE TABLE IF NOT EXISTS table_sign_up (
id INT AUTO_INCREMENT PRIMARY KEY,
s_name VARCHAR(255),
s_email VARCHAR(255),
s_password VARCHAR(255),
s_password_confirmation VARCHAR(255),
s_phone VARCHAR(255)
);
# 新的端點,用於接收 POST 請求並添加新的 user
@app.route('/user/signup', methods=['POST'])
@cross_origin() # 使用 @cross_origin 裝飾器啟用 CORS
def sign_up():
try:
json_data = request.get_json()
# 檢查是否包含所需的標題
required_titles = ['s_name', 's_email', 's_password', 's_password_confirmation', 's_phone']
# 檢查是否有任何可插入的標題為空
if any(title not in json_data or not json_data[title].strip() for title in required_titles):
return jsonify({'Error': 'have some parameter null'}), 403
# 取得 'access_level' 的值,如果不存在,預設值為 0
access_level = request.headers.get('Authorization', 0)
# 準備用於插入的標題和值
insert_titles = required_titles + ['access_level']
insert_values = [json_data[title] for title in required_titles] + [access_level]
# 檢查 's_password' 和 's_password_confirmation' 是否相同
if 's_password' in json_data and 's_password_confirmation' in json_data:
if json_data['s_password'] != json_data['s_password_confirmation']:
return jsonify({'Error': 'need identical password'}), 401
# 檢查 's_email' 是否已經存在於表格中
check_email_query = "SELECT COUNT(*) FROM table_sign_up WHERE s_email = %s"
cursor.execute(check_email_query, (json_data['s_email'],))
email_exists = cursor.fetchone()[0]
if email_exists:
return jsonify({'Error': 'email already registers'}), 402
# 插入資料到 MySQL 表格
insert_query = f"INSERT INTO table_sign_up ({', '.join(insert_titles)}) VALUES ({', '.join(['%s']*len(insert_titles))})"
cursor.execute(insert_query, insert_values)
connection.commit()
# 加入 print 語句以記錄成功接收並插入資料
print(f"Received JSON: {json_data}")
return jsonify({'message': 'JSON received successfully'}), 200
except Exception as e:
return jsonify({'error': str(e)}), 400
http://192.168.0.2:5000/user/signup
http://140.118.121.93:1112/user/signup
{
"s_name": "jimmy",
"s_email": "jimmy20152811@gmail.com",
"s_password": "rtlab111",
"s_password_confirmation": "rtlab111",
"s_phone": "0903396991"
}
User 類別:
authenticate 函式:
identity 函式:
這裡使用 JWT 類別來啟用 Flask-JWT。建立 JWT 實例時,需要提供三個參數:Flask 應用程式實例 (app)、用於驗證的回調函式 (authenticate) 和用於生成 JWT 的回調函式 (identity)。
總的來說,這些程式碼協助你在 Flask 應用程式中實現了使用 JWT 進行身分驗證的功能。當使用者提供有效的電子郵件和密碼進行登入時,你可以生成一個包含使用者資訊的 JWT,之後該令牌可以用來驗證和授權用戶的請求。
你的觀察是正確的,感謝提醒。在你的登入 API 的程式碼中,確實沒有直接使用到 identity 函式。讓我解釋一下可能的原因:
Flask-JWT 在驗證和生成 JWT 時,會自動調用 authenticate 函式來驗證使用者的身份。而當你在 Flask-JWT 中啟用了 JWT 實例時,它會自動處理驗證流程,包括呼叫 authenticate 函式,這是內建的行為。
在實際的應用中,identity 函式可能用於在每個請求中提取 JWT 中的使用者識別信息,並將其存儲在 Flask 的 current_identity 中,以便稍後在應用中取用。在你的程式碼中,如果你希望在 /user/login 的請求中使用 current_identity,你可以在該請求中使用 current_identity 取得當前使用者的資訊。
總結來說,Flask-JWT 在啟用後會自動處理身份驗證的部分,而 identity 函式則在需要取得當前使用者信息時提供了一個方法。你的登入 API 程式碼中如果沒有直接使用到 identity,可能是因為目前的邏輯還不需要它,但在更複雜的應用中可能會用到。
是的,當前的登入邏輯中,你主要是透過 authenticate 函式來從資料庫中對比使用者提供的帳號密碼是否正確。在這個過程中,identity 函式並沒有直接使用到。
identity 函式通常在你需要在每個請求中取得當前使用者的資訊時使用。例如,當你的應用需要在請求中驗證使用者的權限,或者在請求中記錄使用者的操作歷史時,就可能會使用到 identity 函式。
總的來說,identity 函式的使用取決於你的應用邏輯,如果目前的邏輯不需要直接取得當前使用者的資訊,那麼你可以在不使用它的情況下繼續進行。
JWT(JSON Web Token)的主要目的是在網路應用中提供一種安全的方法來傳遞資訊,特別是用於驗證和資訊交換。在你的情境中,JWT 通常用於驗證使用者的身份,以及在使用者成功登入後發送安全的令牌。
下面是 JWT 的一些主要優勢:
安全的身份驗證: JWT 可以在使用者驗證成功後生成一個安全的令牌,該令牌包含了使用者的身份信息。這樣,當使用者在之後的請求中提供這個令牌,你的應用可以驗證該令牌,確保該使用者是有效的,而不需要再次查詢資料庫。
無需每次都查詢資料庫: 一旦使用者登入,你可以使用 JWT 來在之後的請求中驗證使用者身份,而不必每次都去查詢資料庫。這有助於提高效能,減少對資料庫的負擔。
避免明文傳輸密碼: JWT 通常不包含使用者的密碼等敏感資訊,避免了在請求中傳輸明文密碼的風險。
在Flask中,app.config['SECRET_KEY'] 是一個用於簽署和驗證 session cookie 或其他資料的金鑰。它是一個安全性設定,用來確保特定的資料是由應用程式生成並未被竄改。
當你使用 Flask 中的某些擴展,如 Flask-WTF(用於處理表單)或 Flask-JWT(用於處理 JSON Web Tokens),它們可能會使用這個密鑰來確保應用的安全性。
密鑰的選擇應該是隨機且複雜的字符串,以增加安全性。你可以自行生成一個安全的密鑰,例如使用 Python 的 secrets 模組,而不是將其設為明文字符串。
這樣的設定通常用於確保某些 Flask 擴展或功能的安全性。在這個例子中,這個密鑰可能會被 Flask-JWT 用來簽署和驗證 JSON Web Tokens(JWT)。
實際上我資料庫中的id只是資料筆數和順序而已 這樣是否需要更改程式碼
ChatGPT
id 欄位通常是資料表的主鍵,用來唯一識別每一筆資料。在你的程式碼中,id 欄位被用作 JWT 中的 identity,這是 Flask-JWT 擴展預期的用法。這樣的做法基本上是合理的,因為 JWT 需要一個唯一的識別符號來代表每個使用者。
如果你的 id 欄位不是唯一的,你可能需要考慮使用其他唯一的識別符號來替代,或者針對不同的使用者建立自訂的 identity 生成邏輯。
總的來說,如果你的 id 欄位確實是唯一的並且足夠用作使用者的唯一標識符,則沒有必要修改這部分的程式碼。如果有其他適合的唯一標識符,可以考慮修改 identity 函式以反映這一點。
Google 登入路由,導向 Google 登入頁面
@app.route('/user/google-login')
@cross_origin()
def google_login():
# 在這裡包含需要的權限,例如 user.phonenumbers.read
google = OAuth2Session(
GOOGLE_CLIENT_ID,
redirect_uri=GOOGLE_REDIRECT_URI,
scope=['openid', 'email', 'profile', 'https://www.googleapis.com/auth/user.phonenumbers.read']
)
authorization_url, state = google.authorization_url(GOOGLE_AUTHORIZATION_BASE_URL)
return redirect(authorization_url)
和這串有什麼差異
另外怎麼在控制台開啟權限
ChatGPT
這兩段程式碼的差異在於 scope 參數中包含的權限。在你提供的程式碼中,包含了 'https://www.googleapis.com/auth/user.phonenumbers.read',這表示你希望在 Google 登入時取得手機號碼的讀取權限。
至於如何在 Google 開發者控制台中開啟權限,你可以參考以下步驟:
前往 Google Cloud Console.
選擇你的專案(如果還沒有,請建立一個新的專案)。
在左側的導覽欄中,點選 "API 和服務" > "憑證"。
在 "憑證" 頁面中,找到你的 OAuth 2.0 用戶端 ID。
在 "授權的 JavaScript 來源" 和 "已授權的重新導向 URI" 中,確保你的網站的網址被正確設定。
另外,關於手機號碼的權限,Google 可能會有一些限制和審查,請確保你的應用程式遵守 Google 的相關政策和規定。如果需要特定的權限,建議查閱 Google 的官方文件。
User
上面那段只u有加phone沒辦法在 Google 登入時取得手機號碼的讀取權限?
ChatGPT
抱歉我之前的回答有誤,Google API 的 OAuth 2.0 驗證確實不提供直接取得使用者手機號碼的功能。Google 在他們的 OAuth 2.0 API 中並未包含用戶手機號碼的權限。我為混淆的回答感到抱歉。
一般而言,Google 的 OAuth 2.0 主要提供 "openid", "email", "profile" 等標準身份驗證相關的信息,而不包括敏感信息,例如手機號碼。手機號碼通常不是一個直接包含在 Google OAuth 的範疇內的資訊。
如果你需要使用者的手機號碼,你可能需要考慮其他方式,例如在你的應用程序中要求使用者提供手機號碼,並透過其他驗證方法確認其真實性。在一些國家或地區,可能有法規限制取得手機號碼,因此在實施時需確保符合當地法規和隱私政策。
User
那程式碼是否要改掉
ChatGPT
如果你希望使用者的手機號碼能夠透過 Google 登入取得,你需要先確定 Google API 是否支援這樣的功能。根據我之前的了解,Google OAuth 2.0 的範疇(scope)中並未包含用戶手機號碼的權限。因此,無法透過 Google OAuth 直接取得使用者的手機號碼。
如果你仍然想要收集使用者的手機號碼,有以下一些方式可以考慮:
在應用程序中要求手機號碼: 在註冊或登錄流程中,要求使用者提供手機號碼。這可能需要一個額外的表單或步驟,但這是獲取手機號碼的常見方式。
使用其他身份驗證方式: 例如,使用簡訊驗證或其他身份驗證方式,來確認使用者的手機號碼。
使用其他身份提供者: 如果手機號碼對你的應用程序很重要,可以考慮使用其他身份提供者,其中一些可能提供手機號碼作為資訊。
當然,上述的方式需要你在應用程序中進行相應的修改,包括前端和後端的程式碼。具體的實現方式取決於你的應用程序的需求和架構。
請注意,上面提到的步驟是基於目前的 Google 開發者控制台介面,該介面可能在未來有所變化。在設置 OAuth 憑證之前,你需要確保你的專案中啟用了 Google+ API 和 Google People API,這兩者都是用於取得用戶資訊的 API。
在使用 Google OAuth 2.0 時,Google 要求在授權 JavaScript 來源和重新導向 URI 時使用有效的網域,而不僅僅是 IP 地址。這是為了提高安全性,避免潛在的風險。
如果你在本地測試時遇到這個問題,有幾種方法可以解決:
- 使用 localhost:
在開發階段,你可以將 JavaScript 來源和重新導向 URI 設置為 http://localhost:your-port。這是因為 localhost 在大多數情況下被視為有效的網域。
- 使用 ngrok:
ngrok 是一個工具,可以將本地伺服器公開到互聯網上。你可以在 ngrok 中建立一個公共 URL,然後將這個 URL 用於 Google OAuth 的 JavaScript 來源和重新導向 URI。然後,將 ngrok 提供的 URL 用於 Google OAuth。
- 設定有效的網域:
如果你有一個有效的域名,你可以在本機開發環境中模擬這個域名。這可能需要在你的本地 hosts 文件中進行一些設定,並在路由器或防火牆上進行一些設定,以允許外部流量進入。
選擇哪一種方法取決於你的需求和開發環境。
在 Postman 中測試 Google 登入部分,你可以使用 OAuth 2.0 授權碼流程進行測試。以下是一個簡單的步驟:
建立 OAuth 2.0 請求:
在 Postman 中建立一個新的請求,選擇 OAuth 2.0 作為授權類型。點擊 "Get New Access Token"。
填寫 OAuth 2.0 資訊:
Token Name: 任意命名你的 token。
Grant Type: 選擇 "Authorization Code".
Callback URL: 這應該是你應用程式的登入回調 URI。
Auth URL: 這是 Google 的授權端點,通常類似於 https://accounts.google.com/o/oauth2/auth.
Access Token URL: 這是 Google 的令牌端點,通常類似於 https://accounts.google.com/o/oauth2/token.
Client ID: 你在 Google 開發者控制台中註冊應用程式時獲得的客戶端 ID.
Client Secret: 你在 Google 開發者控制台中註冊應用程式時獲得的客戶端密鑰.
Scope: 這是你想要的權限範圍,例如 "openid email profile",以及你的應用程式所需的任何其他範圍。
完成後,點擊 "Request Token"。
登入 Google 帳戶:
Postman 會彈出一個新的視窗,要求你登入 Google 帳戶,同時同意你的應用程式所需的權限。
取得 Access Token:
在成功登入並同意授權後,Postman 會收到包含 Access Token 的回應。
使用 Access Token 向 API 發送請求:
將收到的 Access Token 添加到你的 API 請求標頭中,通常是 Authorization: Bearer YOUR_ACCESS_TOKEN。
這樣你就可以使用 Postman 模擬整個 Google 登入的流程,同時檢查你的應用程式是否能夠正確處理授權碼和取得 Access Token。
在 Postman 中添加 Access Token 到 API 請求標頭是相對簡單的。以下是具體步驟:
步驟 1:取得 Access Token
在 Postman 中,你首先需要確保你已經成功登入並同意授權,以便收到包含 Access Token 的回應。
步驟 2:添加 Access Token 到請求標頭
打開 Postman。
創建或打開你想要測試的請求。
在請求的標頭(Headers)部分,你將添加 Authorization 標頭,其值為 "Bearer YOUR_ACCESS_TOKEN",其中 "YOUR_ACCESS_TOKEN" 是你從授權伺服器獲得的實際 Access Token。
選擇 "Authorization" 標頭類型為 "Bearer Token"。
在 "Token" 欄位中輸入你的 Access Token。
點擊 "Send" 以發送你的請求。
POST有認證成功拿到Token但沒有得到return,server停留在302,拿不到200。
pip3 install requests-oauthlib
pip3 install Flask-JWT
pip3 install requests
curl -s https://ngrok-agent.s3.amazonaws.com/ngrok.asc | sudo tee /etc/apt/trusted.gpg.d/ngrok.asc >/dev/null && echo "deb https://ngrok-agent.s3.amazonaws.com buster main" | sudo tee /etc/apt/sources.list.d/ngrok.list && sudo apt update && sudo apt install ngrok
ngrok config add-authtoken 2YPM0OZTQUMtRDd5oEAfha28qDC_23ceq4hHgzDx3RoXQkA4o
# 要先在官網註冊才有authtoken
ngrok http 192.168.0.2:5000
from flask import Flask, jsonify, request, redirect, url_for
import pymysql
from flask_cors import cross_origin
from flask_jwt import JWT, jwt_required, current_identity
from requests_oauthlib import OAuth2Session
import secrets
app = Flask(__name__)
app.config['SECRET_KEY'] = secrets.token_hex(16)
# MySQL 連接資訊
db_config = {
'host': '127.0.0.1',
'user': 'root',
'password': 'rtlab111',
'database': 'db_1',
#'port': 3306
}
# 處理 404 錯誤
@app.errorhandler(404)
def not_found_error(error):
return jsonify({'error': 'Not Found'}), 404
# 創建 MySQL 連接
connection = pymysql.connect(**db_config)
# 創建游標
cursor = connection.cursor()
# 定義使用者類別,用於 JWT
class User:
def __init__(self, id, s_name, s_email, s_phone, access_level):
self.id = id
self.s_name = s_name
self.s_email = s_email
self.s_phone = s_phone
self.access_level = access_level
# 用於 JWT 的回調函式
def authenticate(s_name, s_password):
query = "SELECT * FROM table_sign_up WHERE s_name = %s AND s_password = %s"
cursor.execute(query, (s_name, s_password))
user = cursor.fetchone()
if user:
return User(id=user[0], s_name=user[1], s_email=user[2], s_phone=user[5], access_level=user[-1])
# 用於生成 JWT 的回調函式
def identity(payload):
user_id = payload['identity']
query = "SELECT * FROM table_sign_up WHERE id = %s"
cursor.execute(query, (user_id,))
user = cursor.fetchone()
if user:
return User(id=user[0], s_email=user[2], access_level=user[-1])
# 在 Flask 中啟用 JWT
jwt = JWT(app, authenticate, identity)
# Google OAuth 資訊
GOOGLE_CLIENT_ID = '92303118686-evca8stap1l4t512m5nobbgaog7pllvk.apps.googleusercontent.com'
GOOGLE_CLIENT_SECRET = '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'
GOOGLE_REDIRECT_URI = 'https://c22b-140-118-121-93.ngrok-free.app/user/google-callback'
GOOGLE_AUTHORIZATION_BASE_URL = 'https://accounts.google.com/o/oauth2/auth'
GOOGLE_TOKEN_URL = 'https://accounts.google.com/o/oauth2/token'
GOOGLE_USERINFO_URL = 'https://www.googleapis.com/oauth2/v1/userinfo'
# Google 登入路由,導向 Google 登入頁面
@app.route('/user/google-login')
@cross_origin()
def google_login():
google = OAuth2Session(GOOGLE_CLIENT_ID, redirect_uri=GOOGLE_REDIRECT_URI, scope=['openid', 'email', 'profile'])
authorization_url, state = google.authorization_url(GOOGLE_AUTHORIZATION_BASE_URL)
return redirect(authorization_url)
# 這裡沒有加上手機,因為不包含要求這個功能
# Google 登入回調路由
@app.route('/user/google-callback')
@cross_origin()
def google_callback():
try:
google = OAuth2Session(GOOGLE_CLIENT_ID, redirect_uri=GOOGLE_REDIRECT_URI)
token = google.fetch_token(GOOGLE_TOKEN_URL, authorization_response=request.url)
user_info = google.get(GOOGLE_USERINFO_URL).json()
# 在這裡處理 Google 登入成功後的邏輯
# 你可能需要在資料庫中檢查使用者是否存在,如果不存在就創建一個新的使用者
existing_user_query = "SELECT * FROM table_sign_up WHERE s_email = %s"
cursor.execute(existing_user_query, (user_info['email'],))
existing_user = cursor.fetchone()
if existing_user:
# 使用現有使用者的資訊
user = User(id=existing_user[0], s_name=existing_user[1], s_email=existing_user[2], s_phone=existing_user[5], access_level=existing_user[-1])
else:
# 創建新的使用者
insert_user_query = "INSERT INTO table_sign_up (s_name, s_email, access_level) VALUES (%s, %s, %s)"
cursor.execute(insert_user_query, (user_info['name'], user_info['email'], 0)) # 這裡假設使用者的預設權限是 0
connection.commit()
# 取得新使用者的資訊
cursor.execute(existing_user_query, (user_info['email'],))
new_user = cursor.fetchone()
user = User(id=new_user[0], s_name=new_user[1], s_email=new_user[2], s_phone=new_user[5], access_level=new_user[-1])
# 在這裡執行重定向
return jsonify({'message': 'Google login successful', 'user_info': {'s_name': user.s_name, 's_email': user.s_email, 's_phone': user.s_phone, 'access_level': user.access_level}}), 200
except Exception as e:
return jsonify({'error': str(e)}), 500
# 登入的路由,支援一般登入和使用 Google 帳戶登入
@app.route('/user/login', methods=['POST'])
@cross_origin()
def login():
try:
json_data = request.get_json()
# 檢查是否包含所需的標題
required_titles = ['s_name', 's_password']
# 檢查是否有任何可插入的標題為空
if any(title not in json_data or not json_data[title].strip() for title in required_titles):
return jsonify({'Error': 'Missing required parameters'}), 400
# 使用一般帳戶登入
if 's_name' in json_data and 's_password' in json_data:
user = authenticate(json_data['s_name'], json_data['s_password'])
if user:
# 生成 JWT
access_token = jwt.jwt_encode_callback(user)
# 返回使用者所有資訊,不包括密碼
return jsonify({'message': 'Login successful', 'user_info': {'s_name': user.s_name, 's_email': user.s_email, 's_phone': user.s_phone, 'access_level': user.access_level}, 'access_token': access_token.decode('utf-8')}), 200
else:
return jsonify({'Error': 'Invalid credentials'}), 400
else:
return jsonify({'error'}), 400
except Exception as e:
return jsonify({'error': str(e)}), 400
# Run the app
if __name__ == '__main__':
app.run(host='192.168.0.2',port=5000, debug=True)
http://140.118.121.93:1112/user/login
{
"s_name": "jimmy",
"s_password": "rtlab111"
}
不能使用瀏覽器POSTMAN測試,redirect uri會無法輸入
pip3 install flask-socketio
pip3 install schedule
...
def calculate_average_cpu_usage():
# 執行 SQL 查詢以獲取 s_cpu 數據
select_query = "SELECT s_cpu FROM table_2 WHERE s_nf = 'amf'"
cursor.execute(select_query)
# 獲取查詢結果
cpu_data = cursor.fetchall()
# 轉換 s_cpu 的數據為數字並計算總和
total_cpu = sum(float(data[0]) for data in cpu_data)
# 計算 s_cpu 的平均值
if cpu_data:
average_cpu = total_cpu / len(cpu_data)
return average_cpu
else:
return 0 # 或者返回其他預設值
# 定義 Socket.IO 事件處理程序(用於向前端發送警告)
@socketio.on('alert')
def handle_alert(alert_data):
print('Received alert data:', alert_data)
# 在這裡可以向前端發送警告
def job():
# 計算平均 s_cpu 使用率
average_cpu = calculate_average_cpu_usage()
# 檢查是否超過 90%
if average_cpu > 90:
# 發送警告到前端
alert_data = {'message': 'High CPU Usage', 'average_cpu': average_cpu}
socketio.emit('alert', alert_data)
# 定義定時任務,每分鐘執行一次
schedule.every(1).minutes.do(job)
def run_flask_app():
# 啟動 Socket.IO
socketio.run(app, host='192.168.0.2', port=5000, debug=True, use_reloader=False)
# 在一個新的執行緒中運行 Flask 應用程式
flask_thread = Thread(target=run_flask_app)
flask_thread.start()
# 在主執行緒中執行定時任務
while True:
try:
schedule.run_pending()
time.sleep(1)
except KeyboardInterrupt:
break # 中斷程式
# 等待 Flask 應用程式執行緒完成
flask_thread.join()
// socketio_client.js
const io = require('socket.io-client');
const socket = io('http://192.168.0.2:5000');
// 監聽 "alert" 事件
socket.on('alert', function (data) {
console.log('Received alert:', data);
// 在這裡處理接收到的警告信息
});
npm install socket.io-client
node socketio_client.js
CREATE TABLE IF NOT EXISTS table_account (
time_register TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP PRIMARY KEY,
s_name VARCHAR(255),
s_email VARCHAR(255),
s_password VARCHAR(255),
s_phone CHAR(10),
i_follower INT,
i_donate INT,
time_streaming INT,
access_right TINYINT,
i_status TINYINT
);
CREATE TABLE IF NOT EXISTS table_streaming (
s_name VARCHAR(255) PRIMARY KEY,
i_people INT,
hours TIMESTAMP,
i_follower INT,
i_donate INT
);
CREATE TABLE IF NOT EXISTS table_sourceinfo (
s_name VARCHAR(255) PRIMARY KEY,
ip_source VARCHAR(255),
time_login TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP,
time_logout TIMESTAMP NOT NULL DEFAULT CURRENT_TIMESTAMP
);
alter table table_account change time_register time_register timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP;
INSERT INTO table_streaming (s_name, i_people , i_follower , i_donate ) VALUES ('ymmijJ', '5', '4','1000');
ALTER TABLE table_account MODIFY COLUMN i_status INT DEFAULT 0;
-- 在已有表上更改主键约束
ALTER TABLE table_sourceinfo DROP PRIMARY KEY;
-- 在 s_email 字段上创建普通索引
CREATE INDEX idx_s_email ON table_sourceinfo (s_email);
/user/access_right
/user/search
@app.route('/user/search', methods=['POST'])
@cross_origin()
def search():
json_data = request.get_json()
# 檢查是否包含所需的標題
required_titles = ['s_name']
# 檢查是否有任何可插入的標題為空
if any(title not in json_data or not json_data[title].strip() for title in required_titles):
return jsonify({'Error': 'Missing required parameters'}), 400
s_name = json_data.get('s_name', '')
search_name = f"SELECT * FROM table_streaming WHERE s_name LIKE %s"
cursor.execute(search_name, (f"%{s_name}%",))
results = cursor.fetchall()
print(results)
# 如果有结果,则返回状态码 200 和查询结果
if results:
name_list = [{'s_name': result[0]} for result in results]
return jsonify(name_list), 200
else:
# 如果没有结果,则返回状态码 400 和错误消息
return jsonify({'Error': f"No results found for s_name: {s_name}"}), 400
@app.route('/user/live', methods=['POST'])
@cross_origin()
def live():
json_data = request.get_json()
# 檢查是否包含所需的標題
required_titles = ['s_name', 'i_people', 'i_follower', 'i_donate']
# 檢查是否有任何可插入的標題為空
if any(title not in json_data or (type(json_data[title]) == str and not json_data[title].strip()) for title in required_titles):
return jsonify({'Error': 'Missing required parameters'}), 400
# 準備用於插入的標題和值
insert_titles = required_titles
insert_values = [json_data[title] for title in required_titles]
# 檢查 's_name' 是否已經存在於表格中
check_email_query = "SELECT COUNT(*) FROM table_streaming WHERE s_name = %s"
cursor.execute(check_email_query, (json_data['s_name'],))
email_exists = cursor.fetchone()[0]
if email_exists:
return jsonify({'Error': 's_name already exists'}), 400
# 插入資料到 MySQL 表格
insert_query = f"INSERT INTO table_streaming ({', '.join(insert_titles)}) VALUES ({', '.join(['%s']*len(insert_titles))})"
cursor.execute(insert_query, insert_values)
connection.commit()
# 加入 print 語句以記錄成功接收並插入資料
print(f"Received JSON: {json_data}")
return jsonify({'message': 'JSON received successfully'}), 200
/user/login
/user/logout
/user/signup
/user/money_follow
/user/current_people
/user/current_time
/user/ueinfo
/user/alert