こんにちは!
今回はひとつ要望がありまして投稿しております。先日の投稿にも書きましたが、私は今、自作プラグインと自作APIプラグインとを作り、「自作プラグイン」 → 「自作APIプラグイン」 → 「外部サービスのコール」という流れをテストしているところです。
ひとつ気づいたのですが、APIコールするときに、無認可の者に直接APIを叩かれないように、secret code(秘密コード)をURLに含められる形になっていますよね。
- 「秘密コード」とは「管理者メニュー」→「API管理」で設定するもののことです。
- ApiPluginBase.php の apiCallCheck()メソッドのコードを確認しました。
懸念点
APIプラグインを同一ホスト内の別のプラグインからコールするのであれば、URL(秘密コード含む)がインターネットにさらされることはありませんが、次の点が懸念材料です。
(1) webサーバのアクセスログに秘密コードが保存されうる点。アクセスログは誰が見ることができ、どのように管理されるのか、状況によっては心配の元となるため。
(2) Connect-CMSサイトの外部からAPIコールする用途では、URL(秘密コード)がインターネットにさらされる点。
要望
自作の通常プラグイン(あるいは外部サイトから)、HTTPヘッダーに「Authorization: Bearer 」を含める形で、APIをコールできるようにして欲しいです。言い換えると、apiCallCheck() に Authorization ヘッダーのチェック機能を実装して欲しいです。
コード例は以下のとおりです。これであれば、現状の GET で URLパラメータに秘密コードを含む方法とも互換性があります。
public function apiCallCheck($request, $plugin_name)
{
// まず `Authorization` ヘッダーを確認
$auth_header = $request->header('Authorization');
if (!empty($auth_header) && preg_match('/Bearer\s+(.+)/', $auth_header, $matches)) {
$secret_code = $matches[1];
}
// `Authorization` ヘッダーがない場合は `GET` パラメータを確認
elseif ($request->filled('secret_code')) {
$secret_code = $request->secret_code;
} // どちらもない場合はエラー
else {
return array('code' => 403, 'message' => '秘密コードが必要です。');
}
// 以降は今の `apiCallCheck()` と同じ処理
/* 後略 */
}
apiCallCheck()メソッドが上記のようになっていれば、自作プラグインなどから、例えば、以下のようなコードで安全にAPIをコールできます。(下のコードでは、環境変数に秘密コードを保存しておく形としていますが、もっとよい方法もあるでしょう。)
// Secret code を Authorization ヘッダーで渡す
$response = Http::withHeaders([
'Authorization' => 'Bearer ' . env('SECRET_CODE')
])->get($url);
以上、ご検討いただけますでしょうか。よろしくお願いいたします。
永原さま
HTTP ヘッダーの Authorization 行を使った認証に興味を持っていただきありがとうございました。
「懸念点」に書きました内容のうち、(2)は私の無理解でした。こちらは暗号化されるので安全なようです。ただ、他にも URL に secret が含まれていると、利用者がそのURLをコピペして、よくないところに送ったりするリスクもあるかと思います。
> トークンを.envに書いて認可するような形
はい、私も .env に書くのは想定しておりません(コードを簡潔に提示するために .env をむ使いました)。.env に書くと、Connect-CMSサイトから特定のAPIにしかアクセスできなくなり、柔軟性に欠ける面もありますね。
私が考えている方法としては、「管理者メニュー」→「API管理」で設定した「秘密コード」を、各プラグインのフレームの設定画面で、例えば「API設定」などというタブ画面を設けて、(そこに「秘密コード」を直に書くのもアレなので)「利用名」の方を書いておいて、「API管理」でセットした「秘密コード」を取得するようにするといいのかなと考えています。以下はそのイメージ図です。


akaz様
永原です。
2点、気になる点を返信しますね。
1.トークンの生成と形式
永原が参考に見させていただいたサイトの中で、「様々な認証方式について」の中で触れられていたことに、以下がありました。
あと、他のサイトもですが、トークンはサーバ側で生成するように書かれています。
と、ここで、Laravel にBearer 機能は用意されていないのかな?と思って探してみました。
すると、以下がありました。
以下のページの「APIトークン認証」の部分。
https://readouble.com/laravel/10.x/ja/sanctum.html
これを使えそうです。
2.クライアント側はトークンの保持機構が必要かな。
実際に実装する際は、上記のLaravel の翻訳マニュアルやRFCを確認しますが、いま、参考にしたページではクライアント側でトークンを保持する機構も必要そうです。
トークンをサーバ側で生成する以上、クライアント側ではセッションなのかデータベースなのか、何らかの保持する機構は必要ですものね。
永原がもっとわかっていれば、最初からBearer 方式で実装できたかもしれないのですが、そこはご容赦を。(^-^)
以上、情報共有でした。
永原さま
> 1.トークンの生成と形式
(中略)
> あと、他のサイトもですが、トークンはサーバ側で生成するように書かれています。
そうですね。サーバ側(APIのサービスを提供する側)が用意しますね。
今回、私が作成しているものの流れは次のようなものです。
(1) kintone(サーバ側)のSampleアプリに以下のようなデータを保存してあります。

(2) kintoneのSampleアプリの設定画面で、Connect-CMS(クライアント側)のためにAPIトークンを発行します。

(3) Connect-CMS に作ったプラグインで、(2)のAPIトークンを使って(Connect-CMSのどこかに保存しておいて)、kintoneのSampleアプリにアクセスしてその中のデータ(小麦とかトマト)を取得する。

> と、ここで、Laravel にBearer 機能は用意されていないのかな?と思って探してみました。
> すると、以下がありました。
> 以下のページの「APIトークン認証」の部分。
> https://readouble.com/laravel/10.x/ja/sanctum.html
これは、Connect-CMSがサーバとして振る舞うときの話ですよね。
いずれにしても、Connect-CMSのプラグインには、サーバ(上の例ではkintone)側のAPIトークンを保存しておき、kintoneにアクセスすることになりますね。
akaz様
おはようございます。
永原です。
なるほど、Connect-CMSはクライアント側なのですね。(失礼。勘違いしていたかも)
apiCallCheck関数はサーバ側の関数かな。
ちょっと混乱してきました。(笑)
すみません、ちょっと混乱してきたのもあるので、実装を検討する際に、再度ゆっくり見たいと思います。
以上、失礼いたします。