Spaces:
Sleeping
Sleeping
Update API for connect
Browse files- app.py +141 -6
- baseline_logs.csv +60 -0
app.py
CHANGED
|
@@ -2,7 +2,7 @@ import gradio as gr
|
|
| 2 |
import datetime
|
| 3 |
import pandas as pd
|
| 4 |
import joblib
|
| 5 |
-
|
| 6 |
import numpy as np
|
| 7 |
import logger_service
|
| 8 |
import os
|
|
@@ -11,6 +11,8 @@ import matplotlib.pyplot as plt
|
|
| 11 |
import seaborn as sns
|
| 12 |
import matplotlib.font_manager as fm
|
| 13 |
import shutil
|
|
|
|
|
|
|
| 14 |
|
| 15 |
# --- 🌟 解決 Matplotlib 中文顯示問題 ---
|
| 16 |
font_path = 'SimHei.ttf'
|
|
@@ -200,6 +202,15 @@ def api_get_chart_data(action_name):
|
|
| 200 |
"action_code": action_code,
|
| 201 |
"data": {"normal": normal_data, "abnormal": abnormal_data}
|
| 202 |
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 203 |
# =====================================================================
|
| 204 |
|
| 205 |
|
|
@@ -244,7 +255,111 @@ def get_dashboard_html():
|
|
| 244 |
</div>
|
| 245 |
"""
|
| 246 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 247 |
def get_plot_data(selected_key):
|
|
|
|
| 248 |
if not selected_key or not AI_READY: return None
|
| 249 |
action_code = ACTION_MAP.get(selected_key)
|
| 250 |
try:
|
|
@@ -419,7 +534,7 @@ def check_anomaly(ip, account, action, log_time):
|
|
| 419 |
fit_X = np.vstack((other_history, relevant_history, new_data_point))
|
| 420 |
strictness = max(2, int(2 + (ow / 100.0) * 4))
|
| 421 |
|
| 422 |
-
model = HDBSCAN(min_cluster_size=strictness, min_samples=2)
|
| 423 |
clusters = model.fit_predict(fit_X)
|
| 424 |
|
| 425 |
if clusters[-1] == -1: return "⚠️異常_作息或行為不符"
|
|
@@ -668,13 +783,12 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
|
|
| 668 |
|
| 669 |
demo.load(fn=timer_update, inputs=[action_dropdown], outputs=[stat_dashboard_display, action_plot])
|
| 670 |
dashboard_timer.tick(fn=timer_update, inputs=[action_dropdown], outputs=[stat_dashboard_display, action_plot])
|
| 671 |
-
action_dropdown.change(fn=get_plot_data, inputs=[action_dropdown], outputs=[action_plot])
|
| 672 |
time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
|
| 673 |
btn_explain_log.click(fn=explain_abnormal_log, inputs=[abnormal_log_input], outputs=[ai_explanation_output])
|
| 674 |
|
| 675 |
-
weight_inputs = [overall_weight, time_weight, ip_weight, device_weight, geo_weight, freq_weight]
|
| 676 |
-
|
| 677 |
-
w_input.change(fn=update_system_weights, inputs=weight_inputs, outputs=[weights_status])
|
| 678 |
|
| 679 |
update_outputs = [main_router, role_tabs, login_msg, welcome_text, store_df_all, store_df_abn, abnormal_log_input]
|
| 680 |
|
|
@@ -735,6 +849,27 @@ with gr.Blocks(title="模擬校園入口與資安防護系統") as demo:
|
|
| 735 |
api_chart_in = gr.Textbox()
|
| 736 |
api_chart_out = gr.JSON()
|
| 737 |
api_chart_btn.click(fn=api_get_chart_data, inputs=[api_chart_in], outputs=[api_chart_out], api_name="get_chart_data")
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 738 |
# =====================================================================
|
| 739 |
|
| 740 |
if __name__ == "__main__":
|
|
|
|
| 2 |
import datetime
|
| 3 |
import pandas as pd
|
| 4 |
import joblib
|
| 5 |
+
import hdbscan
|
| 6 |
import numpy as np
|
| 7 |
import logger_service
|
| 8 |
import os
|
|
|
|
| 11 |
import seaborn as sns
|
| 12 |
import matplotlib.font_manager as fm
|
| 13 |
import shutil
|
| 14 |
+
import io
|
| 15 |
+
import base64
|
| 16 |
|
| 17 |
# --- 🌟 解決 Matplotlib 中文顯示問題 ---
|
| 18 |
font_path = 'SimHei.ttf'
|
|
|
|
| 202 |
"action_code": action_code,
|
| 203 |
"data": {"normal": normal_data, "abnormal": abnormal_data}
|
| 204 |
}
|
| 205 |
+
|
| 206 |
+
def api_get_abnormal_logs():
|
| 207 |
+
"""取得所有異常 Log"""
|
| 208 |
+
abnormal_logs = [log for log in log_history if "異常" in str(log.get("status", "")) or "錯誤" in str(log.get("status", "")) or "受限" in str(log.get("status", ""))]
|
| 209 |
+
return {
|
| 210 |
+
"status": "success",
|
| 211 |
+
"count": len(abnormal_logs),
|
| 212 |
+
"data": abnormal_logs
|
| 213 |
+
}
|
| 214 |
# =====================================================================
|
| 215 |
|
| 216 |
|
|
|
|
| 255 |
</div>
|
| 256 |
"""
|
| 257 |
|
| 258 |
+
def get_plot_data_for_api(selected_key):
|
| 259 |
+
"""API專用版本,返回Base64圖片字符串"""
|
| 260 |
+
if not selected_key or not AI_READY: return None
|
| 261 |
+
action_code = ACTION_MAP.get(selected_key)
|
| 262 |
+
try:
|
| 263 |
+
plt.close('all')
|
| 264 |
+
df_hist = baseline_df[baseline_df['action'] == action_code].copy()
|
| 265 |
+
|
| 266 |
+
df_live = pd.DataFrame(log_history)
|
| 267 |
+
if not df_live.empty:
|
| 268 |
+
df_live['timestamp'] = pd.to_datetime(df_live['timestamp'], errors='coerce')
|
| 269 |
+
df_live = df_live.dropna(subset=['timestamp'])
|
| 270 |
+
df_live = df_live[df_live['action'] == action_code].copy()
|
| 271 |
+
|
| 272 |
+
if not df_live.empty:
|
| 273 |
+
df_combined = pd.concat([df_hist, df_live], ignore_index=True)
|
| 274 |
+
df_combined = df_combined.drop_duplicates(subset=['timestamp', 'account', 'action'])
|
| 275 |
+
else:
|
| 276 |
+
df_combined = df_hist.copy()
|
| 277 |
+
|
| 278 |
+
if df_combined.empty:
|
| 279 |
+
fig, ax = plt.subplots(figsize=(12, 6))
|
| 280 |
+
if os.path.exists(font_path): plt.rc('font', family='SimHei')
|
| 281 |
+
ax.text(0.5, 0.5, f"【{selected_key}】目前尚無資料", ha='center', va='center', fontsize=15)
|
| 282 |
+
# 將圖片轉換為 Base64
|
| 283 |
+
buf = io.BytesIO()
|
| 284 |
+
fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
|
| 285 |
+
buf.seek(0)
|
| 286 |
+
img_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
|
| 287 |
+
buf.close()
|
| 288 |
+
plt.close(fig)
|
| 289 |
+
return f"data:image/png;base64,{img_base64}"
|
| 290 |
+
|
| 291 |
+
df_combined['month'] = df_combined['timestamp'].dt.month
|
| 292 |
+
df_combined['time_of_day'] = df_combined['timestamp'].dt.hour + df_combined['timestamp'].dt.minute / 60.0
|
| 293 |
+
|
| 294 |
+
is_abnormal = df_combined['status'].astype(str).str.contains("異常", na=False)
|
| 295 |
+
df_normal = df_combined[~is_abnormal]
|
| 296 |
+
df_abnormal = df_combined[is_abnormal]
|
| 297 |
+
|
| 298 |
+
fig, ax = plt.subplots(figsize=(12, 6))
|
| 299 |
+
sns.set_theme(style="whitegrid")
|
| 300 |
+
if os.path.exists(font_path): plt.rc('font', family='SimHei')
|
| 301 |
+
plt.rcParams['axes.unicode_minus'] = False
|
| 302 |
+
|
| 303 |
+
has_data = False
|
| 304 |
+
months_order = list(range(1, 13))
|
| 305 |
+
|
| 306 |
+
if not df_normal.empty:
|
| 307 |
+
has_data = True
|
| 308 |
+
sns.stripplot(data=df_normal, x='month', y='time_of_day', jitter=0.3, alpha=0.4, size=5, color='#10b981', order=months_order, ax=ax, label='正常資料')
|
| 309 |
+
|
| 310 |
+
if not df_abnormal.empty:
|
| 311 |
+
has_data = True
|
| 312 |
+
sns.stripplot(data=df_abnormal, x='month', y='time_of_day', jitter=0.3, alpha=0.9, size=9, color='#ef4444', marker='X', order=months_order, ax=ax, label='異常資料')
|
| 313 |
+
|
| 314 |
+
if not has_data:
|
| 315 |
+
ax.text(0.5, 0.5, f"【{selected_key}】目前尚無資料", ha='center', va='center', fontsize=15)
|
| 316 |
+
# 將圖片轉換為 Base64
|
| 317 |
+
buf = io.BytesIO()
|
| 318 |
+
fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
|
| 319 |
+
buf.seek(0)
|
| 320 |
+
img_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
|
| 321 |
+
buf.close()
|
| 322 |
+
plt.close(fig)
|
| 323 |
+
return f"data:image/png;base64,{img_base64}"
|
| 324 |
+
|
| 325 |
+
ax.set_xlabel('月份 (1 ~ 12月)', fontsize=12)
|
| 326 |
+
ax.set_ylabel('時間 (24小時制)', fontsize=12)
|
| 327 |
+
ax.set_yticks(np.arange(0, 25, 2))
|
| 328 |
+
ax.set_ylim(24.5, -0.5)
|
| 329 |
+
|
| 330 |
+
handles, labels = ax.get_legend_handles_labels()
|
| 331 |
+
by_label = dict(zip(labels, handles))
|
| 332 |
+
if by_label: ax.legend(by_label.values(), by_label.keys(), loc='upper right', bbox_to_anchor=(1.15, 1))
|
| 333 |
+
|
| 334 |
+
plt.tight_layout()
|
| 335 |
+
|
| 336 |
+
# 將圖片轉換為 Base64
|
| 337 |
+
buf = io.BytesIO()
|
| 338 |
+
fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
|
| 339 |
+
buf.seek(0)
|
| 340 |
+
img_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
|
| 341 |
+
buf.close()
|
| 342 |
+
plt.close(fig)
|
| 343 |
+
return f"data:image/png;base64,{img_base64}"
|
| 344 |
+
except Exception as e:
|
| 345 |
+
print(f"繪圖失敗: {e}")
|
| 346 |
+
# 返回一個簡單的錯誤圖片
|
| 347 |
+
fig, ax = plt.subplots(figsize=(8, 4))
|
| 348 |
+
ax.text(0.5, 0.5, f"圖表生成失敗: {str(e)}", ha='center', va='center', fontsize=12, color='red')
|
| 349 |
+
ax.set_xlim(0, 1)
|
| 350 |
+
ax.set_ylim(0, 1)
|
| 351 |
+
ax.axis('off')
|
| 352 |
+
|
| 353 |
+
buf = io.BytesIO()
|
| 354 |
+
fig.savefig(buf, format='png', dpi=100, bbox_inches='tight')
|
| 355 |
+
buf.seek(0)
|
| 356 |
+
img_base64 = base64.b64encode(buf.getvalue()).decode('utf-8')
|
| 357 |
+
buf.close()
|
| 358 |
+
plt.close(fig)
|
| 359 |
+
return f"data:image/png;base64,{img_base64}"
|
| 360 |
+
|
| 361 |
def get_plot_data(selected_key):
|
| 362 |
+
"""給Gradio界面使用,返回Figure對象"""
|
| 363 |
if not selected_key or not AI_READY: return None
|
| 364 |
action_code = ACTION_MAP.get(selected_key)
|
| 365 |
try:
|
|
|
|
| 534 |
fit_X = np.vstack((other_history, relevant_history, new_data_point))
|
| 535 |
strictness = max(2, int(2 + (ow / 100.0) * 4))
|
| 536 |
|
| 537 |
+
model = hdbscan.HDBSCAN(min_cluster_size=strictness, min_samples=2)
|
| 538 |
clusters = model.fit_predict(fit_X)
|
| 539 |
|
| 540 |
if clusters[-1] == -1: return "⚠️異常_作息或行為不符"
|
|
|
|
| 783 |
|
| 784 |
demo.load(fn=timer_update, inputs=[action_dropdown], outputs=[stat_dashboard_display, action_plot])
|
| 785 |
dashboard_timer.tick(fn=timer_update, inputs=[action_dropdown], outputs=[stat_dashboard_display, action_plot])
|
| 786 |
+
action_dropdown.change(fn=get_plot_data, inputs=[action_dropdown], outputs=[action_plot], api_name="getPlotData")
|
| 787 |
time_mode.change(fn=toggle_time_input, inputs=time_mode, outputs=custom_time_input)
|
| 788 |
btn_explain_log.click(fn=explain_abnormal_log, inputs=[abnormal_log_input], outputs=[ai_explanation_output])
|
| 789 |
|
| 790 |
+
# weight_inputs = [overall_weight, time_weight, ip_weight, device_weight, geo_weight, freq_weight]
|
| 791 |
+
# 移除所有 UI 欄位的 update_system_weights 綁定,僅保留 API 專用端點
|
|
|
|
| 792 |
|
| 793 |
update_outputs = [main_router, role_tabs, login_msg, welcome_text, store_df_all, store_df_abn, abnormal_log_input]
|
| 794 |
|
|
|
|
| 849 |
api_chart_in = gr.Textbox()
|
| 850 |
api_chart_out = gr.JSON()
|
| 851 |
api_chart_btn.click(fn=api_get_chart_data, inputs=[api_chart_in], outputs=[api_chart_out], api_name="get_chart_data")
|
| 852 |
+
|
| 853 |
+
api_abnormal_logs_btn = gr.Button("API_Abnormal_Logs")
|
| 854 |
+
api_abnormal_logs_out = gr.JSON()
|
| 855 |
+
api_abnormal_logs_btn.click(fn=api_get_abnormal_logs, inputs=[], outputs=[api_abnormal_logs_out], api_name="get_abnormal_logs")
|
| 856 |
+
|
| 857 |
+
api_plot_btn = gr.Button("API_Plot")
|
| 858 |
+
api_plot_in = gr.Textbox()
|
| 859 |
+
api_plot_out = gr.Textbox()
|
| 860 |
+
api_plot_btn.click(fn=get_plot_data_for_api, inputs=[api_plot_in], outputs=[api_plot_out], api_name="get_plot_data_api")
|
| 861 |
+
|
| 862 |
+
# System weights update API endpoint
|
| 863 |
+
api_update_weights_btn = gr.Button("API_Update_Weights")
|
| 864 |
+
api_update_weights_ow = gr.Number(label="Overall Weight")
|
| 865 |
+
api_update_weights_tw = gr.Number(label="Time Weight")
|
| 866 |
+
api_update_weights_iw = gr.Number(label="IP Weight")
|
| 867 |
+
api_update_weights_dw = gr.Number(label="Device Weight")
|
| 868 |
+
api_update_weights_gw = gr.Number(label="Geo Weight")
|
| 869 |
+
api_update_weights_fw = gr.Number(label="Frequency Weight")
|
| 870 |
+
api_update_weights_in = [api_update_weights_ow, api_update_weights_tw, api_update_weights_iw, api_update_weights_dw, api_update_weights_gw, api_update_weights_fw]
|
| 871 |
+
api_update_weights_out = gr.Textbox()
|
| 872 |
+
api_update_weights_btn.click(fn=update_system_weights, inputs=api_update_weights_in, outputs=[api_update_weights_out], api_name="update_system_weights")
|
| 873 |
# =====================================================================
|
| 874 |
|
| 875 |
if __name__ == "__main__":
|
baseline_logs.csv
CHANGED
|
@@ -49999,3 +49999,63 @@ timestamp,ip_address,cookie_id,account,role,action,status
|
|
| 49999 |
2025-12-21 22:29:10,140.124.18.22,baseline_session,student,學生,click_eval_system,success
|
| 50000 |
2025-02-18 22:19:13,61.228.45.112,baseline_session,student,學生,click_course_system,success
|
| 50001 |
2025-06-11 08:40:08,61.228.45.112,baseline_session,student,學生,click_leave_system,success
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 49999 |
2025-12-21 22:29:10,140.124.18.22,baseline_session,student,學生,click_eval_system,success
|
| 50000 |
2025-02-18 22:19:13,61.228.45.112,baseline_session,student,學生,click_course_system,success
|
| 50001 |
2025-06-11 08:40:08,61.228.45.112,baseline_session,student,學生,click_leave_system,success
|
| 50002 |
+
2026-03-29 11:25:30,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50003 |
+
2026-06-13 11:00:00,140.124.71.55 (校內預設),sess_baseline,admin,管理,click_pre_select_system,success
|
| 50004 |
+
2026-10-15 13:00:00,140.124.71.55 (校內預設),sess_baseline,admin,管理,click_pre_select_system,⚠️異常_作息或行為不符
|
| 50005 |
+
2026-03-29 11:25:43,140.124.71.55 (校內預設),sess_baseline,student,學生,login_attempt,success
|
| 50006 |
+
2026-03-29 11:25:45,140.124.71.55 (校內預設),sess_baseline,student,學生,click_istudy,⚠️異常_作息或行為不符
|
| 50007 |
+
2026-03-29 11:25:49,140.124.71.55 (校內預設),sess_baseline,student,學生,click_istudy,⚠️異常_作息或行為不符
|
| 50008 |
+
2026-03-29 11:25:51,140.124.71.55 (校內預設),sess_baseline,student,學生,click_card_loss,success
|
| 50009 |
+
2026-03-29 11:25:53,140.124.71.55 (校內預設),sess_baseline,student,學生,click_course_system,⚠️異常_作息或行為不符
|
| 50010 |
+
2026-03-29 11:25:54,140.124.71.55 (校內預設),sess_baseline,student,學生,click_score_query,⚠️異常_作息或行為不符
|
| 50011 |
+
2026-03-29 11:25:56,140.124.71.55 (校內預設),sess_baseline,student,學生,click_dorm_system,⚠️異常_作息或行為不符
|
| 50012 |
+
2026-03-29 11:25:57,140.124.71.55 (校內預設),sess_baseline,student,學生,click_leave_system,success
|
| 50013 |
+
2026-03-29 11:25:59,140.124.71.55 (校內預設),sess_baseline,student,學生,click_webmail,⚠️異常_作息或行為不符
|
| 50014 |
+
2026-03-29 11:26:00,140.124.71.55 (校內預設),sess_baseline,student,學生,click_vdesk,success
|
| 50015 |
+
2026-03-29 11:26:01,140.124.71.55 (校內預設),sess_baseline,student,學生,click_webmail,⚠️異常_作息或行為不符
|
| 50016 |
+
2026-03-29 11:26:04,140.124.71.55 (校內預設),sess_baseline,student,學生,click_scholarship,success
|
| 50017 |
+
2026-03-29 11:26:06,140.124.71.55 (校內預設),sess_baseline,student,學生,click_scholarship,success
|
| 50018 |
+
2026-03-29 11:26:08,140.124.71.55 (校內預設),sess_baseline,student,學生,click_leave_system,success
|
| 50019 |
+
2026-03-29 11:26:10,140.124.71.55 (校內預設),sess_baseline,student,學生,click_dorm_system,⚠️異常_作息或行為不符
|
| 50020 |
+
2026-03-29 11:26:11,140.124.71.55 (校內預設),sess_baseline,student,學生,click_webmail,⚠️異常_作息或行為不符
|
| 50021 |
+
2026-03-29 11:26:14,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50022 |
+
2026-06-13 11:00:00,140.124.71.55 (校內預設),sess_baseline,admin,管理,click_pre_select_system,success
|
| 50023 |
+
2026-03-29 11:27:35,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50024 |
+
2026-03-29 19:59:38,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50025 |
+
2026-03-29 20:10:17,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50026 |
+
2026-03-29 20:10:47,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50027 |
+
2026-03-29 20:11:07,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50028 |
+
2026-03-29 20:15:19,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50029 |
+
2026-03-29 20:15:31,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50030 |
+
2026-03-29 20:18:07,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50031 |
+
2026-03-29 20:29:45,192.168.1.1,test_cookie,admin,管理,login_attempt,failed_captcha
|
| 50032 |
+
2026-03-29 21:32:17,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50033 |
+
2026-03-29 21:33:13,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50034 |
+
2026-03-29 21:35:14,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50035 |
+
2026-03-29 21:35:31,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50036 |
+
2026-03-29 21:53:57,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50037 |
+
2026-03-29 21:54:17,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50038 |
+
2026-03-29 22:01:26,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50039 |
+
2026-03-29 22:01:39,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50040 |
+
2026-03-29 22:07:04,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50041 |
+
2026-03-29 22:15:21,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50042 |
+
2026-03-29 22:15:29,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50043 |
+
2026-03-29 22:23:16,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,click_add_drop_system,⚠️異常_地理位置受限 (預設防護: 禁止海外異常 IP)
|
| 50044 |
+
2026-03-29 22:23:30,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50045 |
+
2026-03-29 22:28:32,140.124.71.55 (校內預設),sess_baseline,student,學生,login_attempt,success
|
| 50046 |
+
2026-03-29 22:28:34,140.124.71.55 (校內預設),sess_baseline,student,學生,click_eval_system,⚠️異常_作息或行為不符
|
| 50047 |
+
2026-03-29 22:28:35,140.124.71.55 (校內預設),sess_baseline,student,學生,click_istudy,success
|
| 50048 |
+
2026-03-29 22:28:38,140.124.71.55 (校內預設),sess_baseline,admin,管理,login_attempt,success
|
| 50049 |
+
2026-02-25 07:50:00,61.228.45.112 (家裡),sess_baseline,admin,管理,click_course_system,success
|
| 50050 |
+
2026-03-20 03:00:00,61.228.45.112 (家裡),sess_baseline,student,學生,login_attempt,success
|
| 50051 |
+
2026-03-20 03:00:00,61.228.45.112 (家裡),sess_baseline,student,學生,logout,success
|
| 50052 |
+
2026-03-20 03:00:00,61.228.45.112 (家裡),sess_baseline,admin,管理,login_attempt,success
|
| 50053 |
+
2026-03-20 03:00:00,61.228.45.112 (家裡),sess_baseline,admin,管理,logout,success
|
| 50054 |
+
2026-03-20 03:00:00,61.228.45.112 (家裡),sess_baseline,adfa ,Unknown,login_attempt,failed_no_account
|
| 50055 |
+
2026-03-29 22:29:31,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,logout,success
|
| 50056 |
+
2026-03-29 22:29:34,114.32.1.45,sess_9a2b4c6d8e0f,ad fa,Unknown,login_attempt,failed_no_account
|
| 50057 |
+
2026-03-29 22:29:40,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,failed_captcha
|
| 50058 |
+
2026-03-29 22:29:43,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,failed_captcha
|
| 50059 |
+
2026-03-29 22:29:48,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,failed_captcha
|
| 50060 |
+
2026-03-29 22:29:52,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,login_attempt,success
|
| 50061 |
+
2026-03-29 22:29:55,114.32.1.45,sess_9a2b4c6d8e0f,admin,管理,logout,success
|