トピックの ACL のカスタマイズ
トピックの ACL を変更して、トピックの購読やメッセージの送信を実行できるユーザーをカスタマイズすることができます。ここでは、アクセス権を変更するための実装方法を説明します。
トピックの ACL エントリー
トピックの ACL エントリーに指定可能な項目は以下のとおりです。
アクション(アクセス制御)
対象のユーザーやグループが「何をできるか」を指定します。
アクション コードでの指定 ※ 対象ユーザー/グループ/Thing ができること SUBSCRIBE_TO_TOPIC topicActionSubscribe
トピックの講読。 SEND_MESSAGE_TO_TOPIC topicActionSend
トピックに対するプッシュメッセージの送信。 ※ これらのシンボルは、列挙型
KiiACLAction
で定義されています。KiiACLAction.topicActionSubscribe
のように指定できます。サブジェクト(対象)
「誰が」実行できるようになるかを指定します。
サブジェクト 誰が実行可能か 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 つ目の例に対応します。
Swift:
-
// Instantiate a group. let group = KiiGroup(uri: groupUri) do{ // Refresh the group. try group.refreshSynchronous() } catch let error as NSError { // Handle the error. return } // Instantiate a topic in the group scope. let topicName = "GroupTopic" let topic = group.topic(withName: topicName) // Get an ACL handler. let acl = topic.topicACL // Allow the authenticated users to subscribe to the topic. let entry1 = KiiACLEntry(subject: KiiAnyAuthenticatedUser.aclSubject(), andAction: KiiACLAction.topicActionSubscribe)! acl.put(entry1) // Find a user. let user : KiiUser? user = try? KiiUser.find(byUsernameSynchronous: "_I_am_a_supervisor_") if user == nil { // Handle the error. return } // Allow the user to subscribe to the topic. let entry2 = KiiACLEntry(subject: user, andAction: KiiACLAction.topicActionSubscribe)! acl.put(entry2) // Allow the user to send push messages to the topic. let entry3 = KiiACLEntry(subject: user, andAction: KiiACLAction.topicActionSend)! acl.put(entry3) var succeeded: NSArray? var failed: NSArray? do{ // Save all the ACL entries. try acl.saveSynchronous(&succeeded, didFail: &failed) } catch let error as NSError { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return }
-
// Instantiate a group. let group = KiiGroup(uri: groupUri) // Refresh the group. group.refresh { (group : KiiGroup?, error : Error?) -> Void in if (error != nil) { // Handle the error. return } // Instantiate a topic in the group scope. let topicName = "GroupTopic" let topic = group!.topic(withName: topicName) // Get an ACL handler. let acl = topic.topicACL // Allow the authenticated users to subscribe to the topic. let entry1 = KiiACLEntry(subject: KiiAnyAuthenticatedUser.aclSubject(), andAction: KiiACLAction.topicActionSubscribe)! acl.put(entry1) // Find a user. let user : KiiUser? user = try? KiiUser.find(byUsernameSynchronous: "_I_am_a_supervisor_") if user == nil { // Handle the error. return } // Allow the user to subscribe to the topic. let entry2 = KiiACLEntry(subject: user, andAction: KiiACLAction.topicActionSubscribe)! acl.put(entry2) // Allow the user to send push messages to the topic. let entry3 = KiiACLEntry(subject: user, andAction: KiiACLAction.topicActionSend)! acl.put(entry3) // Save all the ACL entries. acl.save { (acl : KiiACL , succeeded : [Any]?, failed : [Any]?, error : Error?) -> Void in if (error != nil) { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return } } }
Objective-C:
-
NSError *error; // Instantiate a group. KiiGroup *group = [KiiGroup groupWithURI:groupUri]; // Refresh the group. [group refreshSynchronous:&error]; if (error != nil) { // Handle the error. return; } // Instantiate a topic in the group scope. NSString *topicname = @"GroupTopic"; KiiTopic *topic = [group topicWithName:topicname]; // Get the ACL handler. KiiACL *acl = [topic topicACL]; // Allow the authenticated users to subscribe to the topic. KiiAnyAuthenticatedUser *authenticatedUser = [KiiAnyAuthenticatedUser aclSubject]; KiiACLEntry *entry1 = [KiiACLEntry entryWithSubject:authenticatedUser andAction:KiiACLTopicActionSubscribe]; [acl putACLEntry:entry1]; // Find a user. KiiUser* user = [KiiUser findUserByUsernameSynchronous:@"_I_am_a_supervisor_" withError:&error]; // Allow the user to subscribe to the topic. KiiACLEntry *entry2 = [KiiACLEntry entryWithSubject:user andAction:KiiACLTopicActionSubscribe]; [acl putACLEntry:entry2]; // Allow the user to send push messages to the topic. KiiACLEntry *entry3 = [KiiACLEntry entryWithSubject:user andAction:KiiACLTopicActionSend]; [acl putACLEntry:entry3]; NSArray *succeeded, *failed; // Save all the ACL entries. [acl saveSynchronous:&error didSucceed:&succeeded didFail:&failed]; if (error != nil) { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return; }
-
// Instantiate a group. KiiGroup *group = [KiiGroup groupWithURI:groupUri]; // Refresh the group. [group refreshWithBlock:^(KiiGroup *group, NSError *error) { if (error != nil) { // Handle the error. return; } // Instantiate a topic in the group scope. NSString *topicname = @"GroupTopic"; KiiTopic *topic = [group topicWithName:topicname]; // Get the ACL handler. KiiACL *acl = [topic topicACL]; // Allow the authenticated users to subscribe to the topic. KiiAnyAuthenticatedUser *authenticatedUser = [KiiAnyAuthenticatedUser aclSubject]; KiiACLEntry *entry1 = [KiiACLEntry entryWithSubject:authenticatedUser andAction:KiiACLTopicActionSubscribe]; [acl putACLEntry:entry1]; // Find a user. KiiUser* user = [KiiUser findUserByUsernameSynchronous:@"_I_am_a_supervisor_" withError:&error]; // Allow the user to subscribe to the topic. KiiACLEntry *entry2 = [KiiACLEntry entryWithSubject:user andAction:KiiACLTopicActionSubscribe]; [acl putACLEntry:entry2]; // Allow the user to send push messages to the topic. KiiACLEntry *entry3 = [KiiACLEntry entryWithSubject:user andAction:KiiACLTopicActionSend]; [acl putACLEntry:entry3]; // Save all the ACL entries. [acl saveWithBlock:^(KiiACL *acl, NSArray *succeeded, NSArray *failed, NSError *error) { if (error != nil) { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return; } }]; }];
ここでは以下の処理が行われています。
- URI から目的のグループを取得し、そのグループ内の
GroupTopic
という名前のトピックを取得します。 - 変更対象のトピックの
topicACL()
メソッドを実行して ACL ハンドラーを作成します。 KiiACLEntry(subject:andAction:)
メソッドを実行して、冒頭に示したentry1
~entry3
の ACL エントリーを作成します。put(_:)
メソッドを実行して、各 ACL エントリーをローカル保存します。save(_:)
メソッドを実行して、ローカルの ACL エントリーを Kii Cloud に保存します。
複数の ACL エントリーを追加する場合、SDK はそれらを 1 件ずつ処理するため、一部の ACL エントリーの処理が失敗する可能性があります。ACL の設定に失敗したときは、サンプルコード上の succeeded
と failed
によって、成功した ACL エントリーの一覧と成功した ACL エントリーの一覧を取得できます。
ユーザースコープのトピック
2 つ目のサンプルコードは、ユーザースコープのトピック MyTODO
に対して、以下の 1 つの ACL エントリーを追加する例です。
- URI で指定されたグループに、「トピックの購読」アクションを許可。
なお、これは アクセス権の変更例 で示したシナリオの 3 つ目の例に対応します。
Swift:
-
// Instantiate an existing topic in the user scope. let user = KiiUser.current()! let topicName = "MyTODO" let topic = user.topic(withName: topicName) // Get an ACL handler. let acl = topic.topicACL // Instantiate a group. let group = KiiGroup(uri: groupUri) do{ // Refresh the group. try group.refreshSynchronous() // Allow the group members to subscribe to the topic. let entry = KiiACLEntry(subject: group, andAction: KiiACLAction.topicActionSubscribe)! acl.put(entry) var succeeded: NSArray? var failed: NSArray? // Save all the ACL entries. try acl.saveSynchronous(&succeeded, didFail: &failed) } catch let error as NSError { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return }
-
// Instantiate an existing topic in the user scope. let user = KiiUser.current()! let topicName = "MyTODO" let topic = user.topic(withName: topicName) // Get an ACL handler. let acl = topic.topicACL // Instantiate a group. let group = KiiGroup(uri: groupUri) // Refresh the group. group.refresh { (group : KiiGroup?, error : Error?) -> Void in if (error != nil) { // Handle the error. return } // Allow the group members to subscribe to the topic. let entry = KiiACLEntry(subject: group, andAction: KiiACLAction.bucketActionQueryObjects)! acl.put(entry) // Save all the ACL entries. acl.save { (acl : KiiACL , succeeded : [Any]?, failed : [Any]?, error : Error?) -> Void in if (error != nil) { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return } } }
Objective-C:
-
NSError *error; // Instantiate an existing topic in the user scope. KiiUser* user = [KiiUser currentUser]; NSString *topicname = @"MyTODO"; KiiTopic *topic = [user topicWithName:topicname]; // Get the ACL handler. KiiACL *acl = [topic topicACL]; // Instantiate a group. KiiGroup *group = [KiiGroup groupWithURI:groupUri]; // Refresh the group. [group refreshSynchronous:&error]; if (error != nil) { // Handle the error. return; } // Allow the group members to subscribe to the topic. KiiACLEntry *entry = [KiiACLEntry entryWithSubject:group andAction:KiiACLTopicActionSubscribe]; [acl putACLEntry:entry]; NSArray *succeeded, *failed; // Save all the ACL entries. [acl saveSynchronous:&error didSucceed:&succeeded didFail:&failed]; if (error != nil) { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return; }
-
// Instantiate an existing topic in the user scope. KiiUser* user = [KiiUser currentUser]; NSString *topicname = @"MyTODO"; KiiTopic *topic = [user topicWithName:topicname]; // Get the ACL handler. KiiACL *acl = [topic topicACL]; // Instantiate a group. KiiGroup *group = [KiiGroup groupWithURI:groupUri]; // Refresh the group. [group refreshWithBlock:^(KiiGroup *group, NSError *error) { if (error != nil) { // Handle the error. return; } // Allow the group members to subscribe to the topic. KiiACLEntry *entry = [KiiACLEntry entryWithSubject:group andAction:KiiACLTopicActionSubscribe]; [acl putACLEntry:entry]; // Save all the ACL entries. [acl saveWithBlock:^(KiiACL *acl, NSArray *succeeded, NSArray *failed, NSError *error) { if (error != nil) { // Failed to update one ACL entry at least. // Check the error description and the succeeded and failed arrays. return; } }]; }];
基本的な処理は、先ほどのサンプルコードと同様です。こちらの例では、ACL エントリーのサブジェクトとしてユーザーグループを指定しています。これにより、指定したアクション(トピックの購読)が、このユーザーグループのメンバー全員に許可されます。
トピックの ACL エントリーを削除する
設定されている ACL エントリーを削除するには、KiiACLEntry
の grant
を false にしたエントリーを作成して保存します。サーバー上の ACL から指定した ACL エントリーが削除されます。
サンプルコードはグループスコープのトピック、ユーザースコープのトピックとも、上記の ACL エントリーの追加の場合と同様で、grant
プロパティを false にする点だけが異なります。
KiiACL
の removeACLEntry(_:)
メソッドは、クライアント側で準備中の「ACL の 変更リスト」のエントリーを削除するもので、サーバー上の ACL エントリーを削除するものではない点にご注意ください。ACL 設定のコードでは、クライアント上の acl
に対して KiiACLTopicActionSubscribe
を伴う ACL エントリーの削除要求を登録してから、save
でサーバーに反映しています。removeACLEntry(_:)
メソッドは、この ACL エントリーを変更リストから削除するためのもので、サーバー上の ACL を直接操作するためのものではありません。
トピックの ACL を取得する
トピックに設定されている ACL を取得できます。ACL エントリーを明示的に設定していない場合でも、デフォルトの ACL を取得することができます。
以下のように、ACL は ACL エントリーの NSArray として取得できます。
Swift:
-
// Instantiate an existing topic in the user scope. let topic = KiiUser.current()!.topic(withName: "MyTODO") // Get the ACL handler. let acl = topic.topicACL do{ // Get the ACL. let aclList = try acl.listACLEntriesSynchronous() as! [KiiACLEntry] for entry in aclList{ let action = entry.action let subject = entry.subject // Check the ACL entry. } }catch(let error as NSError){ // Handle the error. return }
-
// Instantiate an existing topic in the user scope. let topic = KiiUser.current()!.topic(withName: "MyTODO") // Get the ACL handler. let acl = topic.topicACL // Get the ACL. acl.listACLEntries { (retAcl : KiiACL, result : [Any]?, error : Error?) -> Void in if (error != nil) { // Handle the error. return } let aclList = result as! [KiiACLEntry] for entry in aclList{ let action = entry.action let subject = entry.subject // Check the ACL entry. } }
Objective-C:
-
// Instantiate an existing topic in the user scope. KiiTopic *topic = [[KiiUser currentUser] topicWithName:@"MyTODO"]; // Get the ACL handler. KiiACL *acl = [topic topicACL]; NSError *error = nil; // Get the ACL. NSArray *aclList = [acl listACLEntriesSynchronous:&error]; if (error != nil) { // Handle the error. return; } for (KiiACLEntry *entry in aclList) { KiiACLAction action = entry.action; id subject = entry.subject; // Check the ACL entry. }
-
// Instantiate an existing topic in the user scope. KiiTopic *topic = [[KiiUser currentUser] topicWithName:@"MyTODO"]; // Get the ACL handler. KiiACL *acl = [topic topicACL]; // Get the ACL. [acl listACLEntriesWithBlock:^(KiiACL *acl, NSArray *aclList, NSError *error) { if (error != nil) { // Handle the error. return; } for (KiiACLEntry *entry in aclList) { KiiACLAction action = entry.action; id subject = entry.subject; // Check the ACL entry. } }];
topicACL()
メソッドをコールしてKiiACL
のインスタンスを生成します。listACLEntries(_:)
メソッドをコールして、登録されている ACL をKiiACLEntry
インスタンスの NSArray として取得します。- NSArray の各エントリーを確認することで目的の処理を実行します。
ACL 設定の際、設定済みの ACL エントリーをさらに追加しようとするとエラーとなります。ここに示す方法で ACL を事前にチェックすることによって、必要な ACL エントリーの変更差分を作成できます。
期待どおりに動作しない場合
複数回実行するとエラーになる
ACL エントリーは初期化処理等で 1 回だけ書き換え、次回の実行時には再設定しないような実装が必要です。
保存しようとしている ACL エントリーがすでに設定されていた場合、エラーになります。特に、同じ登録処理を複数回実行すると、登録しようとしている ACL エントリーがすでに存在することになるため、エラーになる点に注意が必要です。
なお、複数の ACL エントリーは 1 件ずつサーバーに反映するため、途中でエラーが発生すると不完全な形で ACL エントリーが保存されます。このような状況から回復するには、既存の ACL をサーバーから一旦取得し、重複している ACL エントリーを削除してから登録するような処理が必要です。取得方法の詳細は トピックの ACL を取得する をご覧ください。
ACL エントリーを削除できない
トピック作成者やスコープオーナーにデフォルトで許可されるアクションの ACL エントリーは削除できません。詳細は スコープオーナーや作成者の ACL エントリーは削除できません をご覧ください。