Security & Privacy
Parse와 Back4App 통한 안전한 앱 개발 기술 가이드
21 분
parse를 사용하여 안전한 앱 만드는 방법 소개 안녕하세요 back4app 커뮤니티! unhandled content type 이것은 startup soul http //startup soul com/ 의 joren winge가 제공하는 게스트 튜토리얼입니다 우리는 스타트업이 제품을 빠르게 구축하고 출시할 수 있도록 돕습니다 back4app의 친구들이 여러분에게 back4app 위에 안전한 앱을 만드는 방법을 보여달라고 요청했습니다 이번 포스트에서는 back4app에서 안전한 할 일(to do) 앱을 만드는 단계를 안내해 드리겠습니다 보안은 중요합니다 만약 여러분의 앱이 성공한다면, 앱의 데이터가 안전하고 시스템이 해킹되지 않도록 해야 합니다 parse의 보안 기능 먼저 보안의 첫 번째 수준인 acl(액세스 제어 목록)에 대해 이야기해 보겠습니다 acl은 기본적으로 객체를 생성할 때 설정하는 규칙입니다 예를 들어, 할 일 항목을 생성할 때, 생성 시점에 해당 항목을 누가 읽을 수 있고, 누가 쓸 수 있는지를 설정할 수 있습니다 특정 사용자에게 해당 항목을 읽거나 쓸 수 있는 권한을 부여하거나, 둘 중 하나를 공개로 설정하여 누구나 접근할 수 있도록 할 수 있습니다 하지만 acl은 항상 작동하지는 않습니다 때때로 단순한 acl 대신 더 정교한 논리가 필요할 수 있는 경우가 있습니다 때로는 acl과 같은 절대적인 기준 대신 조건부로 객체에 대한 접근 권한을 부여해야 할 수도 있습니다 그래서 acl 사용을 건너뛰겠습니다 acl은 너무 경직되어 있고 동시에 데이터에 대한 접근을 너무 많이 허용합니다 그래서 이제 back4app과 parse server에서 안전한 앱을 만드는 비밀을 알려드리겠습니다 준비되셨나요? 클래스 수준 권한! 네, 우리는 데이터베이스의 각 테이블에 대해 클래스 수준 권한을 설정할 것입니다 우리가 설정할 권한 수준은 전혀 권한이 없습니다 우리는 모든 테이블을 잠가서 누구에게도 읽기 또는 쓰기 접근이 허용되지 않도록 할 것입니다! 극단적으로 들리겠지만, 이것이 안전한 앱을 만드는 첫 번째 단계입니다 우리가 허용할 유일한 권한은 사용자 테이블에 대한 것으로, 새로운 사용자 객체를 생성하고 사용자가 자신의 데이터를 볼 수 있도록 하는 것입니다 이는 현재 사용자를 새로 고치는 데 필요합니다 우리는 acl을 사용하여 사용자가 다른 사용자의 데이터를 볼 수 없도록 보호할 것입니다 이것이 우리가 acl을 사용할 한 번의 기회이므로, 그들이 전혀 쓸모없지는 않다고 생각합니다 그들은 있으면 좋지만 모든 것을 그들에게 의존하지 마세요 하지만 데이터를 어떻게 접근할 수 있냐고요? 좋은 질문입니다, 당신이 그것에 대해 생각하고 있어서 기쁩니다! 클라이언트가 데이터를 제어된 방식으로 접근할 수 있도록 하는 비결은 클라이언트와 데이터베이스 간의 모든 상호작용을 클라우드 코드 함수로 필터링하는 것입니다 네, 앱으로 무언가를 할 때마다 이제는 사용자 정의 클라우드 코드 함수를 통해 이루어질 것입니다 더 이상 클라이언트 기반 pfqueries는 없습니다 사실상 회원가입 기능, 로그인 기능, 비밀번호 찾기 기능, 로그아웃 기능을 제외하고는 전체 클라이언트 기반 parse sdk를 사용하지 않게 됩니다 이 기능들에 대해서는 여전히 네이티브 클라이언트 sdk를 사용할 것입니다 그냥 더 쉽습니다 클라우드 코드를 작성해본 적이 있나요? 아니라고요? 글쎄요, 꽤 쉽습니다 그냥 자바스크립트이고 parse 자바스크립트 sdk를 사용하지만 내부적으로는 자신의 앱 서버에서 실행됩니다 사실, parse 서버는 node js를 기반으로 하므로 express로 라우트를 작성하는 것과 매우 유사하지만, 쿼리 언어가 이미 설치되어 있고 클라우드 코드 함수가 전체 node js express 앱보다 훨씬 쉽게 작성할 수 있기 때문에 더 쉽습니다 그래서 우리가 할 일은 이렇습니다 제가 이미 만든 ios 할 일 앱을 사용할 것입니다 제가 어떻게 만들었는지 보여드리지 않을 것입니다 대신, 클라우드 코드를 작성하고 데이터베이스를 보호하는 데 집중할 것입니다 할 일 앱은 당신이 자신의 할 일만 접근할 수 있고, 자신의 할 일만 작성할 수 있는 안전한 앱이 될 것입니다 데이터는 악의적인 불법 클라이언트로부터 안전하게 서버에 보호될 것입니다 또한 안전한 parse 백그라운드 작업을 작성하는 방법도 보여드릴 것입니다 기본적으로 크론 작업과 같은 것입니다 그래서 자동화된 서비스가 일정에 따라 데이터를 조작할 수 있습니다 복잡하게 들리지만 그렇지 않습니다 자동화된 일정에 따라 원하는 모든 것을 하는 작은 서버 로봇을 상상해 보세요 멋지지 않나요? 자, 그럼 시작해봅시다!!!!!! back4app 안전한 할 일 앱 설정하기 1\) back4app에서 앱 만들기 back4app에서 새 앱을 만드세요 앱 이름을 ‘secure todo app’으로 설정하세요 참고 new parse app 튜토리얼 을 따라 back4app에서 앱을 만드는 방법을 배우세요 앱의 core settings 페이지로 들어가서 edit app details를 클릭하세요 ‘allow client class creation’이라는 체크박스를 비활성화하여 클라이언트 클래스 생성을 비활성화하고 저장하세요 규칙으로서 클라이언트가 할 수 있는 것을 제한하고자 합니다 2\) 사용자 클래스에 대한 클래스 수준 보안 권한 설정 다음으로 사용자 클래스에 대한 권한을 설정하겠습니다 back4app 데이터베이스 대시보드로 이동하여 사용자 클래스를 클릭합니다 그런 다음 보안 탭을 클릭하고 오른쪽 상단의 기어 아이콘을 클릭합니다 simple/advanced라는 메뉴가 표시됩니다 슬라이더를 advanced로 전환합니다 그러면 이 클래스에 대한 전체 클래스 수준 권한이 표시됩니다 find 체크박스를 비활성화합니다 update 및 delete 체크박스를 비활성화합니다 마지막으로 add field 체크박스를 비활성화합니다 그런 다음 저장을 클릭합니다 보안 설정은 다음과 같아야 합니다 3\) todo 클래스를 생성합니다 클래스를 생성하고 이름을 todo로 지정합니다 클래스 유형을 사용자 정의로 설정합니다 4\) todo 클래스에 대한 클래스 수준 보안 권한을 설정합니다 다음으로 todo 클래스에 대한 권한을 설정하겠습니다 back4app 데이터베이스 대시보드로 이동하여 todo 클래스를 클릭합니다 그런 다음 보안 탭을 클릭하고 오른쪽 상단의 기어 아이콘을 클릭합니다 simple/advanced라는 메뉴가 표시됩니다 슬라이더를 advanced로 전환합니다 그러면 이 클래스에 대한 전체 클래스 수준 권한이 표시됩니다 모든 것을 비활성화한 후 저장을 클릭합니다 보안 설정은 다음과 같아야 합니다 5\) todo 클래스에 열을 추가해 보겠습니다 먼저 todo 클래스를 user 클래스에 연결해 보겠습니다 2개의 열을 추가하여 그렇게 할 것입니다 첫 번째 열은 'user'라고 불리며 사용자 클래스를 가리키는 포인터가 될 것입니다 다음으로, 그것을 생성한 사용자의 객체 id를 위한 열을 만들어 보겠습니다 문자열 유형이 될 것이며 'userobjectid'라고 불릴 것입니다 다음으로, 실제 todo 정보를 저장할 열을 만들어 보겠습니다 이것도 문자열이 될 것이며 'tododescription'이라고 부를 것입니다 todo의 상태를 저장할 부울을 만들어 보겠습니다 'finished'라고 부르겠습니다 마지막으로, todo를 완료한 날짜를 저장할 열을 하나 더 추가하겠습니다 'finisheddate'라고 부르고 날짜 유형으로 설정하겠습니다 당신의 todo 클래스는 다음과 같아야 합니다 6\) 클라이언트를 살펴보겠습니다 클라이언트는 꽤 기본적인 할 일 앱입니다 로그인, 새 사용자 생성 및 비밀번호 재설정을 위해 내장된 파서 기능을 사용합니다 그 외에는 모든 것이 클라우드 코드 기반이며 안전합니다 사용자의 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 이 클라우드 코드는 앱을 안전하게 만드는 두 가지 주요 기능인 request user와 masterkey를 사용합니다 request user는 클라우드 코드 호출을 하는 사용자를 접근할 수 있게 해주며, 해당 사용자의 접근을 제한할 수 있게 해줍니다 이 경우, 우리는 사용자의 acl을 설정하여 현재 사용자만 읽을 수 있도록 제한하고 있습니다 이렇게 하면 오직 사용자만 자신의 정보를 읽을 수 있습니다 클래스 수준의 권한은 현재 사용자조차도 쓰기 접근을 방지합니다 이렇게 하면 사용자는 자신의 정보를 수정할 수 없습니다 그들은 클라우드 코드를 통해 자신의 사용자에 대한 것만 변경할 수 있습니다 사용자가 처음 가입할 때 잘못된 정보를 가져오는 것이 가능하지만, 새로운 사용자가 생성된 후 사용자의 정보를 확인하는 클라우드 코드 함수를 작성하는 것을 추천합니다 새로운 사용자를 생성하기 위한 내장된 파스 함수는 정말 유용하므로 괜찮은 절충안이라고 생각하지만, 사용자가 가입한 직후 클라우드 코드를 통해 사용자에 대한 기본값을 항상 설정할 수 있습니다 클라우드 코드에 여러 가지 안전 장치를 작성하고, 사용자가 처음 생성될 때 가져온 악의적인 사용자 정보를 감지하기 위해 백그라운드 작업을 사용하여 자동으로 지속적으로 실행할 수 있습니다 정말 안전하게 하고 싶다면, 회원 상태나 결제 정보와 같은 민감한 정보를 사용자 테이블과 별도의 테이블에 저장할 수 있습니다 그렇게 하면 사용자가 사용자 생성 시 민감한 정보를 위조할 수 없습니다 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\ 다음으로 서버에서 생성한 할 일을 가져오는 방법을 살펴보겠습니다 클라이언트에서 todocontroller swift로 가서 gettodosfordate 함수를 찾으세요 이 함수는 할 일을 가져올 때 호출됩니다 이 함수는 날짜를 매개변수로 받아 해당 날짜 이전에 생성된 할 일 목록을 내림차순으로 가져오는 데 사용됩니다 날짜를 사용하는 것은 건너뛰기를 사용하지 않는 지연 로딩 쿼리를 작성하는 좋은 방법입니다 큰 데이터 세트에서는 건너뛰기가 실패할 수 있습니다 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\ 이제 시작 날짜를 기준으로 데이터베이스에서 할 일을 검색하는 클라우드 코드 함수를 작성해 보겠습니다 우리는 매개변수 날짜 이전에 생성된 할 일을 쿼리하므로 'query lessthan'을 사용합니다 날짜는 기본적으로 미래로 갈수록 커지는 숫자이기 때문입니다 여기에는 약간의 복잡한 코드도 포함되어 있습니다 할 일을 생성한 사용자 객체를 포함하고 있지만 해당 사용자에 대한 민감한 정보를 다른 사용자와 공유하고 싶지 않다면 json 응답에서 이를 제거해야 합니다 그래서 우리는 할 일에서 사용자 객체를 꺼내고, json에서 이메일과 사용자 이름을 제거한 다음 다시 할 일에 넣는 for 루프를 사용합니다 이는 반환할 필드를 제어할 수 없는 상황에서 api 호출에서 민감한 데이터를 제거하는 데 유용합니다 포함된 사용자 객체와 같은 경우입니다 이 경우에는 이 함수가 사용자가 생성한 할 일만 반환하므로 실제로 필요하지 않습니다 우리는 currentuser를 다시 사용하여 요청에 첨부된 currentuser가 생성한 할 일만 쿼리합니다 결과는 내림차순으로 반환되어 최신 할 일이 먼저 나타납니다 다른 배치의 할 일을 지연 로드해야 할 때는 마지막 할 일의 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\ 할 일을 완료로 표시하려면 생성한 할 일 중 하나에서 ‘완료로 표시’ 버튼을 누르기만 하면 됩니다 그러면 선택한 할 일을 매개변수로 사용하는 todocontroller swift의 ‘marktodosascompletedfor’라는 메서드가 실행됩니다 이 메서드는 todo objectid를 매개변수로 서버에 전송한 다음 업데이트된 할 일을 결과로 반환합니다 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\ 이제 이 할 일을 업데이트하기 위한 클라우드 코드를 작성하겠습니다 이는 objectid를 기반으로 업데이트할 할 일을 찾지만, 쿼리를 수행하는 사용자가 만든 할 일인지 확인하기 위해 currentuser도 사용합니다 이렇게 하면 사용자가 만든 할 일만 볼 수 있으므로 안전합니다 서버가 할 일을 찾은 후 계속 검색하지 않도록 결과 수를 1로 제한합니다 objectid를 기반으로 객체를 찾기 위한 또 다른 방법이 있지만, objectid와 연결된 객체를 찾지 못하면 이상한 결과를 반환할 수 있기 때문에 사용하고 싶지 않습니다 또한 객체가 업데이트될 때 현재 날짜로 'finisheddate'를 설정하고 있습니다 이 함수에 의해만 finisheddate가 설정되므로 finisheddate가 안전하고 위조되거나 변경될 수 없도록 했습니다 또한 'query equalto( 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\) 마무리! 그게 전부입니다 안전한 할 일 앱을 만들었습니다 다시 말하지만, 파스 서버에서 안전한 앱을 만드는 핵심은 사용자 클래스 외의 모든 클래스에 대한 클래스 수준 권한을 비활성화하는 것입니다 사용자 클래스에서는 create와 get을 제외한 모든 권한을 비활성화합니다 또한 모든 사용자의 acl을 설정하여 사용자가 자신의 데이터만 get할 수 있도록 해야 합니다 그러면 모든 상호작용은 클라우드 코드를 통해 이루어지고 request user, 즉 currentuser를 사용하여 필터링됩니다 자, 이제 parse 서버와 back4app 위에 안전한 시스템을 구축할 수 있습니다 하지만 기다리세요? 백그라운드 작업과 실시간 쿼리는 어떻게 되나요? 좋은 지적입니다 그래서 다음 두 개의 보너스 섹션에서 그것을 다루겠습니다 8\) 보너스 섹션 1\ 백그라운드 작업 때때로 매시간, 매일 또는 매주 실행되는 백그라운드 작업을 생성해야 할 필요가 있습니다 모든 클래스 수준 권한이 꺼져 있는 상태에서 실행하는 경우, 백그라운드 작업은 올바르게 설정되지 않으면 데이터베이스를 쿼리할 수 없습니다 이것은 다소 까다롭기 때문에 여기에서 예제를 포함하고자 합니다 이 경우, 1년 이상 된 미완료 할 일을 데이터베이스에서 확인하고 자동으로 완료로 표시하는 백그라운드 작업을 생성할 것입니다 여기서의 요령은 'usemasterkey'를 올바르게 사용하는 것입니다 쿼리의 then 약속 전에 추가해야 합니다 이 템플릿을 따르기만 하면 안전한 백그라운드 작업을 쉽게 작성할 수 있습니다 항상 전체 데이터베이스를 반복할 쿼리를 작성하는 것으로 시작하고, 오류가 발생하면 status error를 포함하고 완료되도록 status success로 끝내야 합니다 back4app에서 로그를 확인하여 백그라운드 작업이 실행되는 것을 볼 수 있습니다 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의 보안에 관한 이 튜토리얼을 읽어 주셔서 감사합니다 질문이 있으시면 언제든지 연락해 주세요 그리고 기꺼이 답변해 드리겠습니다 감사합니다! 요렌