Box API の Java SDK を試してみる
まとめ記事ができました
このスクラップについて
今後の仕事で Box API の Java SDK を使うかも知れないので今のうちに基本的な使い方を調べておこうと思う。
Box サインアップ
Box のアカウントを持っていないので作成してみる。
個人向けの Individual プランであれば無料で使用できる。
サインアップはメールアドレスか Google アカウントでできる。
今回は手軽に Google アカウントを使用する。
サインアップするとすぐに利用できる、素晴らしい。
アップロード
動作確認のためにあると便利そうなので事前に適当なファイルを作成してアップロードしておく。
touch hello-box.txt
HELLO BOX!
Web UI にドラッグ&ドロップするとファイルをアップロードできる。
SDK
下記の言語に対応している。
- Java
- .NET
- Python
- Node.js
- iOS
- Android
それぞれの言語に GitHub リポジトリがあり、Java SDK は下記の通り。
Box DEV
Box サービスサイトとは別に Box DEV という開発者向けサイトがある。
開発者コンソール
Box DEV の開発者コンソールに移動ボタンを押すと開発者コンソールページへ移動する。
ページ上部の「開発者コンソールのすべての機能にアクセスするには、Box Developerアカウントにログインまたはサインアップしてください。」というメッセージが気になるが一旦放置しておく。
アプリ作成
開発者コンソールのアプリの新規作成ボタンを押すとアプリの新規作成ページが表示される。
アプリの種類は下記の 3 つ。
- カスタムアプリ
- アクセス制限付きアプリ
- Box Custom Skill
それぞれの詳しい説明は下記ページが参考になりそう。
認証については下記ページが参考になりそう。
カスタムアプリの認証方法
- サーバー認証(JWT使用)
- ユーザー認証(OAuth 2.0)
- サーバー認証(クライアント認証情報許可)
OAuth 2.0 がスタンダードな方法だと思っていたけど 1 番目に JWT があることを見るとこちらの方がスタンダードなのだろうか?
認証方法の選択
ページの最後の方にある比較表がとてもわかりやすい。
質問 | OAuth 2.0 | JWT | クライアント資格情報 | アプリトークン |
---|---|---|---|---|
ユーザーの関与が必要? | はい | いいえ | いいえ | いいえ |
管理者の承認が必要? | いいえ | はい | はい | はい |
他のユーザーの代理で操作可能? | はい | はい | はい | いいえ |
ユーザーにBoxを表示? | はい | いいえ | いいえ | いいえ |
App Userを作成可能? | いいえ | はい | はい | いいえ |
カスタムアプリで使用する場合は下記 3 つの認証方法を利用できる。
- OAuth 2.0
- JWT
- クライアント資格情報
一般ユーザー向けのアプリの場合は OAuth 2.0 だが何らかのシステムで Box 連携機能を作る場合には JWT かクライアント資格情報を使うことになりそう。
Box ドキュメントは日本語が秀逸
今のところ全てのページを日本語で読めてしかも日本語訳も違和感がない、めちゃ助かる。
今日はここまで
時間が来てしまった。
次回はサーバー認証の設定を行いたい。
何となくだがクライアント資格情報が一番簡単そうなのでクライアント資格情報から試してみようと思う。
カスタムアプリ作成
サーバー認証(クライアント資格情報許可)でカスタムアプリを作成する。
アプリ名は My First App とした。
クライアント資格情報許可に関するドキュメント
前提条件
ドキュメントによると下記 3 つが必要になる。
- カスタムアプリ(作成済み)
- クライアントシークレットの取得
- Box 管理コンソールからアプリケーションを承認
クライアントシークレットの取得
カスタムアプリのページの構成タブを選ぶ。
OAuth 2.0 資格情報のセクションにあるクライアントシークレットを取得ボタンを押す。
下記のアラートメッセージが表示される。
この操作を実行するには、2要素認証を有効にする必要があります。[Settings ボタン]
2 要素認証を有効にする必要がありそうなので [Settings ボタン] を押す。
2 要素認証の設定
2 段階認証セクションにある設定ボタンを押す。
認証方法には認証アプリ、SMS、メールを使える、今回は認証アプリを使用する。
QR コードが表示されたらスマホの認証システムアプリなどで読み取って 6 桁のコードを入力する。
デバイスを紛失した時のためにアカウントのバックアップコードが表示されるので控えておく。
クライアントシークレット取得の再挑戦
開発者コンソールに戻ってクライアントシークレットの取得ボタンを押すと 2 段階認証ページが表示される。
正しい認証コードを入力すると元のページに戻るのでクライアントシークレットの取得ボタンを再度押すとクライアントシークレットが表示される。
コピーボタンを押してクリップボードにコピーする。
残りは承認
これでクライアントシークレットを取得できたので 3 つの前提条件のうち 2 つが満たされた。
残りは承認だけ、関連ドキュメントは下記の通り。
承認と翻訳されると少し戸惑うが英語では authorization なので認可と思えばなんとなく理解できる気がする。
今はまだ十分に理解できていないが、承認のしくみを使って作成したカスタムアプリにユーザー(例えば僕)の Box ファイルにアクセスする権限などを与えるということなのかな?
承認する方法がわからない
ドキュメントを読むと管理コンソールにアクセスすることが書いてあるがどこにあるのかがわからない。
無料のアカウントだと管理コンソールは使えないのかな?
サービスアカウントなどについてももう少し理解する必要がありそう。
もしかして個人アカウントの場合は承認する必要がない?
個人アカウントの場合は特に承認とかしなくてもデフォルトでカスタムアプリが自分のアカウントの情報を読み書きできる?
とりあえずやるだけやってみよう。
できなかったとしてもエラーメッセージとかで何かがわかるかもしれない。
まずは Node.js で試す
あまり使っていない Java から始めるとハマりそうなので勝手知ったる Node.js から始めてみる。
まずはワークスペースを作成する。
mkdir hello-box-api
cd hello-box-api
npm init -y
npm install --save dotenv box-node-sdk
npm install --save-dev ts-node @types/node
touch getting-started.ts .env
コーディング
import BoxSDKNode from "box-node-sdk";
async function main() {
const sdk = new BoxSDKNode({
clientID: process.env.BOX_CLIENT_ID!,
clientSecret: process.env.BOX_CLIENT_SECRET!,
});
const client = sdk.getBasicClient(process.env.BOX_DEVELOPER_TOKEN!);
const user = await client.users.get(client.CURRENT_USER_ID);
console.log(JSON.stringify(user, null, 2));
}
main().catch((err) => console.error(err));
環境変数
BOX_CLIENT_ID="xxxx"
BOX_CLIENT_SECRET="yyyy"
BOX_DEVELOPER_TOKEN="zzzz"
client ID と client secret は既に取得できたが開発者トークンは初めてだ。
開発者トークンを生成ボタンを押すと表示される。
開発トークンとは何だろうという感じだけどしっかり説明が記載されている。
開発者トークンを使用して、ユーザーとしてアクセスをテストするかスクリプトを作成します。開発者トークンを使用すると、Box APIを使用して個人用のBoxアカウントにのみアクセスできます。このトークンは60分間有効です。Enterprise全体にアクセスするには、Enterpriseへのアクセス権限をリクエストし、承認を受けるためにアプリを送信します。
OAuth 2.0 や JWT の場合
クライアント資格情報許可の場合は client ID と client secret が発行されるけど他の場合はどうなんだろう。
気になるので作成してみた所、OAuth 2.0 や JWT のいずれの場合も client ID と client secret が発行されていた。
どうやら client ID とclient secret はクライアント資格情報許可に固有のものではないようだ。
動作確認
npx ts-node -r dotenv/config getting-started.ts
{
"type": "user",
"id": "12345678901",
"name": "薄田達哉",
"login": "susukida@example.com",
"created_at": "2023-04-13T22:14:29-07:00",
"modified_at": "2023-04-16T17:20:45-07:00",
"language": "ja",
"timezone": "Asia/Tokyo",
"space_amount": 10737418240,
"space_used": 10,
"max_upload_size": 262144000,
"status": "active",
"job_title": "",
"phone": "",
"address": "",
"avatar_url": "https://app.box.com/api/avatar/large/12345678901",
"notification_email": []
}
せっかくなのでファイルを表示してみる
touch get-items.ts
import BoxSDKNode from "box-node-sdk";
async function main() {
const sdk = new BoxSDKNode({
clientID: process.env.BOX_CLIENT_ID!,
clientSecret: process.env.BOX_CLIENT_SECRET!,
});
const client = sdk.getBasicClient(process.env.BOX_DEVELOPER_TOKEN!);
const folderID = "0"; // ルートフォルダは常に ID 0 で表されます。
const getItemsResult = await client.folders.getItems(folderID);
console.log(JSON.stringify(getItemsResult, null, 2));
}
main().catch((err) => console.error(err));
npx ts-node dotenv/config get-items.ts
{
"total_count": 1,
"entries": [
{
"type": "file",
"id": "1190396933725",
"file_version": {
"type": "file_version",
"id": "1297794363325",
"sha1": "c47b8e953b00f2ff97e28ce6b7c9b693d8f20fe4"
},
"sequence_id": "0",
"etag": "0",
"sha1": "c47b8e953b00f2ff97e28ce6b7c9b693d8f20fe4",
"name": "hello-box.txt"
}
],
"offset": 0,
"limit": 100,
"order": [
{
"by": "type",
"direction": "ASC"
},
{
"by": "name",
"direction": "ASC"
}
]
}
せっかくなのでファイル内容を表示してみる
touch get-content.ts
import BoxSDKNode from "box-node-sdk";
async function main() {
const sdk = new BoxSDKNode({
clientID: process.env.BOX_CLIENT_ID!,
clientSecret: process.env.BOX_CLIENT_SECRET!,
});
const client = sdk.getBasicClient(process.env.BOX_DEVELOPER_TOKEN!);
const folderID = "0"; // ルートフォルダは常に ID 0 で表されます。
const { entries } = await client.folders.getItems(folderID);
for (const entry of entries) {
const readStream = await client.files.getReadStream(entry.id);
const buffer = await new Promise<Buffer>((resolve, reject) => {
const chunks: Buffer[] = [];
readStream.on("data", (chunk: Buffer) => chunks.push(chunk));
readStream.on("end", () => resolve(Buffer.concat(chunks)));
readStream.on("error", (err: Error) => reject(err));
});
console.log(buffer.toString());
}
}
main().catch((err) => console.error(err));
npx ts-node dotenv/config get-content.ts
HELLO BOX!
一発で動いたみたいな感じになっているけど実際にはちょっと試行錯誤した。
まずカスタムアプリのアプリケーションスコープセクションで Box に格納されているすべてのファイルとフォルダへの書き込みにチェックを入れる。
書き込まないのに何故だろうという感じだが仕方がない。
チェックを入れたら変更を保存ボタンを押す。
変更を反映するために開発者トークンを取り消して再び開発者トークンを生成ボタンを押す。
新しい開発者トークンで .env を書き換える。
以上で動くようになった。
やはりファイル内容が表示されると嬉しい。
時間が来てしまったので今日はここまで
次回は Java で同じことを試してみる。
今日こそ Box API Java SDK を使う
だいぶ前置きが長くなってしまったが今日こそ本題の Box API Java SDK を使うことを目標にする。
具体的には下記の 3 点について検証したい。
- 認証(ユーザー認証|OAuth 2.0)
- フォルダ作成
- 分割アップロード
IntelliJ IDEA プロジェクト作成
IntelliJ IDEA を起動する
New Project ボタンを押す。
Build system については悩ましいが Gradle にした、IntelliJ ってなんだ?
Create ボタンを押す。
無事にプロジェクトが作成された。
とりあえずコミット
IntelliJ IDEA では Command + K で Git コミットできる。
Commit ボタンを押すか Command + Enter でコミットされる。
実行
Main クラスや main() 関数の左にある ▶︎ ボタンを押すとプログラムを実行できる。
Box API Java SDK インストール
上記のページによると build.gradle に下記の依存関係を追加する。
dependencies {
compile 'com.box:box-java-sdk:4.0.1'
}
ドキュメントではバージョンは 2.32.0 だが上記の通り現時点の最新バージョンである 4.0.1 を指定した。
build.gradle では compile は非推奨
compile の代わりに implementation を使う。
build.gradle 変更反映
メニュー > View > Tool Windows > Gradle で Gradle ウィンドウを表示してから左上の更新ボタンを押す。
なるほど IntelliJ IDEA ではこうやると build.gradle の変更が反映されるのか。
コード補完が効くようになった
BoxAPIConnection と入力したら自動的に import してくれた、ありがたや。
環境変数の設定
メニュー > Run > Edit Configurations... を選ぶと Run / Debug 構成を編集できる。
環境変数(Environment variables)の入力部にセミコロン区切りで環境変数を KEY=value
形式で入力する。
String accessToken = System.getenv("BOX_ACCESS_TOKEN");
System.out.println(accessToken);
xxxx
▶︎ ボタンを押す代わりに Ctrl + R でも main() 関数を実行できる。
環境変数の設定は .idea/workspace.xml に保存され、このファイルは .idea/.gitignore でバージョン管理対象から外されているので安心して Git にコミットできる。
コーディング
package org.example;
import com.box.sdk.BoxAPIConnection;
import com.box.sdk.BoxFolder;
import com.box.sdk.BoxItem;
public class Main {
public static void main(String[] args) {
String accessToken = System.getenv("BOX_ACCESS_TOKEN");
BoxAPIConnection api = new BoxAPIConnection(accessToken);
BoxFolder rootFolder = BoxFolder.getRootFolder(api);
for (BoxItem.Info itemInfo : rootFolder) {
System.out.format("[%s] %s\n", itemInfo.getID(), itemInfo.getName());
}
}
}
実行結果
[1190396933725] hello-box.txt
無事にルートフォルダのファイル一覧に成功した。
フォルダー作成
フォルダー作成には親フォルダーの createFolder() メソッドを呼び出す。
package org.example;
import com.box.sdk.BoxAPIConnection;
import com.box.sdk.BoxFolder;
import com.box.sdk.BoxItem;
public class Main {
public static void main(String[] args) {
// mainGettingStarted();
mainCreateFolder();
}
public static void mainCreateFolder() {
String accessToken = System.getenv("BOX_ACCESS_TOKEN");
BoxAPIConnection api = new BoxAPIConnection(accessToken);
BoxFolder rootFolder = BoxFolder.getRootFolder(api);
String createdFolderName = "New folder created by Java SDK";
rootFolder.createFolder(createdFolderName);
}
}
前のコードを残しておきたいので mainCreateFolder() メソッドを作成した。
開発者トークンが時間切れになっていたので再発行して環境変数を設定し直した。
Ctrl + R で実行したところ正常に終了した。
Box Web UI を開いた所、フォルダーが作成されていることを確認できた。
フォルダーの重複作成
同じ名前のフォルダーを作成しようとしたらどうなるだろう?
実際にやってみたところ例外が発生した。
例外の内容を表示するために main() メソッドに変更を加える。
public static void main(String[] args) {
try {
mainCreateFolder();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
The API returned an error code [409 | tps6gihd3svaellc.16a397f56c28e189a422b2e323039d6af] item_name_in_use - Item with the same name already exists
エラーメッセージがとてもわかりやすい。
ちなみにステータスコード 409 は Conflict(競合)。
同じ名前のファイルがあった場合はどうなる?
興味深かったのでやってみた。
String createdFolderName = "hello-box.txt";
rootFolder.createFolder(createdFolderName);
The API returned an error code [409 | 4ayapohd3t1208xf.0f052da01dd64183ec7a60835d5fa2953] item_name_in_use - Item with the same name already exists
結果は同じ名前のフォルダーがあった場合と同じだった。
フォルダー作成の改良版
package org.example;
import com.box.sdk.BoxAPIConnection;
import com.box.sdk.BoxFolder;
import com.box.sdk.BoxItem;
public class Main {
public static void main(String[] args) {
try {
// mainGettingStarted();
// mainCreateFolder();
mainCreateFolderIfNotExists();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
public static void mainCreateFolderIfNotExists() {
String accessToken = System.getenv("BOX_ACCESS_TOKEN");
BoxAPIConnection api = new BoxAPIConnection(accessToken);
BoxFolder rootFolder = BoxFolder.getRootFolder(api);
String createdFolderName = "New folder created by Java SDK";
boolean found = false;
for (BoxItem.Info itemInfo : rootFolder) {
if (itemInfo.getName().equals(createdFolderName)) {
found = true;
break;
}
}
if (!found) {
rootFolder.createFolder(createdFolderName);
System.out.println("Created");
} else {
System.out.println("Not created");
}
}
}
Not created
mkdirp が欲しい
mkdir -p a/b/c
と等価な機能はあるのかな?
なくても再帰を使えば作れそう。
ファイルアップロード
API リファレンスに書かれている通りファイルのアップロードには分割の有無で 2 パターンある。
分割アップロードをするには uploadLargeFile() メソッドを使えば良いのかな?
Main クラスのソースコードをアップロードしてみる。
package org.example;
import com.box.sdk.BoxAPIConnection;
import com.box.sdk.BoxFolder;
import com.box.sdk.BoxItem;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
public class Main {
public static void main(String[] args) {
try {
// mainGettingStarted();
// mainCreateFolder();
// mainCreateFolderIfNotExists();
mainUploadFile();
} catch (Exception e) {
System.err.println(e.getMessage());
}
}
public static void mainUploadFile() throws IOException, InterruptedException {
String accessToken = System.getenv("BOX_ACCESS_TOKEN");
BoxAPIConnection api = new BoxAPIConnection(accessToken);
BoxFolder rootFolder = BoxFolder.getRootFolder(api);
String uploadedFilePath = "src/main/java/org/example/Main.java";
File uploadedFile = new File(uploadedFilePath);
FileInputStream inputStream = new FileInputStream(uploadedFile);
String createdFileName = "New file created by Java SDK";
long fileSize = uploadedFile.length();
rootFolder.uploadLargeFile(inputStream, createdFileName, fileSize);
System.out.println("Succeed to upload");
}
}
実行した所なんと下記のエラーが発生した。
The API returned an error code [400 | a28964f1bbf9aa98d7e2991334c71517] file_size_too_small - File size 2737 less than minimum allowed for this API: 20000000
どうやら 2MB 以上でないとこの uploadLargeFile() メソッドは利用できないようだ。
ファイルアップロードの改良版
下記のような条件分岐を追加した。
if (fileSize >= 2000000) {
rootFolder.uploadLargeFile(inputStream, createdFileName, fileSize);
} else {
rootFolder.uploadFile(inputStream, createdFileName);
}
Succeed to upload
Box Web UI を確認するとファイルが作成されていることがわかる。
今日はここまで
次回はユーザー認証(OAuth 2.0)か mkdirp 実装を行いたい。
今日わかったこと
- フォルダ作成は同じ名前のフォルダやファイルがあると失敗する。
- アップロードについては 2MB 以下だと分割アップロードができないことがわかり、ファイルサイズに応じて分割/非分割アップロードを使い分ける必要がある。
今日はここから
今日はユーザー認証(OAuth2.0)について調べる。
余力があればサーバー認証(JWT)やカスタムアプリ以外のアプリについても調べたい。
認証についての説明が GitHub の方が詳細
しかもわかりやすい。
認証方法には下記の 5 つがある。
- 開発者トークン
- サーバー認証(JWT)
- OAuth 2.0
- アプリトークン
- クライアント資格情報
開発者トークンは client ID や client secret なしで単体でアクセスできるようだ。
また Client Credentials Grant(クライアント資格情報)に興味深い記述がある。
Obtaining User token
To obtain user account you will have to provide user ID with client id and secret
BoxCCGAPIConnection api = BoxCCGAPIConnection.userConnection( "client_id", "client_secret", "user_id" );
In order to enable generating user token you have to go to your application configuration that can be found here. In Configuration tab, in section Advanced Features select Generate user access tokens. Do not forget to re-authorize application if it was already authorized.
ユーザートークン(ユーザーアクセストークン)を使うことで Box 個人アカウントの場合でもアクセスできるようになるのかな?
個人アカウントの場合はユーザー ID ではなくアカウント ID なので何となく違う気もする。
それともサーバー認証を使用するカスタムアプリは Enterprise 版でしか使えないのかな?
何となくだがそんな感じがする。
OAuth 2.0 を試す
サーバー認証(JWT / クライアント資格情報)を使う認証についてはエンタープライズ版じゃないと検証ができない可能性が高いことがわかったので、まずは OAuth 2.0 の方を試してみようと思う。
カスタムアプリの作成
ウェブアプリ統合が興味深い
サードパーティーアプリから Box にアクセスするだけではなく、Box の Web UI にサードパーティーアプリに関するアクションを組み込めるようだ。
これは素晴らしい。
OAuth 2.0 リダイレクト URI 設定
カスタムアプリページの構成タブから変更できる。
とりあえず http://localhost:3000 などにしておこう。
変更を保存ボタンを忘れずに押す。
公式ドキュメントがあった
承認 URL へのリダイレクト
Web サーバーを使用している場合はサーバーサイドまたはクライアントサイドで承認 URL へリダイレクトする。
response.redirect(authorizationUrl)
window.location.assign(authorizationUrl)
Box API Java SDK には承認 URL を生成するメソッドが無いので手動で作る必要がある。
String authorizationUrl = "https://account.box.com/api/oauth2/authorize?client_id=[CLIENT_ID]&response_type=code";
プログラムを書いても良いが動作を確認するだけなら手動で [CLIENT_ID] の部分を書き換えるだけで大丈夫そう。
[CLIENT_ID] の部分を書き換えた URL にアクセスする。
例えば xxxx に書き換えた場合は https://account.box.com/api/oauth2/authorize?client_id=xxxx&response_type=code などにアクセスする。
承認ページ
スコープやコールバック URL を設定しなくてもよろしくやってくれるようだ。
承認コードの取得
Box へのアクセスを許可ボタンを押すと http://localhost:3000 にリダイレクトされる。
http://localhost:3000 では Web サーバーを立ち上げていないので当然ながらエラーページが表示される。
ブラウザのアドレスバーに ?code=xxxx
のように承認コードが付加されているのでこれを控えておく。
承認コードの有効期間は数秒
このコードはアクセストークンではなく、有効期間はほんの数秒です。SDKを使用すると、このコードを実際のアクセストークンと交換できます。
手動でコピー&ペーストしてアクセストークンと交換しようと思っていたので残念だが、有効期間があまり長くてもリスクが高そうなので仕方ない。
Java で Web サーバーを作る勉強をする必要がありそうだ。
別のスクラップを作った
Java で Web サーバーを作るのに Spring Boot を使おうと思う。
Web サーバーを作る手順についてはこのスクラップにまとめてもよいが趣旨からズレる感じがしたので別のスクラップを作成した。
上記のスクラップをクローズしたら戻って来ようと思う。
戻ってきた
Spring Boot クイックスタートがとても素晴らしかったので 1 時間もかからずに終わってしまった。
別のスクラップを作る必要がなかったかも知れない。
Spring Boot プロジェクトに Box API Java SDK 追加
build.gradle に依存関係を追加する。
dependencies {
implementation 'com.box:box-java-sdk:4.0.1'
}
Gradle ツールウィンドウの左上の更新 🔃 ボタンを押して変更を反映する。
OAuth 2.0 リダイレクト URI 変更
Spring Boot に合わせて http://localhost:8080/oauth2callback に変更する。
うっかり https:
にしないように注意する。
コーディング
package com.example.demo;
import com.box.sdk.BoxAPIConnection;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
@SpringBootApplication
@RestController
public class DemoApplication {
public static void main(String[] args) {
SpringApplication.run(DemoApplication.class, args);
}
@GetMapping("/oauth2")
public String OAuth2redirect() {
String clientID = System.getenv("BOX_CLIENT_ID");
String authorizationUrl = "https://account.box.com/api/oauth2/authorize?client_id=" + clientID + "&response_type=code";
return "<a href=\"" + authorizationUrl + "\">" + authorizationUrl + "</a>";
}
@GetMapping("/oauth2callback")
public String OAuth2Callback(@RequestParam(value = "code", defaultValue = "") String authorizationCode) {
String clientId = System.getenv("BOX_CLIENT_ID");
String clientSecret = System.getenv("BOX_CLIENT_SECRET");
BoxAPIConnection client = new BoxAPIConnection(clientId, clientSecret, authorizationCode);
return String.format("Access token: %s!", client.getAccessToken());
}
}
動作確認
http://localhost:8080/oauth2 にアクセスすると下記のようなリンクが表示される。
https://account.box.com/api/oauth2/authorize?client_id=xxxx&response_type=code
リンクをクリックすると承認ページが表示されるので承認すると http://localhost:8080/oauth2/oauth2callback にリダイレクトされる。
リダイレクト先では下記のようにアクセストークンが表示される。
Access token: xxxx
アクセストークン動作確認
せっかくなのでルートフォルダーを一覧してみる。
@GetMapping("/list")
public String list(@RequestParam(value = "accessToken", defaultValue = "") String accessToken) {
BoxAPIConnection client = new BoxAPIConnection(accessToken);
BoxFolder rootFolder = BoxFolder.getRootFolder(client);
StringBuilder response = new StringBuilder();
response.append("<ul>");
for (BoxItem.Info itemInfo : rootFolder) {
response.append(String.format("<li>%s</li>", itemInfo.getName()));
}
response.append("</ul>");
return response.toString();
}
http://localhost:8080/list?accessToken=xxxx にアクセスする。
xxxx の部分をアクセストークンで置き換える。
成功すると下記のようなリストが表示される。
- New folder created by Java SDK
- hello-box.txt
- New file created by Java SDK
今日わかったこと
- サーバー認証(JWT or クライアント資格情報)はエンタープライズ版じゃないと検証できなさそう
- ユーザー認証(OAuth 2.0)のやり方
- 承認コードの有効期間は数秒程度と短いので動作確認には Web サーバーを作る必要がある
まだまだ調べたいことはあるけど
明日くらいに一旦クローズしようと思う。
おわりに
正直に言うとスクラップを書き始める時は Box 自体知らなかったけどドキュメントや API や SDK がわかりやすかったのはとても良かった。
エンタープライズ向け Dropbox みたいな位置付けなのかな?
クラウドストレージサービスは様々な場面で使えそうなので今回 API を使う方法について学べて良かった。
Box Sign など他にも色々な機能があるようで機会を作って試してみたい。
SDK については Node.js よりも Java の方がソースコード的にもドキュメント的にも完成度が高かったように感じた。
心残りはサーバー認証がエンタープライズ版じゃないと試せなさそうなので、仕事や覚悟が決まってエンタープライズ版を契約することがあったら試してみたい。
一旦クローズするけどまた何かしらを調べる必要が生じたらこのスクラップに追記するか新しいスクラップを作成してリンクを投稿しようと思う。
関連スクラップ
続編的なスクラップを作成しました。
続編
無料試用期間を活用してサーバー認証を試してみる。
まずは Business プランのアカウントを作成する。
さらに続編
実際にサーバー認証を試してみる。
さらにさらに続編
JWT によるサーバー認証を試してみる。
まとめ
- Box でアプリを登録するには開発者コンソールを使う必要がある。
- 開発者コンソールには Box DEV というサイトからログインできる。
- カスタムアプリの認証方法にはサーバー認証とユーザー認証の大きく 2 つがある。
- サーバー認証はさらに JWT 使用とクライアント資格情報許可の 2 つに分けられる。
- サーバー認証は B2B 向けで管理者が設定作業を行うケースに適している。
- ユーザー認証は B2C 向けでユーザーが自ら設定作業を行うケースに適している。
- サーバー認証でクライアントシークレットを取得するには 2 段階認証の設定が必要となる。
- 無料の Individual アカウントではサーバー認証のカスタムアプリを作成しても承認できない。
- 承認するには管理コンソールが必要で、管理コンソールには有料プラン契約が必要となる。
- クライアント ID とシークレットはどの認証方法を使う場合でも発行される。
- Box API Node.js SDK の TypeScript サポートはあまり良くない。
- ファイルをダウンロードするには書き込み権限が必要となる。
- IntelliJ IDEA で Box API Java SDK を使うには build.gradle に依存関係の追加が必要となる。
- build.gradle では compile は非推奨なので代わりに implementation を使う。
- IntelliJ IDEA で build.gradle の変更を反映するに Gradle ツールウィンドウの更新ボタンを押す。
- 環境変数を設定するには Run / Debug 構成を編集する。
- 環境変数は Git リポジトリにはコミットされない。
- フォルダー一覧、フォルダー作成に成功した。
- 同じ名称のファイルやフォルダーがあるとフォルダーを作成できない。
- ファイルアップロードには分割と非分割の 2 種類がある。
- 分割は 2 MB 以上でないと利用できない。
- Web アプリ統合を使うと Box Web UI にさードパーティーアプリに関するアクションを組み込める。
- Box では認可(authorization)を承認と呼ぶ。
- Box API Java SDK には承認 URL を作成するメソッドは無いので手動で作成する必要がある。
- 承認コードの有効期間は数秒程度と短いので承認コードとアクセストークンの交換は自動で行う必要がある。
- 交換を自動で行うには Spring Boot で Web アプリを作ると良い。