logo NodeSeekbeta

自动获取onedrive配置并添加alist存储

更新:适用于2024年6月之前已注册过azure应用的微软账户

为了不用alist不开源的api(因为不知道那个api都会干什么),用gpt写了个python脚本

运行方法是你要有python环境

然后python alist-onedrive.py 一下了

准备工作

https://portal.azure.com 用你想要挂载onedrive的E5或者个人账户登录

然后去 https://portal.azure.com/#view/Microsoft_AAD_RegisteredApps/ApplicationsListBlade 创建应用程序

注意
受支持的账户类型选 任何组织目录(任何 Microsoft Entra ID 租户 - 多租户)中的帐户和个人 Microsoft 帐户(例如 Skype、Xbox)
重定向URI 选 Web 是 http://localhost:53682/

然后记住这个 是 client_id

然后添加客户端密码

记住这个东西是 client_secret

然后去添加API权限 Files.ReadWrite.All offline_access Sites.Read.All





然后运行py脚本就行了

输入区可以写在or后面 也可以按照命令行提示输入

脚本会打开默认浏览器 接受权限


然后就成功了

遇到这个问题把代理全退出就好了

import http.server
import webbrowser
import urllib.parse
import requests
import json
import os

# ========== 输入区 ==========
CLIENT_ID = input("🔑 请输入 Azure client_id: ").strip() or " client_id"
CLIENT_SECRET = input("🔒 请输入 Azure client_secret: ").strip() or "client_secret"
ALIST_REMARK = input("📝 Alist 挂载备注(如 OneDrive): ").strip() or "My OneDrive"
ALIST_PATH = input("📂 Alist 显示路径(如 /onedrive): ").strip() or "/onedrive"
ONEDRIVE_ROOT = input("📁 OneDrive 根路径(如 / 或 /某个子目录): ").strip() or "/"
ALIST_URL = input("📁  Alist 服务地址: ").strip() or "http://localhost:5244" 
ALIST_USER = input("👤 Alist 管理员用户名: ").strip() or "admin"
ALIST_PASS = input("🔑 Alist 管理员密码: ").strip() or "123456"

# ========== 常量区 ==========
REDIRECT_URI = "http://localhost:53682/"
SCOPES = "Files.ReadWrite.All offline_access User.Read Sites.Read.All"
TOKEN_URL = "https://login.microsoftonline.com/common/oauth2/v2.0/token"
CONFIG_OUTPUT_PATH = "alist_onedrive_config.json"

auth_code = None

class OAuthHandler(http.server.BaseHTTPRequestHandler):
    def do_GET(self):
        global auth_code
        params = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
        if "code" in params:
            auth_code = params["code"][0]
            self.send_response(200)
            self.send_header("Content-type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write("<h1>✅ 授权成功!请返回终端。</h1>".encode("utf-8"))
        else:
            self.send_response(400)
            self.send_header("Content-type", "text/html; charset=utf-8")
            self.end_headers()
            self.wfile.write("<h1>❌ 授权失败,未获取到 code。</h1>".encode("utf-8"))


def start_server():
    server = http.server.HTTPServer(('localhost', 53682), OAuthHandler)
    server.handle_request()

def get_alist_token(alist_url: str, username: str, password: str, otp: str = None) -> str:
    login_url = f"{alist_url}/api/auth/login"
    payload = {
        "username": username,
        "password": password
    }
    if otp:
        payload["otp_code"] = otp

    res = requests.post(login_url, json=payload)
    if res.status_code != 200:
        raise Exception("❌ 无法连接 Alist 登录接口")
    data = res.json()
    if data.get("code") != 200:
        raise Exception(f"❌ 登录失败:{data.get('message')}")
    return data["data"]["token"]

def main():
    print("🌐 打开浏览器进行 OneDrive 授权...")
    auth_url = (
        f"https://login.microsoftonline.com/common/oauth2/v2.0/authorize"
        f"?client_id={CLIENT_ID}"
        f"&response_type=code"
        f"&redirect_uri={urllib.parse.quote(REDIRECT_URI)}"
        f"&scope={urllib.parse.quote(SCOPES)}"
    )
    webbrowser.open(auth_url)
    start_server()

    if not auth_code:
        print("❌ 未获取到授权码。")
        return

    print("🔄 获取 refresh_token 中...")
    data = {
        "client_id": CLIENT_ID,
        "client_secret": CLIENT_SECRET,
        "code": auth_code,
        "redirect_uri": REDIRECT_URI,
        "grant_type": "authorization_code"
    }
    response = requests.post(TOKEN_URL, data=data)
    if response.status_code != 200:
        print("❌ 获取 token 失败:")
        print(response.text)
        return

    tokens = response.json()
    refresh_token = tokens.get("refresh_token")
    if not refresh_token:
        print("❌ token 响应中未找到 refresh_token。")
        return

    # 获取 Alist 管理 token
    TWO_FA_CODE = input("📲 请输入两步验证码(如启用)[可留空]: ").strip()
    print("🔐 正在登录 Alist...")
    alist_token = get_alist_token(ALIST_URL, ALIST_USER, ALIST_PASS, TWO_FA_CODE)

    # 构造符合 Alist API 要求格式的配置
    payload = {
        "mount_path": ALIST_PATH,
        "order": 0,
        "remark": ALIST_REMARK,
        "cache_expiration": 30,
        "web_proxy": False,
        "webdav_policy": "302_redirect",
        "down_proxy_url": "",
        "order_by": "",
        "order_direction": "",
        "extract_folder": "",
        "enable_sign": False,
        "driver": "Onedrive",
        "addition": json.dumps({
            "root_folder_path": ONEDRIVE_ROOT,
            "region": "global",
            "is_sharepoint": False,
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
            "redirect_uri": REDIRECT_URI,
            "refresh_token": refresh_token,
            "site_id": "",
            "chunk_size": 5,
            "custom_host": ""
        }, ensure_ascii=False)
    }

    print("🚀 向 Alist 推送挂载配置...")
    api_url = f"{ALIST_URL}/api/admin/storage/create"
    headers = {
        "Content-Type": "application/json",
        "Authorization": alist_token
    }
    res = requests.post(api_url, json=payload, headers=headers)

    if res.status_code == 200 and res.json().get("code") == 200:
        print("✅ 成功添加 OneDrive 挂载!请在 Alist 后台查看。")
    else:
        print("❌ 推送失败:")
        print(res.text)

    # 同时写入配置文件备份
    print(f"💾 正在写入配置到 {CONFIG_OUTPUT_PATH}...")
    with open(CONFIG_OUTPUT_PATH, "w", encoding="utf-8") as f:
        json.dump(payload, f, ensure_ascii=False, indent=2)


if __name__ == "__main__":
    main()

  • 拿你的代码用AI改了个Google Drive的,不过去掉了自动导入alist

    import http.server
    import webbrowser
    import urllib.parse
    import requests
    import json
    import os
    
    # ========== 常量区 - 请在这里定义你的 CLIENT_ID 和 CLIENT_SECRET ==========
    # 从 Google Cloud Console 获取的客户端 ID
    CLIENT_ID = "YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com"  # 替换为你的实际客户端 ID
    # 从 Google Cloud Console 获取的客户端秘钥
    CLIENT_SECRET = "YOUR_GOOGLE_CLIENT_SECRET"  # 替换为你的实际客户端秘钥
    
    # 重定向 URI,必须与你在 Google Cloud Console 中设置的“桌面应用”重定向 URI 之一匹配
    # 通常是 http://localhost:<port>,这里使用一个常用端口
    REDIRECT_URI = "http://localhost:53682" # 确保这个端口没有被其他程序占用
    
    # Google Drive API 授权范围
    # drive: 访问用户所有 Google Drive 文件
    # drive.appdata: 访问应用特定数据(通常用于应用自己的配置或数据)
    # offline_access: 允许获取 refresh_token,以便在没有用户交互的情况下刷新 access_token
    SCOPES = "https://www.googleapis.com/auth/drive https://www.googleapis.com/auth/drive.appdata profile email openid" # 更多通用范围
    
    # Google OAuth2 授权和 Token 端点
    AUTH_URL = "https://accounts.google.com/o/oauth2/v2/auth"
    TOKEN_URL = "https://oauth2.googleapis.com/token"
    
    # 全局变量用于存储授权码
    auth_code = None
    
    class OAuthHandler(http.server.BaseHTTPRequestHandler):
        def do_GET(self):
            global auth_code
            params = urllib.parse.parse_qs(urllib.parse.urlparse(self.path).query)
            if "code" in params:
                auth_code = params["code"][0]
                self.send_response(200)
                self.send_header("Content-type", "text/html; charset=utf-8")
                self.end_headers()
                self.wfile.write("<h1>✅ 授权成功!请返回终端。</h1><p>您可以关闭此浏览器标签页。</p>".encode("utf-8"))
            elif "error" in params:
                error_msg = params["error"][0]
                self.send_response(400)
                self.send_header("Content-type", "text/html; charset=utf-8")
                self.end_headers()
                self.wfile.write(f"<h1>❌ 授权失败!错误信息:{error_msg}</h1>".encode("utf-8"))
            else:
                self.send_response(400)
                self.send_header("Content-type", "text/html; charset=utf-8")
                self.end_headers()
                self.wfile.write("<h1>❌ 授权失败,未获取到 code。</h1>".encode("utf-8"))
    
    def start_local_server():
        """启动本地 HTTP 服务器监听重定向回调"""
        server_address = ('localhost', urllib.parse.urlparse(REDIRECT_URI).port)
        httpd = http.server.HTTPServer(server_address, OAuthHandler)
        print(f"🌍 正在监听 {REDIRECT_URI} 等待授权回调...")
        httpd.handle_request() # 只处理一个请求就关闭
    
    def get_google_refresh_token():
        """
        通过 OAuth2 流程获取 Google Drive 的 refresh_token。
        """
        print("\n🌐 正在打开浏览器进行 Google Drive 授权...")
        
        # 构造授权 URL
        auth_params = {
            "client_id": CLIENT_ID,
            "redirect_uri": REDIRECT_URI,
            "response_type": "code",
            "scope": SCOPES,
            "access_type": "offline", # 关键参数,确保获取 refresh_token
            "prompt": "consent" # 每次都要求用户同意,确保能获取 refresh_token
        }
        auth_url = f"{AUTH_URL}?{urllib.parse.urlencode(auth_params)}"
        
        webbrowser.open(auth_url)
        
        # 启动本地服务器等待回调
        start_local_server()
    
        if not auth_code:
            print("\n❌ 未获取到授权码。授权流程可能失败。")
            return None
    
        print("\n🔄 正在使用授权码获取 refresh_token...")
        
        # 构造获取 token 的请求数据
        token_data = {
            "client_id": CLIENT_ID,
            "client_secret": CLIENT_SECRET,
            "code": auth_code,
            "redirect_uri": REDIRECT_URI,
            "grant_type": "authorization_code"
        }
        
        try:
            response = requests.post(TOKEN_URL, data=token_data)
            response.raise_for_status() # 如果状态码不是 2xx,则抛出异常
            
            tokens = response.json()
            refresh_token = tokens.get("refresh_token")
            
            if refresh_token:
                print("\n✅ 成功获取到 refresh_token!")
                print(f"你的 refresh_token 是: \n\n{refresh_token}\n")
                print("请复制此 refresh_token 并将其用于 Alist 配置。")
                
                # 可选:保存到文件
                with open("google_drive_refresh_token.txt", "w") as f:
                    f.write(refresh_token)
                print("refresh_token 已保存到 'google_drive_refresh_token.txt' 文件中。")
                
                return refresh_token
            else:
                print("\n❌ 在 token 响应中未找到 refresh_token。")
                print("响应内容:", json.dumps(tokens, indent=2))
                print("请检查你的客户端配置和授权范围 (确保包含 offline_access)。")
                return None
                
        except requests.exceptions.HTTPError as e:
            print(f"\n❌ 获取 token 失败,HTTP 错误:{e}")
            print(f"响应内容:{e.response.text}")
            return None
        except requests.exceptions.RequestException as e:
            print(f"\n❌ 请求 token 失败:{e}")
            return None
    
    if __name__ == "__main__":
        # 确保 CLIENT_ID 和 CLIENT_SECRET 在脚本顶部已正确填写
        if CLIENT_ID == "YOUR_GOOGLE_CLIENT_ID.apps.googleusercontent.com" or CLIENT_SECRET == "YOUR_GOOGLE_CLIENT_SECRET":
            print("⚠️ 警告:请在脚本中修改 CLIENT_ID 和 CLIENT_SECRET 为你在 Google Cloud Console 中获取的值。")
            print("请参考脚本开头的注释进行修改。")
        else:
            get_google_refresh_token()
    
    
    
  • 试试 xhj003

  • 感谢 试试!

  • 感谢 去试试

  • 感谢,先收藏一下

  • 感谢 xhj016

  • 点赞,之前获取token都是用rclone的

  • alist已经卖给公司了,别搭了

  • @leenhawk #7 用的旧版的 一直没升级 暂时应该没事

你好啊,陌生人!

我的朋友,看起来你是新来的,如果想参与到讨论中,点击下面的按钮!

📈用户数目📈

目前论坛共有59945位seeker

🎉欢迎新用户🎉