diff --git a/.idea/.gitignore b/.idea/.gitignore
new file mode 100644
index 0000000..35410ca
--- /dev/null
+++ b/.idea/.gitignore
@@ -0,0 +1,8 @@
+# 默认忽略的文件
+/shelf/
+/workspace.xml
+# 基于编辑器的 HTTP 客户端请求
+/httpRequests/
+# Datasource local storage ignored files
+/dataSources/
+/dataSources.local.xml
diff --git a/.idea/E5-ReLogin.iml b/.idea/E5-ReLogin.iml
new file mode 100644
index 0000000..8e75147
--- /dev/null
+++ b/.idea/E5-ReLogin.iml
@@ -0,0 +1,10 @@
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/inspectionProfiles/profiles_settings.xml b/.idea/inspectionProfiles/profiles_settings.xml
new file mode 100644
index 0000000..105ce2d
--- /dev/null
+++ b/.idea/inspectionProfiles/profiles_settings.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000..7d1607b
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000..9cf8123
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000..35eb1dd
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/auth_handler.py b/auth_handler.py
new file mode 100644
index 0000000..e2a1c38
--- /dev/null
+++ b/auth_handler.py
@@ -0,0 +1,14 @@
+from http.server import BaseHTTPRequestHandler
+from urllib.parse import parse_qs, urlparse
+
+class AuthHandler(BaseHTTPRequestHandler):
+ def do_GET(self):
+ query = urlparse(self.path).query
+ params = parse_qs(query)
+ if "code" in params:
+ code = params["code"][0]
+ self.send_response(200)
+ self.send_header("Content-type", "text/html; charset=utf-8")
+ self.end_headers()
+ self.wfile.write("
登录成功!请返回启动器
".encode('utf-8'))
+ print(f"Received code: {code}") # 调试日志
\ No newline at end of file
diff --git a/main.py b/main.py
new file mode 100644
index 0000000..3e9a058
--- /dev/null
+++ b/main.py
@@ -0,0 +1,137 @@
+import requests
+import webbrowser
+import time
+import pyperclip
+from http.server import HTTPServer
+from urllib.parse import parse_qs, urlparse
+import threading
+from tkinter import Tk, Toplevel, Label, Button, Frame # 使用标准 Tkinter
+
+class AuthHandler:
+ def __init__(self):
+ pass # 如果需要额外处理,可以在这里实现
+
+class MicrosoftAuth:
+ def __init__(self, launcher):
+ self.launcher = launcher
+ self.login_window = None
+
+ def start_auth_server(self):
+ server_address = ("", 8080)
+ httpd = HTTPServer(server_address, AuthHandler)
+ server_thread = threading.Thread(target=httpd.serve_forever)
+ server_thread.daemon = True
+ server_thread.start()
+
+ def start_microsoft_login(self):
+ device_url = "https://login.microsoftonline.com/consumers/oauth2/v2.0/devicecode"
+ device_response = requests.post(device_url, data={
+ "client_id": "23c6a66b-9584-4cc7-831c-ad3785d0fc47",
+ "scope": "offline_access user.read mail.read"
+ })
+
+ if device_response.status_code != 200:
+ print(f"获取设备代码失败: {device_response.status_code}")
+ return
+
+ device_data = device_response.json()
+ user_code = device_data["user_code"]
+ verification_url = device_data["verification_uri"]
+
+ self.show_login_instruction(verification_url, user_code)
+
+ threading.Thread(target=self.poll_device_code, args=(device_data["device_code"],)).start()
+
+ def show_login_instruction(self, verification_url, user_code):
+ self.login_window = Toplevel()
+ self.login_window.geometry("400x200")
+ self.login_window.title("微软登录")
+
+ webbrowser.open(verification_url)
+ pyperclip.copy(user_code)
+
+ Label(self.login_window, text=f"访问 {verification_url} 并输入代码: {user_code}").pack(pady=10)
+
+ btn_frame = Frame(self.login_window)
+ btn_frame.pack(pady=10)
+
+ Button(btn_frame, text="打开网页", command=lambda: webbrowser.open(verification_url)).pack(side="left", padx=5)
+ Button(btn_frame, text="复制代码", command=lambda: pyperclip.copy(user_code)).pack(side="right", padx=5)
+
+ def poll_device_code(self, device_code):
+ token_url = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
+ while True:
+ token_response = requests.post(token_url, data={
+ "client_id": "23c6a66b-9584-4cc7-831c-ad3785d0fc47",
+ "device_code": device_code,
+ "grant_type": "urn:ietf:params:oauth:grant-type:device_code"
+ })
+
+ if token_response.status_code == 200:
+ token_data = token_response.json()
+ access_token = token_data["access_token"]
+
+ profile_url = "https://graph.microsoft.com/v1.0/me"
+ headers = {"Authorization": f"Bearer {access_token}"}
+ profile_response = requests.get(profile_url, headers=headers)
+ profile = profile_response.json()
+
+ self.launcher.update_user_info(profile["displayName"])
+ self.launcher.save_tokens(token_data)
+
+ if self.login_window is not None and self.login_window.winfo_exists():
+ self.login_window.destroy()
+
+ print("登录成功!")
+ return
+
+ elif token_response.status_code == 400:
+ error = token_response.json().get("error")
+ if error != "authorization_pending":
+ print(f"登录失败: {error}")
+ return
+
+ time.sleep(5)
+
+class Launcher:
+ def __init__(self):
+ self.root = Tk()
+ self.root.geometry("300x200")
+ self.root.title("Launcher")
+ self.user_info_label = Label(self.root, text="未登录")
+ self.user_info_label.pack(pady=20)
+
+ self.microsoft_auth = MicrosoftAuth(self)
+
+ self.add_buttons()
+
+ def update_user_info(self, display_name):
+ self.user_info_label.configure(text=f"已登录: {display_name}")
+
+ def save_tokens(self, token_data):
+ print("令牌已保存:", token_data)
+
+ def start_login(self):
+ # 启动微软登录逻辑
+ self.microsoft_auth.start_auth_server()
+ self.microsoft_auth.start_microsoft_login()
+
+ def logout(self):
+ # 退出登录逻辑
+ self.user_info_label.configure(text="未登录")
+ if self.microsoft_auth.login_window is not None and self.microsoft_auth.login_window.winfo_exists():
+ self.microsoft_auth.login_window.destroy()
+
+ def add_buttons(self):
+ button_frame = Frame(self.root)
+ button_frame.pack(pady=10)
+
+ Button(button_frame, text="开始登录", command=self.start_login).pack(side="left", padx=5)
+ Button(button_frame, text="退出登录", command=self.logout).pack(side="right", padx=5)
+
+ def run(self):
+ self.root.mainloop()
+
+if __name__ == "__main__":
+ launcher = Launcher()
+ launcher.run()
\ No newline at end of file