ラベル onedrive の投稿を表示しています。 すべての投稿を表示
ラベル onedrive の投稿を表示しています。 すべての投稿を表示

2025年10月25日土曜日

Microsoft Graph API を使って個人の OneDrive を操作する方法

Microsoft Graph API を使って個人の OneDrive を操作する方法

概要

前回 OneDrive にアクセスできるトークンの取得まで行いました
今回はそのトークンを使って実際に OneDrive にアクセスします

環境

  • macOS 15.7.1
  • Python 3.12.11

サンプルコード

import json
import os

import requests

TENANT_ID = "xxx"
CLIENT_ID = "xxx"
CLIENT_SECRET = "xxx"
REDIRECT_URI = "http://localhost:8080"
TOKEN_FILE = "onedrive_token.json"
GRAPH_API_BASE = "https://graph.microsoft.com/v1.0"


# =========================
# トークン管理
# =========================
def load_tokens():
    """保存済みトークンを読み込む"""
    if not os.path.exists(TOKEN_FILE):
        raise FileNotFoundError(f"{TOKEN_FILE} が存在しません。先にトークン取得を実行してください。")
    with open(TOKEN_FILE, "r", encoding="utf-8") as f:
        return json.load(f)


def save_tokens(tokens):
    """トークンを保存"""
    with open(TOKEN_FILE, "w", encoding="utf-8") as f:
        json.dump(tokens, f, indent=2)


def refresh_access_token(refresh_token, client_id, client_secret, redirect_uri):
    """リフレッシュトークンからアクセストークンを更新"""
    token_url = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
    data = {
        "client_id": client_id,
        "client_secret": client_secret,
        "redirect_uri": redirect_uri,
        "grant_type": "refresh_token",
        "refresh_token": refresh_token
    }
    res = requests.post(token_url, data=data)
    res.raise_for_status()
    return res.json()


# =========================
# OneDrive 操作
# =========================
def get_headers(access_token):
    return {"Authorization": f"Bearer {access_token}"}


def upload_file(access_token, local_path, remote_name):
    """小さなファイルをアップロード"""
    url = f"{GRAPH_API_BASE}/me/drive/root:/{remote_name}:/content"
    with open(local_path, "rb") as f:
        res = requests.put(url, headers=get_headers(access_token), data=f)
    if res.status_code in (200, 201):
        print(f"✅ アップロード成功: {remote_name}")
    else:
        print(f"❌ アップロード失敗 ({res.status_code}): {res.text}")


def list_files(access_token):
    """ルートディレクトリのファイル一覧取得"""
    url = f"{GRAPH_API_BASE}/me/drive/root/children"
    res = requests.get(url, headers=get_headers(access_token))
    if res.status_code == 200:
        items = res.json().get("value", [])
        print("📄 OneDrive ファイル一覧:")
        for item in items:
            print(f" - {item['name']}")
    else:
        print(f"❌ 取得失敗 ({res.status_code}): {res.text}")


def delete_file(access_token, remote_name):
    """ファイル削除"""
    url = f"{GRAPH_API_BASE}/me/drive/root:/{remote_name}"
    res = requests.delete(url, headers=get_headers(access_token))
    if res.status_code in (204, 200):
        print(f"🗑️ 削除成功: {remote_name}")
    else:
        print(f"❌ 削除失敗 ({res.status_code}): {res.text}")


# =========================
# メイン
# =========================
if __name__ == "__main__":
    tokens = load_tokens()
    access_token = tokens["access_token"]

    # 必要に応じてリフレッシュ
    tokens = refresh_access_token(tokens["refresh_token"], CLIENT_ID, CLIENT_SECRET, REDIRECT_URI)
    access_token = tokens["access_token"]
    save_tokens(tokens)

    # サンプルファイル作成
    sample_file = "test.txt"
    with open(sample_file, "w", encoding="utf-8") as f:
        f.write("Hello OneDrive via Graph API!")

    # アップロード
    upload_file(access_token, sample_file, "test.txt")

    # ファイル一覧
    list_files(access_token)

    # 削除(必要であればコメント解除)
    delete_file(access_token, "test.txt")

ポイント

  • トークンが切れた場合にリフレッシュトークを使って再度トークンを取得します
  • 毎回行っても問題ないので実際は毎回リフレッシュトークを使って問い合わせたほうがいいです
  • トークンをファイルで保存していますが漏洩すると大変なので管理には注意しましょう

最後に

Python で OneDrive の操作をしてみました
認証が面倒ですが一度認証してしまえばあとはスクリプトを実行するだけです

アプリのシークレットに期限があるのでその期限がすぎたら再度ブラウザを開いてトークンファイルを更新する必要があります

2025年10月24日金曜日

Microsoft Graph API を使って個人の OneDrive にアクセスする方法

Microsoft Graph API を使って個人の OneDrive にアクセスする方法

概要

前回 Graph API に入門しました
今回は個人用の OneDrive アクセスしてみます
なそアプリーケーション権限は使えず「委任されたアクセス許可」に変更する必要があるので注意してください

簡単に言うと API をコールするためのアクセストークンを一度ブラウザを開いて取得しなければなりません

環境

  • macOS 15.7.1
  • Python 3.12.11

サポートされているアカウントの種類

  • 任意の組織ディレクトリ内のアカウント (任意の Microsoft Entra ID テナント - マルチテナント) と個人用の Microsoft アカウント (Skype、Xbox など)

もしくは

  • 個人用 Microsoft アカウントのみ

権限の設定

  • 管理 -> API のアクセス許可 -> アクセス許可の追加 -> Microsoft Graph -> 委任されたアクセス許可
    • Files.ReadWrite.All
    • Sites.ReadWrite.All
    • User.Read
    • offline_access
  • 既定のディレクトリに管理者の権限を与えますを選択

コールバックURLの設定

  • 管理 -> 認証 -> URLの追加 -> http://localhost:8080

トークンの取得

これは一度だけ実行します
表示された URL にブラウザでアクセスしログインします

  • vim ./fetch_token.py
import http.server
import json
import socketserver
import urllib.parse
import webbrowser

import requests

# ======== 設定 ========
TENANT_ID = "xxx"
CLIENT_ID = "xxx"
CLIENT_SECRET = "xxx"
REDIRECT_URI = "http://localhost:8080"
SCOPES = ["Files.ReadWrite.All", "Sites.ReadWrite.All", "User.Read", "offline_access"]
TOKEN_FILE = "onedrive_token.json"
# =======================


def start_local_server():
    """localhostで認可コードを受け取るための簡易HTTPサーバー"""
    class Handler(http.server.SimpleHTTPRequestHandler):
        def do_GET(self):
            query = urllib.parse.urlparse(self.path).query
            params = urllib.parse.parse_qs(query)
            if "code" in params:
                setattr(self.server, "auth_code", params["code"][0])
                self.send_response(200)
                self.end_headers()
                self.wfile.write(b"Authorization successful. You can close this window.")
            else:
                self.send_response(400)
                self.end_headers()
                self.wfile.write(b"Missing authorization code.")

    with socketserver.TCPServer(("localhost", 8080), Handler) as httpd:
        setattr(httpd, "auth_code", None)
        print("🌐 ローカルサーバー起動中 (http://localhost:8080)")
        httpd.handle_request()
        return getattr(httpd, "auth_code", None)


def get_tokens(auth_code):
    """認可コードからトークンを取得"""
    token_url = "https://login.microsoftonline.com/consumers/oauth2/v2.0/token"
    data = {
        "client_id": CLIENT_ID,
        "redirect_uri": REDIRECT_URI,
        "client_secret": CLIENT_SECRET,
        "code": auth_code,
        "grant_type": "authorization_code"
    }
    res = requests.post(token_url, data=data)
    res.raise_for_status()
    return res.json()


def save_tokens(tokens):
    """トークンをローカルに保存"""
    with open(TOKEN_FILE, "w", encoding="utf-8") as f:
        json.dump(tokens, f, indent=2)
    print(f"💾 トークンを保存しました → {TOKEN_FILE}")


def main():
    # 1️⃣ 認可URLを生成
    params = {
        "client_id": CLIENT_ID,
        "response_type": "code",
        "redirect_uri": REDIRECT_URI,
        "response_mode": "query",
        "scope": " ".join(SCOPES)
    }
    auth_url = f"https://login.microsoftonline.com/consumers/oauth2/v2.0/authorize?{urllib.parse.urlencode(params)}"

    print("\n🔗 以下のURLを開いてMicrosoftアカウントでサインインしてください:")
    print(auth_url)
    webbrowser.open(auth_url)

    # 2️⃣ 認可コード受け取り
    auth_code = start_local_server()
    if not auth_code:
        print("❌ 認可コードを取得できませんでした。")
        return

    print(f"✅ 認可コード取得成功: {auth_code[:20]}...")

    # 3️⃣ トークン取得
    tokens = get_tokens(auth_code)
    print("✅ アクセストークン・リフレッシュトークン取得成功")
    save_tokens(tokens)

    print("\n🧾 トークン内容:")
    print(json.dumps(tokens, indent=2))


if __name__ == "__main__":
    main()

動作確認

  • pipenv run python ./app.py

でブラウザが開いたらMicrosoft アカウントでログインしアプリに許可を与えます
成功するとトークン情報が onedrive_token.json に保存されるので今後はこれを使って OneDrive にアクセスします

最後に

Python から OneDrive にアクセスするためのトークンの取得まで行いました
次回は実際にファイルのアップロードや取得などを行います

Onedrive for bussiness だとアプリケーションの許可の権限で操作できるようです