Security & Privacy
Parseを利用したセキュアなアプリ開発完全ガイドライン
18 分
parseを使用して安全なアプリを作成する方法 はじめに back4appコミュニティの皆さん、こんにちは! これは、 startup soul http //startup soul com/ のjoren wingeによるゲストチュートリアルです。私たちはスタートアップが迅速に製品を構築し、立ち上げるのを手助けしています。back4appの友人たちが、back4appの上に安全なアプリを構築する方法を示してほしいと頼んできました。 この記事では、back4app上で安全なto doアプリを作成する手順を説明します。セキュリティは重要です。アプリが成功する場合、アプリのデータが安全であり、システムがハッキングされないことを確認する必要があります。 parseのセキュリティ機能 まず、最初のセキュリティレベル、acl(アクセス制御リスト)について話しましょう。aclは、オブジェクトを作成する際に設定するルールです。to doアイテムを作成するとしましょう。作成時に、そのアイテムを誰が読み取れるか、誰が書き込めるかを指定できます。特定のユーザーにそのアイテムを読み取る権限や書き込む権限を与えることができますし、どちらか一方を公開に設定することで誰でもアクセスできるようにすることもできます。しかし、aclは常に機能するわけではありません。 場合によっては、単純なaclの代わりに、もう少し洗練されたロジックが必要になることがあります。時には、aclのような絶対的な基準ではなく、条件付きでオブジェクトへのアクセスを与える必要がある場合もあります。だから、aclの使用をスキップしましょう。aclはあまりにも堅苦しく、同時にデータへのアクセスを許可しすぎます。さて、back4appとparse serverで安全なアプリを構築するための秘密をお教えします。準備はいいですか? クラスレベルの権限!はい、データベース内の各テーブルに対してクラスレベルの権限を設定します。そして、設定する権限のレベルは全くの無権限です。すべてのテーブルをロックダウンし、誰にも読み取りまたは書き込みアクセスを許可しないようにします!極端に聞こえるかもしれませんが、これは安全なアプリを作成するための第一歩です。唯一許可する権限は、ユーザーテーブルに対して新しいユーザーオブジェクトを作成するためと、ユーザーが自分のデータを表示するためのもので、これは現在のユーザーを更新するために必要です。 aclを使用して、ユーザーが他のユーザーのデータを表示できないようにします。これはaclを使用する唯一の機会なので、完全に無駄ではないと思います。持っていると便利ですが、すべてをそれに頼らないでください。しかし、データにアクセスする方法は何ですか?良い質問ですね、それについて考えてくれて嬉しいです!クライアントがデータに制御された方法でアクセスできる秘密は、クライアントとデータベースの間のすべてのインタラクションをクラウドコード関数を通じてフィルタリングすることです。はい、アプリで何かをするたびに、今ではカスタムクラウドコード関数を通じて行われます。クライアントベースのpfqueriesはもうありません。 サインアップ機能、サインイン機能、パスワードを忘れた機能、ログアウト機能を除いて、ほぼすべてのクライアントベースのparse sdkの使用をスキップします。これらについては、まだネイティブクライアントsdkを使用します。単純にそれが簡単だからです。クラウドコードを書いたことはありますか?いいえ、そうですか?まあ、それは非常に簡単です。javascriptで、parse javascript sdkを使用しますが、内部では自分のアプリのサーバー上で動作します。実際、parse serverはnode jsに基づいているので、expressでルートを書くのと非常に似ていますが、クエリ言語がすでにインストールされているため、node js expressアプリ全体を書くよりもはるかに簡単です。 では、私たちがすることはこれです。すでに作成したiosのtodoアプリを使用します。どのように作成したかを示すことはしません。代わりに、クラウドコードの記述とデータベースのセキュリティに焦点を当てます。このtodoアプリは、あなた自身のtodoにのみアクセスでき、あなた自身のtodoのみを書き込むことができる安全なアプリになります。データはサーバー上で安全に保護され、悪意のある不正クライアントから守られます。また、安全なparseバックグラウンドジョブを書く方法もお見せします 基本的にはcronジョブと同じことです これにより、自動化されたサービスがスケジュールに従ってデータを操作できるようになります。複雑に聞こえますが、そうではありません。自動化されたスケジュールであなたが望むことをする小さなサーバーロボットを想像してみてください。かっこいいですよね?では、始めましょう!!!!!! back4appセキュアtodoアプリを設定しましょう 1\) back4appでアプリを作成する back4appで新しいアプリを作成します。アプリの名前を「secure todo app」とします。 注 新しいparseアプリのチュートリアル を参照して、back4appでアプリを作成する方法を学びます。 アプリのコア設定ページに移動し、「アプリの詳細を編集」をクリックします。 「クライアントクラスの作成を許可する」というチェックボックスを無効にして、クライアントクラスの作成を無効にし、保存をクリックします。ルールとして、クライアントができることを制限したいです。 2\) ユーザークラスのクラスレベルのセキュリティ権限を設定する 次に、userクラスの権限を設定します。back4appデータベースダッシュボードに移動し、userクラスをクリックします。次に、セキュリティタブをクリックし、右上のギアアイコンをクリックします。「シンプル/高度な」メニューが表示されるはずです。スライダーを高度に切り替えます。これにより、このクラスの完全なクラスレベルの権限が表示されます。findチェックボックスを無効にします。updateとdeleteチェックボックスを無効にします。最後に、add fieldチェックボックスを無効にします。それから保存をクリックします。あなたのセキュリティ設定はこのように見えるはずです。 3\) todoクラスを作成します クラスを作成し、todoと呼びます。クラスのタイプをカスタムに設定します。 4\) todoクラスのクラスレベルのセキュリティ権限を設定します 次に、todoクラスの権限を設定します。back4appデータベースダッシュボードに移動し、todoクラスをクリックします。次に、セキュリティタブをクリックし、右上のギアアイコンをクリックします。「シンプル/高度な」メニューが表示されるはずです。スライダーを高度に切り替えます。これにより、このクラスの完全なクラスレベルの権限が表示されます。すべてを無効にしてから保存をクリックします。あなたのセキュリティ設定はこのように見えるはずです。 5\) todoクラスにいくつかのカラムを追加しましょう まず、todoクラスをuserクラスに結合しましょう。それを行うために、2つのカラムを追加します。 最初のカラムは「user」と呼ばれ、ユーザークラスへのポインタになります。 次に、それを作成したユーザーのオブジェクトidのためのカラムを作成しましょう。それは文字列型で「userobjectid」と呼ばれます。 次に、実際のtodo情報を保持するカラムを作成しましょう。それも文字列型で「tododescription」と呼ばれます。 todoの状態を保持するためのbooleanを作成しましょう。それを「finished」と呼びましょう。 最後に、todoを完了した日付を保持するためのもう1つのカラムを追加しましょう。それを「finisheddate」と呼び、日付型に設定します。 あなたのtodoクラスはこのようになります 6\) クライアントについて見てみましょう: クライアントは非常に基本的なtodoアプリです。ログイン、新しいユーザーの作成、パスワードのリセットのために組み込みのパース関数を使用します。それ以外はすべてクラウドコードベースで安全です。ユーザーのaclも、ログインまたはサインアップするとすぐに設定され、システムが安全であることを100%確実にします。ログインまたはサインアップ時にユーザーのaclを設定するためのクラウドコード関数を書き始めましょう。 いつでも、このチュートリアルで構築された完全なiosプロジェクトにアクセスできます。 githubリポジトリ このチュートリアルのために構築されたmain jsクラウドコードファイルにもアクセスできます。 githubリポジトリ。 1 クライアントでtodocontroller swiftに移動し、setusersaclsnow関数を探します。この関数は、ログインするかloggedinviewcontroller swiftを表示するときに呼び出されます。この関数は、ログインしているかどうかを確認し、ログインしている場合は、個人のユーザーaclを設定するためにクラウド関数を呼び出します。 todocontroller swift 1 func setusersaclsnow(){ 2 if pfuser current() != nil{ 3 let cloudparams \[anyhashable\ string] = \["test" "test"] 4 pfcloud callfunction(inbackground setusersacls, withparameters cloudparams, block { 5 (result any?, error error?) > void in 6 if error != nil { 7 //print(error debugdescription) 8 if let descrip = error? localizeddescription{ 9 print(descrip) 10 } 11 }else{ 12 print(result as! string) 13 } 14 }) 15 } 16 } 2 では、クラウドコード関数を書きましょう parse server 3 x 1 parse cloud define('setusersacls', async(request) => { 2 let currentuser = request user; 3 currentuser setacl(new parse acl(currentuser)); 4 return await currentuser save(null, { usemasterkey true }); 5 }); parse server 2 x 1 parse cloud define('setusersacls', function (request, response) { 2 var currentuser = request user; 3 currentuser setacl(new parse acl(currentuser)); 4 currentuser save(null, { 5 usemasterkey true, 6 success function (object) { 7 response success("acls updated"); 8 }, 9 error function (object, error) { 10 response error("got an error " + error code + " " + error description); 11 } 12 }); 13 }); 3 このクラウドコードは、アプリを安全に保つための2つの重要な機能、request userとmasterkeyを使用しています。request userは、クラウドコード呼び出しを行っているユーザーにアクセスできるようにし、そのユーザーのアクセスを制限することを可能にします。この場合、現在のユーザーのみに読み取りアクセスを制限するためにユーザーのaclを設定するために使用しています。この方法では、ユーザーは自分の情報のみを読むことができます。クラスレベルの権限は、現在のユーザーであっても書き込みアクセスを防ぎます。このようにして、ユーザーは自分の情報を変更することができません。彼らはクラウドコードを通じて自分のユーザーに関することだけを変更できます。ユーザーが最初にサインアップする際に虚偽の情報をインポートすることは可能ですが、新しいユーザーが作成された後にユーザーの情報を確認するためのクラウドコード関数を書くことをお勧めします。新しいユーザーを作成するための組み込みのparse関数は非常に便利なので、これは良いトレードオフだと思いますが、サインアップ直後にクラウドコードを介してユーザーのデフォルト値を設定することもできます。また、クラウドコードに多くのフェイルセーフを記述し、ユーザーが最初に作成されたときにインポートされた悪意のあるユーザー情報を検出するためにバックグラウンドジョブを使用して自動的かつ継続的に実行させることもできます。本当に安全を確保したい場合は、メンバーシップステータスや支払い情報などの機密情報をユーザーテーブルとは別のテーブルに保存することができます。そうすれば、ユーザーはユーザー作成時に機密情報を偽装することができません。 4 次に、todoの作成を見てみましょう。クライアントでtodocontroller swiftに移動し、savetodoという関数を探します。この関数は新しいtodoを作成するときに呼び出されます。この関数はtodoを説明する文字列を受け取り、それをデータベースに保存します。 todocontroller swift 1 func savetodo(todostring\ string, completion @escaping ( result bool, message\ string, todoarray \[todo]) >()){ 2 var resulttodoarray \[todo] = \[] 3 let cloudparams \[anyhashable\ any] = \["todostring"\ todostring] 4 pfcloud callfunction(inbackground createtodosforuser, withparameters cloudparams, block { 5 (result any?, error error?) > void in 6 if error != nil { 7 if let descrip = error? localizeddescription{ 8 completion(false, descrip, resulttodoarray) 9 } 10 }else{ 11 resulttodoarray = result as! \[todo] 12 completion(true, "success", resulttodoarray) 13 } 14 }) 15 } 5 では、データベースにtodoを保存するためのクラウドコード関数を書きましょう。 parse server 3 x 1 parse cloud define("createtodosforuser", async(request) => { 2 let currentuser = request user; 3 let todostring = request params todostring; 4 let todo = parse object extend("todo"); 5 let todo = new todo(); 6 todo set("user", currentuser); 7 todo set("userobjectid", currentuser id); 8 todo set("tododescription", todostring); 9 todo set("finished", false); 10 return await todo save(null, { usemasterkey true }); 11 }); parse server 2 x 1 parse cloud define("createtodosforuser", function(request, response) { 2 var currentuser = request user; 3 var todostring = request params todostring; 4 var todo = parse object extend("todo"); 5 var todo = new todo(); 6 todo set("user", currentuser); 7 todo set("userobjectid", currentuser id); 8 todo set("tododescription", todostring); 9 todo set("finished", false); 10 todo save(null, { 11 usemasterkey true, 12 success function (object) { 13 response success(\[todo]); 14 }, 15 error function (object, error) { 16 response error("got an error " + error code + " " + error description); 17 } 18 }); 19 }); 6 このクラウドコード関数はtodoオブジェクトを作成し、現在のユーザーをオブジェクトの所有者として設定します。これは、作成したユーザーだけがそれを見つけたり変更したりできるようにするために重要です。クライアントでtodoを作成できないようにすることで、todoオブジェクトが私たちの基準に従うように強制し、todosがそれを作成したユーザーに所有されることを確認しています。 7 次に、サーバーから作成したtodoを取得する方法を見てみましょう。クライアントでtodocontroller swiftに移動し、gettodosfordate関数を探します。この関数は、todoを取得する際に呼び出されます。この関数は日付をパラメータとして受け取り、その日付以前に作成されたtodoのリストを降順で取得します。日付を使用することは、スキップを使用しない遅延読み込みクエリを書くための素晴らしい方法です。スキップは、大きなデータセットでは失敗することがあります。 todocontroller swift 1 func savetodo(todostring\ string, completion @escaping ( result bool, message\ string, todoarray \[todo]) >()){ 2 var resulttodoarray \[todo] = \[] 3 let cloudparams \[anyhashable\ any] = \["date"\ date] 4 pfcloud callfunction(inbackground gettodosforuser, withparameters cloudparams, block { 5 (result any?, error error?) > void in 6 if error != nil { 7 if let descrip = error? localizeddescription{ 8 completion(false, descrip, resulttodoarray) 9 } 10 }else{ 11 resulttodoarray = result as! \[todo] 12 completion(true, "success", resulttodoarray) 13 } 14 }) 15 } 8 では、開始日を基にデータベースからtodoを取得するためのクラウドコード関数を書きましょう。パラメータの日付より前に作成されたtodoをクエリしますので、‘query lessthan’を使用します。なぜなら、日付は基本的に未来に行くほど大きくなる数字だからです。ここには少し厄介なコードも含めました。todoを作成したユーザーオブジェクトを含めるとしますが、そのユーザーに関する機密情報を他のユーザーと共有したくない場合、jsonレスポンスからそれを削除する必要があります。そこで、forループを使ってtodoからユーザーオブジェクトを取り出し、jsonからメールアドレスとユーザー名を削除し、再びtodoに戻します。これは、返すフィールドを制御できない状況でのapi呼び出しから機密データを削除するのに便利です 例えば、含まれているユーザーオブジェクトのように。この場合、実際には必要ありません。なぜなら、この関数はあなた自身が作成したtodoのみを返すからです。これを行うために、currentuserを再度使用して、リクエストに添付されたcurrentuserによって作成されたtodoのみをクエリします。結果は降順で返されるため、最新のtodoが最初に表示されます。別のtodoのバッチを遅延読み込みする必要がある場合、最後のtodoからcreatedat日付を取得し、それを次のリクエストのための日付パラメータとして使用します。 parse server 3 x 1 parse cloud define("gettodosforuser", async(request) => { 2 let currentuser = request user; 3 let date = request params date; 4 let query = new parse query("todo"); 5 query equalto("user", currentuser); 6 query lessthan("createdat", date); 7 query descending("createdat"); 8 query limit(100); 9 query include("user"); 10 let results = await query find({ usemasterkey true }); 11 if(results length === 0) throw new error('no results found!'); 12 13 let resultsarray = \[]; 14 for (let i = 0; i < results length; i++) { 15 let todo = results\[i]; 16 let tempuser = todo get("user"); 17 let jsonuser = tempuser tojson(); 18 delete jsonuser email; 19 delete jsonuser username; 20 21 jsonuser type = "object"; 22 jsonuser classname = " user"; 23 24 let cleanedtodo = todo tojson(); 25 cleanedtodo user = jsonuser; 26 cleanedtodo type = "object"; 27 cleanedtodo classname = "todo"; 28 resultsarray push(cleanedtodo); 29 } 30 return resultsarray; 31 }); parse server 2 x 1 parse cloud define("gettodosforuser", function(request, response) { 2 var currentuser = request user; 3 var date = request params date; 4 var query = new parse query("todo"); 5 query equalto("user", currentuser); 6 query lessthan("createdat", date); 7 query descending("createdat"); 8 query limit(100); 9 query include("user"); 10 query find({ 11 usemasterkey true, 12 success function (results) { 13 var resultsarray = \[]; 14 for (var i = 0; i < results length; i++) { 15 var todo = results\[i]; 16 var tempuser = todo get("user"); 17 var jsonuser = tempuser tojson(); 18 delete jsonuser email; 19 delete jsonuser username; 20 21 jsonuser type = "object"; 22 jsonuser classname = " user"; 23 24 var cleanedtodo = todo tojson(); 25 cleanedtodo user = jsonuser; 26 cleanedtodo type = "object"; 27 cleanedtodo classname = "todo"; 28 resultsarray push(cleanedtodo); 29 } 30 response success(resultsarray); 31 }, 32 error function (error) { 33 response error(" error " + error code + " " + error message); 34 } 35 }); 36 }); 9 現在、todosがあるので、アプリでそれらを見ることができ、必要に応じて完了としてマークできます。それについて次に説明しましょう。 10 todoを完了としてマークするには、作成したtodoのいずれかにある「完了としてマーク」ボタンを押してください。これにより、選択したtodoをパラメータとして受け取る‘marktodosascompletedfor’というメソッドがtodocontroller swiftで呼び出されます。todoのobjectidをサーバーにパラメータとして送信し、その後、更新されたtodoを結果として返します。 todocontroller swift 1 func marktodosascompletedfor(todo\ todo, completion @escaping ( result bool, message\ string, todoarray \[todo]) >()){ 2 var resulttodoarray \[todo] = \[] 3 let cloudparams \[anyhashable\ any] = \["todoid"\ todo objectid ?? ""] 4 pfcloud callfunction(inbackground marktodoascompletedforuser, withparameters cloudparams, block { 5 (result any?, error error?) > void in 6 if error != nil { 7 if let descrip = error? localizeddescription{ 8 completion(false, descrip, resulttodoarray) 9 } 10 }else{ 11 resulttodoarray = result as! \[todo] 12 completion(true, "success", resulttodoarray) 13 } 14 }) 15 } 11 さて、このtodoを更新するためのクラウドコードを書きます。これは、objectidに基づいて更新するtodoを探しますが、currentuserも使用して、objectidに関連付けられたtodoがクエリを行っているユーザーによって作成されたものであることを確認します。これにより、作成したtodoのみを表示できるようになり、安全性が確保されます。サーバーがtodoを見つけた後に検索を続けないように、結果の制限を1に設定しています。objectidに基づいてオブジェクトを見つけるための別のメソッドもありますが、objectidに関連付けられたオブジェクトが見つからない場合に奇妙な結果を返す可能性があるため、私はそれを使用したくありません。また、オブジェクトが更新されたときの現在の日付で‘finisheddate’を設定しています。この関数によってのみfinisheddateが設定されることで、finisheddateが安全であり、偽造されたり変更されたりすることができないことを確認しました。また、‘query equalto(“finished”, false)’を使用して、未完了のtodoのみが完了としてマークされ、finisheddateが設定されることを確認しました。つまり、一度todoが完了としてマークされると、後で再度完了としてマークすることはできません。 parse server 3 x 1 parse cloud define("marktodoascompletedforuser", async(request) => { 2 let currentuser = request user; 3 let todoid = request params todoid; 4 let query = new parse query("todo"); 5 query equalto("user", currentuser); 6 query equalto("objectid", todoid); 7 query equalto("finished", false); 8 let todo = await query first({ usemasterkey true }); 9 if(object keys(todo) length === 0) throw new error('no results found!'); 10 todo set("finished", true); 11 let date = new date(); 12 todo set("finisheddate", date); 13 try { 14 await todo save(null, { usemasterkey true}); 15 return todo; 16 } catch (error){ 17 return("getnewstore error " + error code + " " + error message); 18 } 19 }); parse server 2 x 1 parse cloud define("marktodoascompletedforuser", function(request, response) { 2 var currentuser = request user; 3 var todoid = request params todoid; 4 var query = new parse query("todo"); 5 query equalto("user", currentuser); 6 query equalto("objectid", todoid); 7 query equalto("finished", false); 8 query limit(1); 9 query find({ 10 usemasterkey true, 11 success function (results) { 12 if (results length > 0) { 13 var todo = results\[0]; 14 todo set("finished", true); 15 var date = new date(); 16 todo set("finisheddate", date); 17 todo save(null, { 18 usemasterkey true, 19 success function (object) { 20 response success(\[todo]); 21 }, 22 error function (object, error) { 23 response error("got an error " + error code + " " + error description); 24 } 25 }); 26 } else { 27 response error("todo not found to update"); 28 } 29 30 }, 31 error function (error) { 32 response error(" error " + error code + " " + error message); 33 } 34 }); 35 }); 7\) まとめ! これで終わりです。安全なtodoアプリを構築しました。再度言いますが、parseサーバーで安全なアプリを作るための鍵は、userクラスを除くすべてのクラスのクラスレベルの権限を無効にすることです。userクラスでは、createとgetを除くすべての権限を無効にします。また、すべてのユーザーのaclを設定して、ユーザーが自分のデータのみをgetできるようにしてください。そうすれば、すべてのインタラクションはクラウドコードを通じて行われ、request user、つまりcurrentuserを使用してフィルタリングされます。これで、parseサーバーとback4appの上に安全なシステムを構築できるようになりました。しかし、待ってください、背景ジョブやライブクエリはどうなりますか?確かに良い指摘ですので、それについては次の2つのボーナスセクションで説明します。 8\) ボーナスセクション 1\ バックグラウンドジョブ 時々、毎時、毎日、または毎週実行するバックグラウンドジョブを作成する必要があります。すべてのクラスレベルの権限を無効にしている場合、バックグラウンドジョブは正しく設定されていない限り、データベースをクエリすることができません。これは少し難しいので、ここにその例を含めたいと思います。この場合、1年以上未完了のtodoをデータベースでチェックし、自動的に完了としてマークするバックグラウンドジョブを作成します。ここでのポイントは、‘usemasterkey’を正しく使用することです。 クエリの thenプロミスの前に追加する必要があります。このテンプレートに従えば、安全なバックグラウンドジョブを簡単に書くことができるはずです。まず、データベース全体を反復処理したいクエリを書き始め、エラーがある場合はstatus errorを含め、完了することを確認するためにstatus successで終わらせます。バック4appのログを見て、実行中のバックグラウンドジョブが動作しているのを確認できます。 parse server 3 x 1 parse cloud job("markunfinishedtodosolderthan1yearasfinished", async(request) => { 2 let date = new date(); 3 let intyear = date getfullyear() 1; 4 let query = new parse query("todo"); 5 query equalto("finished", intyear); 6 query lessthan("createdat", date); 7 8 let todo = await query find({ usemasterkey true }); 9 for (let i = 0; i < results length; i++) { 10 let todo = results\[i]; 11 todo set("finished", true); 12 todo set("finisheddate", date); 13 try { 14 await todo save(null, { usemasterkey true}); 15 } catch (error){ 16 console log("getnewstore error " + error code + " " + error message); 17 } 18 } 19 return "migration completed successfully "; 20 }); parse server 2 x 1 parse cloud define("marktodoascompletedforuser", function(request, response) { 2 var currentuser = request user; 3 var todoid = request params todoid; 4 var query = new parse query("todo"); 5 query equalto("user", currentuser); 6 query equalto("objectid", todoid); 7 query equalto("finished", false); 8 query limit(1); 9 query find({ 10 usemasterkey true, 11 success function (results) { 12 if (results length > 0) { 13 var todo = results\[0]; 14 todo set("finished", true); 15 var date = new date(); 16 todo set("finisheddate", date); 17 todo save(null, { 18 usemasterkey true, 19 success function (object) { 20 response success(\[todo]); 21 }, 22 error function (object, error) { 23 response error("got an error " + error code + " " + error description); 24 } 25 }); 26 } else { 27 response error("todo not found to update"); 28 } 29 30 }, 31 error function (error) { 32 response error(" error " + error code + " " + error message); 33 } 34 }); 35 }); 2 ライブクエリ 時々、ライブチャットアプリのようなものにparseのライブクエリ機能を使用する必要があります。新しいメッセージがユーザーのために作成されたときにそれを見るためにライブクエリを使用したいでしょう。ライブクエリは基本的に、ライブ更新を取得するためにソケットを使用するparseの方法です。非常に便利ですが、find権限がオフになっているクラスでは機能しません。したがって、この場合、メッセージクラスのfind権限を再度オンにし、そのメッセージに対して直接aclを割り当てます。aclは、受信者だけがサーバーからメッセージを取得するためにfindを使用できるように設定する必要があります。次に、クライアントでpfライブクエリを実行し、ユーザーのメッセージを探すと、問題なく動作します。グループメッセージを扱っている場合は、少し異なります。aclに複数の人を割り当てることができますが、実際にはスケールしません。代わりに、より良い方法があります。aclをロール parse role に基づいて設定し、そのメッセージにアクセスしたいユーザーをそのparse roleに割り当てるだけです。そのグループのメッセージを読むのを止めたい場合は、そのロールから彼らを削除します。これは、すべてのメッセージのaclから彼らを削除するよりもはるかに簡単で、大規模なグループにスケールします。これが正しい方法です。このチュートリアルにはコードサンプルを残しませんが、これはこのチュートリアルには複雑すぎるため、次回のチュートリアルで説明するかもしれません。parseとback4appのセキュリティに関するこのチュートリアルを読んでいただきありがとうございます。質問があれば、遠慮なく 私に連絡してください 。喜んでお答えします。 ありがとう!ジョレン