FlaskからMicrosoft Graph APIでOneDrive for Businessにアクセスしてみる
Pythonを使ってAPI経由で、
OneDrive for Businessのファイルを扱いたく、実装方法を調べていたのですが。
難しくは無いものの、
いろいろと混乱してしまい時間がかかったので、メモを残しておこうと思います。
アクセスするサービス・利用するAPI
APIを考える前に、
マイクロソフトが提供しているサービスには、
以下のように「OneDrive for Business」と似たサービスがあります。
- OneDrive ... 家庭向け、個人のファイルのクラウドストレージ
- OneDrive for Business ... 法人向け、個人のファイルのクラウドストレージ
- SharePoint Online ... 法人向け、組織での情報共有用のクラウドストレージ
これらを別のものと認識しておかないと、情報を調べるときに混乱してしまいます。
特に「OneDrive」「OneDrive for Business」が全く別物であることには注意が必要です。
このエントリでは、次の「Microsoft Graph API」を利用します。
Microsoft Graph
これに対しても似たようなものとして、
「Office 365 API」「SharePoint API」などがあるので、混乱しないように注意します。
特に、GitHubでサンプルを探す時など
Azure Active Directoryへのアプリの登録
アプリケーションを実装する前に、
Azure Active Directoryに実装するアプリを登録しておきます。
登録はAzureポータルから実施します。
Microsoft Azure ポータル
登録方法は、以下を参考にして下さい。
Microsoft ID プラットフォームにアプリケーションを登録する | Microsoft Docs
注意点としては、
- リダイレクトURIに
http://localhost:5000/login/azure/authorizedの指定が必要 - APIのアクセス許可に
Microsoft Graph - File.Readの指定が必要
Flaskでの実装
次に、Flaskアプリケーションの実装を行います。
Flaskの環境作り
まず、単純なFlaskのアプリを作成しておきます。
venvの環境を用意して、Flaskをインストールします。
python -m venv venv
. venv/bin/activate
pip install Flask
以下のように「main.py」を作成します。
from flask import Flask
app = Flask(__name__)
@app.route('/')
def home():
return 'hello'
以下のコマンドで実行、ブラウザから表示を確認します。
export FLASK_APP=main.py
export FLASK_ENV=development
flask run
OAuth2による認証
FlaskアプリにOAuth2による認証を追加します。
ここではFlask-Danceを利用します。
Flask-Dance | GitHub
Flask-Danceをインストールします。
pip install Flask-Dance
アプリの登録で取得した、ClientKey, ClientSecretKeyを設定ファイルに記載します。
SECRET_KEY='※ここにSECRET KEY(アプリ固有の適当な文字列)※'
AUTHORITY='https://login.microsoftonline.com'
CLIENT_ID='※ここにアプリのClientKey※'
CLIENT_SECRET='※ここにアプリのClientSecretKey※'
main.pyを変更して、ログイン・ログアウト機能を実装します。
from flask import Flask, url_for, redirect, session
from flask_dance.contrib.azure import make_azure_blueprint, azure
import os
app = Flask(__name__)
app.config.from_pyfile('app.cfg')
conf = app.config
os.environ['OAUTHLIB_RELAX_TOKEN_SCOPE'] = '1'
blueprint = make_azure_blueprint(
client_id=conf["CLIENT_ID"],
client_secret=conf["CLIENT_SECRET"],
scope=['openid'],
redirect_url='{0}/'.format('http://localhost:5000/')
)
app.register_blueprint(blueprint, url_prefix="/login")
@app.route("/logon")
def logon():
return redirect(url_for("azure.login"))
@app.route("/logoff")
def logoff():
if 'azure_oauth_token' in session:
del session['azure_oauth_token']
if 'azure_oauth_state' in session:
del session['azure_oauth_state']
return redirect(url_for("home"))
@app.route('/')
def home():
if azure.authorized:
resp = azure.get("/v1.0/me")
return 'hello, {0}. / <a href="/logoff">logoff</a>'.format(resp.json()['displayName'])
return 'hello. / <a href="/logon">logon</a>'
OAUTHLIB_RELAX_TOKEN_SCOPEを指定しているのは、
Flask-Dance側、ActiveDirectoryのアプリ登録側のscopeが不一致でも、
認証を継続させるために指定しています。
変更出来たら、以下のコマンドで実行、ブラウザから表示を確認します。
ローカルの開発環境は、http(SSLでは無い)なので、
OAUTHLIB_INSECURE_TRANSPORTを指定して、実行させています。
export OAUTHLIB_INSECURE_TRANSPORT=1
flask run
OneDrive for Businessへのアクセス
後は、APIを呼び出して、OneDrive for Businessにアクセスするだけです。
例えば、home関数を以下のように書き換えると、
ルート階層のファイル一覧を表示することが出来ます。
@app.route('/')
def home():
if azure.authorized:
resp = azure.get("/v1.0/me/drive/root/children")
files = '<br>'.join([f['name'] for f in resp.json()['value']])
return '*file list*<br>{0}<br><br><a href="/logoff">logoff</a>'.format(files)
return 'hello. / <a href="/logon">logon</a>'
その他の、具体的な操作は、以下のドキュメントを見れば分かると思います。
Microsoft Graph でのファイルの作業 | Microsoft Graph | Microsoft Docs
tokenのリフレッシュ
OAuth2の認証で得たtokenは、有効期限があるので、
裏で定期的なバッチ処理を行う場合などは、tokenをリフレッシュする必要があります。
リフレッシュ用のrefresh tokenを取得したい場合は、
「Microsoft Azure ポータル」で
「APIのアクセス許可」にMicrosoft Graph - offline_accessの指定が必要になります。
tokenのリフレッシュ方法は、
Flask-Danceは、Requests-OAuthlibを利用しているので、以下が参考になります。
Refreshing tokens | Requests-OAuthlib
具体的に書くと、blueprint.sessionの実体は、
Requests-OAuthlibのOAuth2Sessionなので、
以下のように呼び出すと、新しいtokenを取得する事が出来ます。
extra = {
'client_id': conf["CLIENT_ID"],
'client_secret': conf["CLIENT_SECRET"],
}
new_token = blueprint.session.refresh_token(blueprint.token_url, **extra)
実際にバッチ処理で扱う場合は、
token/refresh tokenをFlaskのセッション変数で無く、DB等に保持させる必要がありますが、
その対応は、Flask-Danceのドキュメントが参考になります。
Token Storages | Flask-Dance
バッチ処理・tokenのリフレッシュあたりは、やり出すと長いので、
以上のとおり、参考程度にとどめておきます。
Discussion