トピックの ACL のカスタマイズ

トピックの ACL を変更して、トピックの購読やメッセージの送信を実行できるユーザーをカスタマイズすることができます。ここでは、アクセス権を変更するための実装方法を説明します。

トピックの ACL エントリー

トピックの ACL エントリーに指定可能な項目は以下のとおりです。

  • アクション(アクセス制御)

    対象のユーザーやグループが「何をできるか」を指定します。

    アクション コードでの指定 ※ 対象ユーザー/グループ/Thing ができること
    SUBSCRIBE_TO_TOPIC SUBSCRIBE_TO_TOPIC トピックの講読。
    SEND_MESSAGE_TO_TOPIC SEND_MESSAGE_TO_TOPIC トピックに対するプッシュメッセージの送信。

    ※ これらのシンボルは、列挙型 TopicAction で定義されています。KiiACL.TopicAction.SUBSCRIBE_TO_TOPIC のように指定できます。

  • サブジェクト(対象)

    「誰が」実行できるようになるかを指定します。

    サブジェクト 誰が実行可能か
    KiiUser インスタンス 指定されたユーザー。
    KiiGroup インスタンス 指定されたグループのメンバー。
    KiiThing インスタンス 指定された Thing。
    KiiAnyAuthenticatedUser ログイン済みの全ユーザー。
    KiiAnonymousUser 匿名ユーザー。

    ログイン済みの全ユーザーと匿名ユーザーの定義については、サブジェクト の説明を参照してください。

トピック の ACL の管理

トピックの ACL にエントリーを追加または削除できます。ACL エントリーの一覧を取得することもできます。

トピックに ACL エントリーを追加する

以下にグループスコープのトピックとユーザースコープのトピックに ACL エントリーを追加するサンプルコードを示します。

グループスコープのトピック

1 つ目のサンプルコードは、グループスコープのトピック GroupTopic に対して、以下の 3 つの ACL エントリーを追加する例です。

  • entry1:「認証済みユーザー全員」に「トピックの購読」アクションを許可。
  • entry2_I_am_a_supervisor_ という名前のユーザーに「トピックの購読」アクションを許可。
  • entry3_I_am_a_supervisor_ という名前のユーザーに「トピックへのプッシュメッセージ送信」アクションを許可。

なお、これは アクセス権の変更例 で示したシナリオの 1 つ目と 2 つ目の例に対応します。

  • try {
      // Instantiate a group.
      KiiGroup group = KiiGroup.createByUri(groupUri);
    
      // Refresh the group.
      group.refresh();
    
      // Instantiate a topic in the group scope.
      String topicName = "GroupTopic";
      KiiTopic topic = group.topic(topicName);
    
      // Get the ACL handler.
      KiiACL acl = topic.acl();
    
      // Allow the authenticated users to subscribe to the topic.
      KiiACLEntry entry1 = new KiiACLEntry(KiiAnyAuthenticatedUser.create(),
          KiiACL.TopicAction.SUBSCRIBE_TO_TOPIC, true);
      acl.putACLEntry(entry1);
    
      // Find a user.
      KiiUser user = KiiUser.findUserByUserName("_I_am_a_supervisor_");
    
      // Allow the user to subscribe to the topic.
      KiiACLEntry entry2 = new KiiACLEntry(user,
          KiiACL.TopicAction.SUBSCRIBE_TO_TOPIC, true);
      acl.putACLEntry(entry2);
    
      // Allow the user to send push messages to the topic.
      KiiACLEntry entry3 = new KiiACLEntry(user,
          KiiACL.TopicAction.SEND_MESSAGE_TO_TOPIC, true);
      acl.putACLEntry(entry3);
    
      // Save all the ACL entries.
      acl.save();
    
    } catch (IOException e) {
      // Handle the error.
    } catch (AppException e) {
      // Handle the error.
    } catch (GroupOperationException e) {
      // Handle the error.
    } catch (ACLOperationException e) {
      // Handle the error.
    }
  • // Instantiate a group.
    KiiGroup group = KiiGroup.createByUri(groupUri);
    
    // Refresh the group.
    group.refresh(new KiiGroupCallBack() {
      @Override
      public void onRefreshCompleted(int token, KiiGroup group, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        // Instantiate a topic in the group scope.
        String topicName = "GroupTopic";
        KiiTopic topic = group.topic(topicName);
    
        // Get the ACL handler.
        final KiiACL acl = topic.acl();
    
        // Allow the authenticated users to subscribe to the topic.
        KiiACLEntry entry1 = new KiiACLEntry(KiiAnyAuthenticatedUser.create(),
                KiiACL.TopicAction.SUBSCRIBE_TO_TOPIC, true);
        acl.putACLEntry(entry1);
    
        // Find a user.
        KiiUser.findUserByUserName("_I_am_a_supervisor_", new KiiUserCallBack() {
          @Override
          public void onFindCompleted(int token, KiiUser caller, KiiUser found, Exception exception) {
            if (exception != null) {
              // Handle the error.
              return;
            }
            KiiUser user = found;
    
            // Allow the user to subscribe to the topic.
            KiiACLEntry entry2 = new KiiACLEntry(user,
                    KiiACL.TopicAction.SUBSCRIBE_TO_TOPIC, true);
            acl.putACLEntry(entry2);
    
            // Allow the user to send push messages to the topic.
            KiiACLEntry entry3 = new KiiACLEntry(user,
                    KiiACL.TopicAction.SEND_MESSAGE_TO_TOPIC, true);
            acl.putACLEntry(entry3);
    
            // Save all the ACL entries.
            acl.save(new KiiACLCallBack() {
              @Override
              public void onSaveCompleted(int token, KiiACL acl, Exception exception) {
                if (exception != null) {
                  // Handle the error.
                  return;
                }
              }
            });
          }
        });
      }
    });

ここでは以下の処理が行われています。

  1. URI から目的のグループを取得し、そのグループ内の GroupTopic という名前のトピックを取得します。
  2. 変更対象のトピックの acl() メソッドを実行して ACL ハンドラーを作成します。
  3. KiiACLEntry のコンストラクタを呼び出して、冒頭に示した entry1entry3 の ACL エントリーを作成します。
  4. 作成した 3 つの ACL エントリーそれぞれを KiiACL オブジェクトの putACLEntry() メソッドでローカル保存します。
  5. KiiACL オブジェクトの save() メソッドを実行し、ローカルの ACL エントリーを Kii Cloud に保存します。

複数の ACL エントリーを追加する場合、SDK はそれらを 1 件ずつ処理するため、一部の ACL エントリーの処理が失敗する可能性があります。ACL の設定に失敗したときは、ACLOperationExceptiongetFailedACLEntries() メソッドを使うと、追加されなかった ACL エントリーの一覧を取得できます。

ユーザースコープのトピック

2 つ目のサンプルコードは、ユーザースコープのトピック MyTODO に対して、以下の 1 つの ACL エントリーを追加する例です。

  • URI で指定されたグループに、「トピックの購読」アクションを許可。

なお、これは アクセス権の変更例 で示したシナリオの 3 つ目の例に対応します。

  • try {
      // Instantiate an existing topic in the user scope.
      String topicName = "MyTODO";
      KiiTopic topic = KiiUser.topic(topicName);
    
      // Get the ACL handler.
      KiiACL acl = topic.acl();
    
      // Instantiate a group.
      KiiGroup group = KiiGroup.createByUri(groupUri);
    
      // Refresh the group.
      group.refresh();
    
      // Allow the group members to subscribe to the topic.
      KiiACLEntry entry = new KiiACLEntry(group,
          KiiACL.TopicAction.SUBSCRIBE_TO_TOPIC, true);
      acl.putACLEntry(entry);
    
      // Save all the ACL entries.
      acl.save();
    
    } catch (GroupOperationException ge) {
      // Handle the error.
    } catch (ACLOperationException e) {
      // Handle the error.
    }
  • // Instantiate an existing topic in the user scope.
    String topicName = "MyTODO";
    KiiTopic topic = KiiUser.topic(topicName);
    
    // Get the ACL handler.
    final KiiACL acl = topic.acl();
    
    // Instantiate a group.
    KiiGroup group = KiiGroup.createByUri(groupUri);
    
    // Refresh the group.
    group.refresh(new KiiGroupCallBack() {
      @Override
      public void onRefreshCompleted(int token, KiiGroup group, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        // Allow the group members to subscribe to the topic.
        KiiACLEntry entry = new KiiACLEntry(group,
                KiiACL.TopicAction.SUBSCRIBE_TO_TOPIC, true);
        acl.putACLEntry(entry);
    
        // Save all the ACL entries.
        acl.save(new KiiACLCallBack() {
          @Override
          public void onSaveCompleted(int token, KiiACL acl, Exception exception) {
            if (exception != null) {
              // Handle the error.
              return;
            }
          }
        });
      }
    });

基本的な処理は、先ほどのサンプルコードと同様です。こちらの例では、ACL エントリーのサブジェクトとしてユーザーグループを指定しています。これにより、指定したアクション(トピックの購読)が、このユーザーグループのメンバー全員に許可されます。

トピックの ACL エントリーを削除する

設定されている ACL エントリーを削除するには、KiiACLEntry の第 3 引数 grant を false にしたエントリーを作成して保存します。サーバー上の ACL から指定した ACL エントリーが削除されます。

サンプルコードはグループスコープのトピック、ユーザースコープのトピックとも、上記の ACL エントリーの追加の場合と同様で、new KiiACLEntry の第 3 引数 grant を false にする点だけが異なります。

KiiACL クラスの removeACLEntry() メソッドは、クライアント側で準備中の「ACL の 変更リスト」のエントリーを削除するもので、サーバー上の ACL エントリーを削除するものではない点にご注意ください。ACL 設定のコードでは、クライアント上の acl に対して SUBSCRIBE_TO_TOPIC を伴う ACL エントリーの削除要求を登録してから、save() メソッドでサーバーに反映しています。removeACLEntry は、この ACL エントリーを変更リストから削除するためのもので、サーバー上の ACL を直接操作するためのものではありません。

トピックの ACL を取得する

トピックに設定されている ACL を取得できます。ACL エントリーを明示的に設定していない場合でも、デフォルトの ACL を取得することができます。

以下のように、ACL は ACL エントリーの Set として取得できます。

  • // Instantiate an existing topic in the user scope.
    String topicName = "MyTODO";
    KiiTopic topic = KiiUser.topic(topicName);
    
    // Get the ACL handler.
    KiiACL topicAcl = topic.acl();
    
    try {
      // Get the ACL.
      Set<KiiACLEntry> list = topicAcl.listACLEntries();
      for (KiiACLEntry entry : list) {
        KiiACL.Action action = entry.getAction();
        KiiSubject subject = entry.getSubject();
        // Check the ACL entry.
      }
    } catch (ACLOperationException e) {
      // Handle the error.
    }
  • // Instantiate an existing topic in the user scope.
    String topicName = "MyTODO";
    KiiTopic topic = KiiUser.topic(topicName);
    
    // Get the ACL handler.
    KiiACL topicAcl = topic.acl();
    
    // Get the ACL.
    topicAcl.listACLEntries(new KiiACLCallBack() {
      public void onListACLEntriesCompleted(int token, Set<KiiACLEntry> list, KiiACL acl, Exception exception) {
        if (exception != null) {
          // Handle the error.
          return;
        }
        for (KiiACLEntry entry : list) {
          KiiACL.Action action = entry.getAction();
          KiiSubject subject = entry.getSubject();
          // Check the ACL entry.
        }
      }
    });
  1. acl() メソッドをコールして KiiACL のインスタンスを生成します。
  2. listAclEntries() メソッドをコールして、登録されている ACL を KiiACLEntry インスタンスの Set として取得します。
  3. Set の各エントリーを確認することで目的の処理を実行します。

ACL 設定の際、設定済みの ACL エントリーをさらに追加しようとするとエラーとなります。ここに示す方法で ACL を事前にチェックすることによって、必要な ACL エントリーの変更差分を作成できます。

期待どおりに動作しない場合

  • 複数回実行するとエラーになる

    ACL エントリーは初期化処理等で 1 回だけ書き換え、次回の実行時には再設定しないような実装が必要です。

    保存しようとしている ACL エントリーがすでに設定されていた場合、エラーになります。特に、同じ登録処理を複数回実行すると、登録しようとしている ACL エントリーがすでに存在することになるため、エラーになる点に注意が必要です。

    なお、複数の ACL エントリーは 1 件ずつサーバーに反映するため、途中でエラーが発生すると不完全な形で ACL エントリーが保存されます。このような状況から回復するには、既存の ACL をサーバーから一旦取得し、重複している ACL エントリーを削除してから登録するような処理が必要です。取得方法の詳細は トピックの ACL を取得する をご覧ください。

  • ACL エントリーを削除できない

    トピック作成者やスコープオーナーにデフォルトで許可されるアクションの ACL エントリーは削除できません。詳細は スコープオーナーや作成者の ACL エントリーは削除できません をご覧ください。