はじめに
2023年6月7日に、カラーミーショップでショップの副管理者が一部のアプリストア アプリを利用できる機能の提供を開始しました。
カラーミーショップの提供する価値の1つに、さまざまな規模のショップの運営業務を効率化するというものがあります。今回提供を開始した機能は、複数人が携わるような中規模から大規模のショップの運営において、この価値の増大に貢献するものです。また、総合的なECプラットフォームとしてショップ自体の管理から拡張機能の利用までを一貫性のある体験として提供できる、という効果もあります。
副管理者がアプリストア アプリを利用できるようにするためには、次のような技術的取り組みが必要でした。
- ショップ副管理者の権限情報をサービスのどの場所からでも利用できるようにする
- アプリストア アプリが権限を意識し、適切なアクセス権限を持った副管理者だけが使えるようにする
この記事では、サービスにこれらの変更を導入するうえで考慮したことについて解説します。
これまでの権限管理とその課題
一般的なSaaSでは、テナントに所属するユーザーがサービスを利用するとき、管理者が一般のユーザーに対して権限を付与することで、ユーザーがどの情報にアクセスできるかを制御することが多いでしょう。これはカラーミーショップでも同じで、テナントの管理者をショップオーナー、一般のユーザーを副管理者と見なして、ショップオーナーが副管理者に権限を付与するというモデルをとっています。
一方で、ショップオーナーによって付与できる副管理者の権限が効果を持つ範囲は限定的なものでした。具体的には、ショップオーナーは管理者ページ (admin.shop-pro.jp) で閲覧できる画面を制御する権限だけを副管理者に付与することが可能でした。
副管理者の権限は次のような形で管理者ページに表示されます。もっとも細かい粒度の権限は管理者ページの個々の画面を表しており、他のアプリケーションがそのまま利用できるものではありません。
また、権限が管理者ページと密結合であるがゆえに、そもそも副管理者は管理者ページしか利用できませんでした。副管理者が利用できない主なサービスとして、モバイルアプリに加えて、カラーミーショップ アプリストアとそこで提供するアプリストア アプリがありました。
カラーミーショップの権限管理のあるべき姿
先述した課題を踏まえて、あるべき姿について説明します。
まず、管理者ページと密結合な副管理者の権限を、サービス横断で利用できるものに改善します。そして、ショップオーナーはサービス横断で参照されうる権限を副管理者に付与できるようにします。
また、カラーミーショップのIdPを通じて認証・認可するアプリストアはOpenID ConnectのRelying Party (RP)であり、アプリストア アプリはOAuthクライアントです。これらはリソースオーナーとしてのユーザーの権限を意識した実装に変更します。ショップオーナーか、もしくは適切なアクセス権限を持った副管理者だけがRPやOAuthクライアントを使えるようにします。
この構成を簡単な図にすると次のようになります。
このあるべき姿に向けて開発するには、後述のとおりいくつか考慮することがありました。
権限管理をあるべき姿へ進化させるための考慮事項
利用者に無理のない移行を促せる機能にする
管理者ページに密結合した副管理者の権限をサービス全体で使えるものにするには、いくつかの方法が考えられます。
1つ目の案として、カラーミーショップが提供するリソース(商品、受注、配送設定など)ごとに読み取り・書き込みなど細かい粒度の権限に分けて整理しなおし、それらを新たな権限として設定できるようにする、という方法が考えられます。もし、ゼロから権限制御の仕組みを作るなら、この方法を採用する可能性が高いでしょう。
また、2つ目の案として、現在の権限の構造をもとに抽象化した権限を設けるという方法も考えられます。先ほどの管理者ページの画像のとおり、最小粒度の権限はカテゴリ(商品管理、受注管理など)に紐づいています。これらのカテゴリを1つの権限と見なすというのが、この方法です。
例をあげて説明すると、次のような「商品管理」のカテゴリを権限と見なすということです。「商品管理」に紐づく最小粒度の権限すべてを副管理者に付与すると、副管理者は「商品管理」の権限を持っていると見なすのが自然です。
1つ目の案のように新しい権限一式を用意する場合、技術的にはあるべき姿に一気に移行できるというメリットがあります。しかし、利用者がスムーズに移行しにくい可能性もあります。すでに存在する副管理者に新しい体系に基づく権限を適切に付与する手間もかかりますし、利用者に新たな権限の仕組みについての学習を強いることになります。
2つ目の案だと、あるべき姿にはもう一歩というのが正直なところです。しかし、ショップオーナーにとっては従来のインタフェースのまま、必要に応じてより抽象度の高い権限を副管理者に付与できます。また、今後それらの権限の下に読み取り・書き込みなど細かい粒度の権限を追加する余地も残しています。後述のとおり、アプリストア アプリはこの権限を利用するので、1つ目の案よりは簡単に副管理者にアプリを利用させることができます。
これらを踏まえて、今回は2つ目の案を採用しました。
サービス全体から特定のユーザーの権限を参照できるようにする
すでに、これまでの取り組みでOAuth/OIDCの機能を提供するIdPにおいて、ショップオーナーと副管理者を同一のエンティティとして扱えるような仕組みに変えてきました。
このIdPを通じて、リソースオーナーにどのような権限が付与されているかを参照できるようにします。具体的にはリソースオーナーのロール(ショップオーナー、副管理者)と権限の一覧を返すAPIエンドポイントを提供し、このエンドポイントをOAuthやOIDCで取得できるアクセストークンで呼び出せるようにします。ショップオーナーは管理者としてつねに全権限を持つものとし、副管理者は先述した抽象度の権限の一部を持つものとします。エンドポイントは次のようなJSONを返すイメージです(キー名などは仮のものです)。
{
"user": {
"id": "1234567890",
"name": "staff-1",
"role": "shop_member",
"permissions": [
"product",
"customer"
]
}
}
アプリストア アプリなどのサービス内の各アプリケーションからこのエンドポイントを呼び出すことで、リソースオーナーの持つ権限を参照して、ユーザーに見せるべき情報のフィルタなどができるようになります。その結果、クライアントとして権限を意識して適切に振る舞えるようになります。
もともと存在するOAuth/OIDCに基づく認証・認可と、サービスの権限制御に関する機能はIdPに集約します。これにより、カラーミーショップを構成するコンポーネント間の依存の方向を制御できるようになります。IdPはつねに他のコンポーネントから依存される側になります。
ユーザーが必要な権限を把握しやすくする
これまで、権限の付与に着目して考慮すべきことを説明してきました。しかし、ユーザー体験としては、ある機能を使うときにどの権限が必要なのか調べる、という操作フローになることが現実的です。よって、そのタイミングで必要な権限を把握しやすいのが理想的です。ショップオーナーが必要な権限を把握できれば、確認してあらかじめ付与できますし、副管理者が必要な権限を把握できれば、ショップオーナーに付与を依頼できます。
また、アプリ自体を使うのに必要な権限は、そのアプリがOAuthクライアントとして利用するカラーミーショップAPIによって異なります。リソースオーナーがカラーミーショップAPIを使うには次の条件を満たす必要があります。
- アクセストークンが適切なスコープを持つ
- 副管理者がリソースオーナーなら、適切な権限を持つ
本来、スコープはOAuthクライアントがアクセスできるものを表し、権限はショップに所属する人がアクセスできるものを表すので、それぞれ別の概念です。よって、API呼び出し時も上述の条件に基づいて、次のように別々に検証を実行しています。
class ProductsController < ApplicationController
# アクセストークンのスコープの検証
before_action -> { doorkeeper_authorize! :read_products }
# カラーミーショップにおける権限の検証
before_action -> { require_permissions! :product }
def index
# ...
end
end
一方で、スコープと権限を紐づけておくと、副管理者に権限がないのでアプリを通じて利用するカラーミーショップAPIが使えないという体験を防ぐことができます。たとえば、read_productsスコープと「商品管理」権限を紐づけておくことを考えます。このとき、read_productsスコープを持つアプリを認可しようとする副管理者が「商品管理」の権限を持っているかを紐づけに基づいて認可のタイミングでチェックすると、アプリを使い始めてから権限が足りないことに気づかずに済みます。
よって、今回はショップオーナーや副管理者がアプリを利用する際に、利用導線の各所で上述の方法に基づいて必要な権限を表示します。具体的には次の箇所です。
- アプリ利用前の画面
- アプリを利用しようとしたときの権限チェック
- 直接アプリをOAuthのフローで認可しようとしたときの権限チェック
アプリ利用前の画面 | アプリを利用しようとしたときの権限チェック | 直接アプリをOAuthのフローで認可しようとしたときの権限チェック |
---|---|---|
最小権限の原則を考慮する
副管理者があるアプリを使うのに必要なカラーミーショップのリソース(商品、受注など)に対する権限を持つようになったとしても、そのアプリ自体は使ってほしくない状況が考えられます。たとえば、従量課金のアプリをショップで利用可能にしていても、必要な権限を持つすべての副管理者に従量課金が発生する操作をさせたいわけではないこともあるでしょう。
このたび副管理者が利用できるようになった受注作成アプリは従量課金の料金体系をとっているので、このユースケースに合致します。また、最小権限の原則の観点からも、アプリを使わない副管理者にはアプリを利用する権限は与えない方式にするのがベターといえます。
この問題を解決するために、リソースについての権限に加えて、ショップオーナーによって明示的にアプリに対する権限が割り当てられるまで副管理者が当該アプリを使えないようにできる仕組みを導入しました。この権限はデフォルトで無効にしており、アプリをショップへの意図しない課金を防ぐようになっています。
まとめ
カラーミーショップでショップの副管理者に付与する権限をサービス横断で利用できるように、権限の構造の改善とIdPへの権限制御ロジックの集約を進めた事例を紹介しました。取り組みとして、まずは副管理者の権限を管理者ページに密結合なものからより抽象度の高いものに変更しました。また、アプリストア アプリは利用者の権限をIdPを通じて参照し、権限を意識した振る舞いができるようにしました。結果として、ショップオーナーもしくは適切なアクセス権限を持った副管理者が適切にアプリストア アプリを使える仕組みが整いました。
このようなWebサービスの基盤の開発に興味があるかたは、ぜひ応募ページからご連絡ください。
謝辞
カラーミーショップのIdPの開発にあたっては、YAuth.jpのNov Matake (nov)さんにご助言をいただいております。また、本記事もnovさんにレビューいただきました。