MongoDB Realmのパーティションへの理解を深めよう

2022年9月9日(金)
柴田 凌輔

はじめに

前回は、MongoDB Realmを使用してCRUD機能を実装し、モバイルアプリから商品情報の表示/追加/編集/削除が行えるようになりました。

今回は、一般ユーザーがモバイルアプリにサインインしたときの動作を作っていきます。前回までに作成した機能では一般ユーザーも管理者ユーザーと同じ操作ができてしまうため、一般ユーザーには制限を設けて商品情報一覧だけが表示されるようにしていきます。

パーティションを更新してアクセス権を変更

本章では、前回記事のプログラムを使用します。まずは、第3回で作成済みのパーティションを更新して、管理者ユーザーだけが商品情報の追加/更新/削除をできるようにしていきます。

  1. MongoDB Cloudの [App Services] から前回まで使っていたアプリを選択して [Device Sync] タブを開きます。
  2. 以下の画面が表示されるので、Device Syncの設定を行っていきます。

  3. [Define Permissions] の設定を以下のように変更します。
    ●Read
    {
      “%%partition” :”PUBLIC”
    }
    ●Wrirte
    {
      "%%partition": "PUBLIC",
      "%%user.custom_data.is_admin": true
    }

  4. 設定ができたら [Save Change] ボタンを押下して設定を更新します。

前回までと違うのは、Define PermissionsのWriteの項目です。Custom User Dataのis_adminがtrueのユーザーだけが、書き込み権限を持つように設定を更新しています。

この設定により、管理者ユーザーが商品情報を編集したときだけ、モバイルアプリのRealmデータベースからMongoDB Atlasへ商品情報の同期が行われるようになります。

パーティション設定の動作確認

パーティションの設定ができたので、実際にアクセス権限が機能しているか確認してみましょう。Visual Studioでモバイルアプリのプロジェクトを開き、[Ctrl]+[F5] を押下してプログラムを実行します。

モバイルアプリの起動ができたら一般ユーザーでサインインします。画面上部に「一般ユーザー」と表示されていれば正しい権限でサインインできています。

まずは、一般ユーザーの権限で追加画面から商品情報を追加してみましょう。例として、

 商品名:ローカルカレー
 定価[円]:500円
 値引き率[%]:20

を追加します。

商品情報を追加して、一覧画面に戻ると商品情報が登録できています。一般ユーザーは商品情報を追加できないパーティション設定にしたはずです。

続いて、モバイルアプリと同期しているMongoDB Atlasのコレクションを見てみましょう。データが沢山ある場合はフィルタ機能を使ってみてください。FILTERと書かれている右側に {item: 'ローカルカレー'} と入力して [Apply] ボタンを押すと検索できます。

コレクションを見ると、モバイルアプリでは追加できていたはずの「ローカルカレー」が同期されていません。

Realmアプリのログも確認してみましょう。MongoDB Cloudの [App Services] からアプリを選択して [Logs] タブを開きます。ログには PermissionDenied Errorが残っています。パーティションへの書き込み権限がないという内容です。

ここまでの動作状況をまとめると、先ほどのWrite権限の設定で「パーティション名 ‘PUBLIC’ のデータは、管理者しか書き込み(追加/更新/削除)できない」と指定したので、MongoDB Atlas側には同期されなかったという結果になりました。

次に、MongoDB Atlasから商品情報を追加してみましょう。先ほど確認したコレクションから [INSERT DOCUMENT] を開いて以下のドキュメントを入力し、[Insert] ボタンを押してコレクションに追加します。

{
"_partition":"PUBLIC",
"discount_rate":{"$numberLong":"10"},
"item":"クラウドカレー",
"price":{"$numberLong":"1000"},
"timestamp":{"$date":{"$numberLong":"1660546362942"}}
}

コレクションが追加できたら、モバイルアプリに同期されるか確認してみましょう。すると、下図のように商品情報が追加(同期)されていることがわかります。

※モバイルアプリが更新されないときは、トップ画面から別画面に移動して戻るなどしてみてください。

先ほどのRead権限の設定で「パーティション名 ‘PUBLIC’ のデータの読み込みは、誰でも可能」と指定したので、MongoDB Atlasから追加されたデータはモバイルアプリのRealmデータベースに同期されたという結果になりました。

パーティション設定のまとめ

パーティションを設定することで、一般ユーザーによる商品情報の変更がMongoDB Atlasに同期されないようになりました。ただし、ローカルの Realmデータベースに対しては一般ユーザーも商品情報を編集できてしまうため、Xamarinの機能で制限をかけていきます。

【参照】https://www.mongodb.com/docs/atlas/app-services/sync/data-access-patterns/permissions/

一般ユーザー用の画面作成

前回で作成したトップ画面では、追加ボタンと商品リストをクリックすることで商品追加画面と商品編集画面へ遷移できます。これでは一般ユーザーも商品情報を編集できてしまうため、一般ユーザーが操作しているときはCustom User Dataを使って商品追加画面と商品編集画面へ遷移できないようにしていきます。

本章で作成するサンプルコードは、こちらからダウンロードできます。

カスタムデータの取得

一般ユーザーと管理者ユーザーを区別するために、Custom User Dataを取得します。カスタムデータの取得方法は第7回で紹介したとおり、CurrentUser.RefreshCustomDataAsync関数とGetValue関数を実行し、Custom User Dataで設定したis_adminの値を取得します。

// サインインユーザーの属性値 (カスタムデータ) を取得する
App app = ((MainActivity)this.Activity).realmApp;
BsonDocument customData = await app.CurrentUser.RefreshCustomDataAsync();
BsonValue isAdmin = customData?.GetValue("is_admin", false) ?? false;
bool isAdmin = (isAdminCustomData.BsonType is BsonType.Boolean ?        
    isAdminCustomData.AsBoolean : false);

商品追加ボタンの設定

ここでは、一般ユーザーが操作をしているときに商品追加ボタンが表示されないようにします。その方法として、ButtonオブジェクトのVisibilityプロパティを使用します。VisibilityがViewStates.Visibleのときはボタンが表示され、ViewStates.Goneのときは表示されません。

そこで、TopFragment.csのOnViewCreated関数に以下のコードを追加します。また、レイアウトファイルのtop.xmlにある追加ボタンのプロパティにも android:visibility="gone" を追加します。

// 一般ユーザーのときは追加ボタンを隠す
addButtion.Visibility = isAdmin switch
{
       true => ViewStates.Visible,
       false => ViewStates.Gone
 };

商品リストをクリックしたときの設定

続いて、一般ユーザーが商品リストをクリックしたときに商品編集画面へ遷移されないように設定します。TopFragment.csのOnListItemClick関数内の処理をif文で囲み、isAdminがtrueのときだけ処理を行うようにします。

App app = ((MainActivity)this.Activity).realmApp;
            BsonDocument customData = await app.CurrentUser.RefreshCustomDataAsync();
            BsonValue isAdminCustomData = customData?.GetValue("is_admin", false) ?? false;
            bool isAdmin = (isAdminCustomData.BsonType is BsonType.Boolean ? isAdminCustomData.AsBoolean : false);
            if (isAdmin)
            {
                 using Realm publicRealm = Realm.GetInstance(

                  ︙

                 Utils.ChangeFragment(this.ParentFragmentManager, ef);

動作確認

動作確認には、第7回で作成した管理者ユーザーのadmin@sample.localを使用します。

Visual Studioで今回作成したプロジェクトファイルを開き、[Ctrl]+[F5] を押下してアプリを動かしてみます。例として、管理者ユーザーのadmin@sampleapp.localと、一般ユーザーの user@sampleapp.local にそれぞれサインインします。

管理者ユーザーでサインインしてみると、前回と同様に追加ボタンが表示され、追加ボタンと商品リストをクリックすることで商品情報を編集できます。

続いて、一般ユーザーでサインインすると追加ボタンが表示されず、商品リストをクリックしても編集画面に遷移しません。そのため、商品表示だけを行えるアプリになっていることがわかります。

おわりに

今回は、 MongoDB Realmの機能であるDevice SyncとCustom User Dataを使用して、ユーザーのロールに応じてデータベースの書き込み権限を変更しました。パーティションによる権限管理は機能がたくさんあるので、工夫次第でさまざまな実装ができると思います。

次回は、最終回となります。本連載の開始(2021年11月)以降からMongoDB Realmの機能やインターフェースも刷新され、SDKの仕様も変わってきているので、モバイルアプリを2022年9月現在の新仕様で再実装したいと思います。お楽しみに!

クリエーションライン株式会社 Exploratory Development & Incubation Team
22年度卒の新卒エンジニア。大学時代の先輩に憧れ、アジャイルの精神を持ったクラウドネイティブエンジニアになるために日々勉強中。趣味は珈琲を淹れること。不定期に会社内の懇親会で披露することも。

連載バックナンバー

Think ITメルマガ会員登録受付中

Think ITでは、技術情報が詰まったメールマガジン「Think IT Weekly」の配信サービスを提供しています。メルマガ会員登録を済ませれば、メルマガだけでなく、さまざまな限定特典を入手できるようになります。

Think ITメルマガ会員のサービス内容を見る

他にもこの記事が読まれています