<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                ??碼云GVP開源項目 12k star Uniapp+ElementUI 功能強大 支持多語言、二開方便! 廣告
                [TOC] ## [簡介](#簡介) 數據安全在應用開發的任何階段都應該被重視。因此本文檔我們詳細介紹了在選擇 LeanCloud 作為后端服務之后,如何使用 LeanCloud 提供的安全功能模塊為開發者的應用以及數據提供安全保障。 如果您尚未對權限管理以及 ACL 的進行過了解,請查看 權限管理以及 ACL 快速指南](acl_quick_start-js.html)。 ## [需求場景](#需求場景) 列舉一個場景: 假設我們要做一個極簡的論壇:用戶只能修改或者刪除自己發的帖子,其他用戶則只能查看。 ### [云引擎使用 ACL](#云引擎使用_ACL) 文檔中使用的?`AV.User.current()`?這個方法僅僅針對瀏覽器端有效,在云引擎中該接口無法使用。云引擎中獲取用戶信息,請參考?[云引擎指南 · 處理用戶登錄和登出](https://leancloud.cn/docs/leanengine_webhosting_guide-node.html#處理用戶登錄和登出)。 ## [基于用戶的權限管理](#基于用戶的權限管理) ### [單用戶權限設置](#單用戶權限設置) 以上需求在 LeanCloud 中實現的步驟如下: 1. 寫一篇帖子 2. 設置帖子的「讀」權限為所有人可讀。 3. 設置帖子的「寫」權限為作者可寫。 4. 保存帖子 實例代碼如下: ~~~ // 新建一個帖子對象 var Post = AV.Object.extend('Post'); var post = new Post(); post.set('title', '大家好,我是新人'); // 新建一個 ACL 實例 var acl = new AV.ACL(); acl.setPublicReadAccess(true); acl.setWriteAccess(AV.User.current(),true); // 將 ACL 實例賦予 Post 對象 post.setACL(acl); post.save().then(function() { // 保存成功 }).catch(function(error) { console.log(error); }); ~~~ 以上代碼產生的效果在?控制臺?>?存儲?>?Post 表?可以看到,這條記錄的 ACL 列上的值為: ~~~ {"*":{"read":true},"55b9df0400b0f6d7efaa8801":{"write":true}} ~~~ 此時,這種 ACL 值的表示:所有用戶均有「讀」權限,而?`objectId`?為?`55b9df0400b0f6d7efaa8801`?擁有「寫」權限,其他用戶不具備「寫」權限。 ### [多用戶權限設置](#多用戶權限設置) 假如需求增加為:帖子的作者允許某個特定的用戶可以修改帖子,除此之外的其他人不可修改。 實現步驟就是額外指定一個用戶,為他設置帖子的「寫」權限: 注意:開啟?`_User`?表的查詢權限才可以執行以下代碼 ~~~ // 創建一個針對 User 的查詢 var query = new AV.Query(AV.User); query.get('55098d49e4b02ad5826831f6').then(function(otherUser) { var post = new AV.Object('Post'); post.set('title', '大家好,我是新人'); // 新建一個 ACL 實例 var acl = new AV.ACL(); acl.setPublicReadAccess(true); acl.setWriteAccess(AV.User.current(), true); acl.setWriteAccess(otherUser, true); // 將 ACL 實例賦予 Post 對象 post.setACL(acl); // 保存到云端 return post.save(); }).then(function() { // 保存成功 }).catch(function(error) { // 錯誤信息 console.log(error); }); ~~~ 執行完畢上面的代碼,回到控制臺,可以看到,該條 Post 記錄里面的 ACL 列的內容如下: ~~~ {"*":{"read":true},"55b9df0400b0f6d7efaa8801":{"write":true},"55f1572460b2ce30e8b7afde":{"write":true}} ~~~ 從結果可以看出,該條 Post 已經允許 Id 為?`55b9df0400b0f6d7efaa8801`?以及?`55f1572460b2ce30e8b7afde`?兩個用戶(AVUser)可以修改,他們擁有?`write:ture`?的權限,也就是「寫」權限。 基于用戶的權限管理比較簡單直接,開發者理解起來成本較低。 ### [局限性](#局限性) 再進一步的場景: 論壇升級,需要一個特定的管理員(Administrator)來統一管理論壇的帖子,他可以修改帖子的內容,刪除不合適的帖子。 論壇升級之后,用戶發布帖子的步驟需要針對上一小節做如下調整: 1. 寫一篇帖子 2. 設置帖子的「讀」權限為所有人。 3. 設置帖子的「寫」權限為作者以及管理員 4. 保存帖子 我們可以設想一下,每當論壇產生一篇帖子,就得為管理員添加這篇帖子的「寫」權限。 假如做權限管理功能的時候都依賴基于用戶的權限管理,那么一旦產生變化就會發現這種實現方式的局限性。 比如新增了一個管理員,新的管理員需要針對目前論壇所有的帖子擁有管理員應有的權限,那么我們需要把數據庫現有的所有帖子循環一遍,為新的管理員增加「寫」權限。 假如論壇又一次升級了,付費會員享有特殊帖子的讀權限,那么我們需要在發布新帖子的時候,設置「讀」權限給部分人(付費會員)。這需要查詢所有付費會員并一一設置。 毫無疑問,這種實現方式是完全失控的,基于用戶的權限管理,在針對簡單的私密分享類的應用是可行的,但是一旦產生需求變更,這種實現方式是不被推薦的。 ## [基于角色的權限管理](#基于角色的權限管理) 管理員,會員,普通用戶這三種概念在程序設計中,被定義為「角色」。 我們可以看出,在列出的需求場景中,「權限」的作用是用來區分某一數據是否允許某種角色的用戶進行操作。 > 「權限」只和「角色」對應,而用戶也和「角色」對應,為用戶賦予「角色」,然后管理「角色」的權限,完成了權限與用戶的解耦。 > > > > + > > 因此我們來解釋 LeanCloud 中「權限」和「角色」的概念。 「權限」在 LeanCloud 服務端只存在兩種權限:讀、寫。 「角色」在 LeanCloud 服務端沒有限制,唯一要求的就是在一個應用內,角色的名字唯一即可,至于某一個「角色」在當前應用內對某條數據是否擁有讀寫的「權限」應該是有開發者的業務邏輯決定,而 LeanCloud 提供了一系列的接口幫助開發者快速實現基于角色的權限管理。 為了方便開發者實現基于角色的權限管理,LeanCloud 在 SDK 中集成了一套完整的 ACL (Access Control List) 系統。通俗的解釋就是為每一個數據創建一個訪問的白名單列表,只有在名單上的用戶(AVUser)或者具有某種角色(AVRole)的用戶才能被允許訪問。 為了更好地保證用戶數據安全性, LeanCloud 表中每一張都有一個 ACL 列。當然,LeanCloud 還提供了進一步的讀寫權限控制。 一個 User 必須擁有讀權限(或者屬于一個擁有讀權限的 Role)才可以獲取一個對象的數據,同時,一個 User 需要寫權限(或者屬于一個擁有寫權限的 Role)才可以更改或者刪除一個對象。下面列舉幾種常見的 ACL 使用范例。 ### [ACL 權限管理](#ACL_權限管理) #### [默認權限](#默認權限) 在沒有顯式指定的情況下,LeanCloud 中的每一個對象都會有一個默認的 ACL 值。這個值代表了所有的用戶對這個對象都是可讀可寫的。此時你可以在數據管理的表中 ACL 屬性中看到這樣的值: ~~~ {"*":{"read":true,"write":true}} ~~~ 在?[基于用戶的權限管理](#基于用戶的權限管理)?的章節中,已經在代碼里面演示了通過 ACL 來實現基于用戶的權限管理,那么基于角色的權限管理也是依賴 ACL 來實現的,只是在介紹詳細的操作之前需要介紹「角色」這個重要的概念。 ### [角色的權限管理](#角色的權限管理) #### [角色的創建](#角色的創建) 首先,我們來創建一個?`Administrator`?的角色。 這里有一個需要特別注意的地方,因為?`AVRole`?本身也是一個?`AVObject`,它自身也有 ACL 控制,并且它的權限控制應該更嚴謹,如同「論壇的管理員有權力任命版主,而版主無權任命管理員」一樣的道理,所以創建角色的時候需要顯式地設定該角色的 ACL,而角色是一種較為穩定的對象: ~~~ // 新建一個角色,并把為當前用戶賦予該角色 var roleAcl = new AV.ACL(); roleAcl.setPublicReadAccess(true); roleAcl.setPublicWriteAccess(false); // 當前用戶是該角色的創建者,因此具備對該角色的寫權限 roleAcl.setWriteAccess(AV.User.current(), true); //新建角色 var administratorRole = new AV.Role('Administrator', roleAcl); administratorRole.save().then(function(role) { // 創建成功 }).catch(function(error) { console.log(error); }); ~~~ 執行完畢之后,在控制臺可以查看?`_Role`?表里已經存在了一個?`Administrator`?的角色。 另外需要開發者注意的是:可以直接通過?控制臺?>?Post 表?>?其他?>?權限設置?直接設置權限。并且我們要強調的是: > ACL 可以精確到 Class,也可以精確到具體的每一個對象(表中的每一條記錄)。 > > > > + > > #### [為對象設置角色的訪問權限](#為對象設置角色的訪問權限) 我們現在已經創建了一個有效的角色,接下來為?`Post`?對象設置?`Administrator`?的訪問「可讀可寫」的權限,設置成功以后,任何具備?`Administrator`?角色的用戶都可以對?`Post`?對象進行「可讀可寫」的操作了: ~~~ // 新建一個帖子對象 var Post = AV.Object.extend('Post'); var post = new Post(); post.set('title', '大家好,我是新人'); // 新建一個角色,并把為當前用戶賦予該角色 var administratorRole = new AV.Role('Administrator'); var relation = administratorRole.getUsers(); //為當前用戶賦予該角色 administratorRole.getUsers().add(AV.User.current()); //角色保存成功 administratorRole.save().then(function(administratorRole) { // 新建一個 ACL 實例 var acl = new AV.ACL(); acl.setPublicReadAccess(true); acl.setRoleWriteAccess(administratorRole, true); // 將 ACL 實例賦予 Post 對象 post.setACL(acl); return post.save(); }).then(function(post) { // 保存成功 }).catch(function(error) { // 保存失敗 console.log(error); }); ~~~ #### [用戶角色的賦予和剝奪](#用戶角色的賦予和剝奪) 經過以上兩步,我們還差一個給具體的用戶設置角色的操作,這樣才可以完整地實現基于角色的權限管理。 在通常情況下,角色和用戶之間本是多對多的關系,比如需要把某一個用戶提升為某一個版塊的版主,亦或者某一個用戶被剝奪了版主的權力,以此類推,在應用的版本迭代中,用戶的角色都會存在增加或者減少的可能,因此,LeanCloud 也提供了為用戶賦予或者剝奪角色的方式。 注意:在代碼級別,為角色添加用戶?與?為用戶賦予角色?實現的代碼是一樣的。 此類操作的邏輯順序是: * 賦予角色:首先判斷該用戶是否已經被賦予該角色,如果已經存在則無需添加,如果不存在則為該用戶(AVUser)的?`roles`?屬性添加當前角色實例。 以下代碼演示為當前用戶添加?`Administrator`角色: ~~~ // 構建 AV.Role 的查詢 var administratorRole= //假設 administratorRole 是之前創建的 「Administrator」 角色; var roleQuery = new AV.Query(AV.Role); // 角色名稱等于 Administrator roleQuery.equalTo('name', 'Administrator'); // 檢查當前用戶是否已經擁有了 Administrator 角色 roleQuery.equalTo('users', AV.User.current()); roleQuery.find().then(function (results) { if (results.length > 0) { // 當前用戶已經具備了 Administrator 角色,因此不需要做任何操作 var administratorRole = results[0]; return administratorRole; } else { // 當前用戶不具備 Administrator,因此你需要把當前用戶添加到 Role 的 Users 中 var relation = administratorRole.getUsers(); relation.add(AV.User.current()); return administratorRole.save(); } }).then(function (administratorRole) { //此時 administratorRole 已經包含了當前用戶 }).catch(function (error) { // 輸出錯誤 console.log(error); }); ~~~ 角色賦予成功之后,基于角色的權限管理的功能才算完成。 另外,此處不得不提及的就是角色的剝奪: * 剝奪角色: 首先判斷該用戶是否已經被賦予該角色,如果未曾賦予則不做修改,如果已被賦予,則從對應的用戶(AVUser)的?`roles`?屬性當中把該角色刪除。 ~~~ // 構建 AV.Role 的查詢 var roleQuery = new AV.Query(AV.Role); roleQuery.equalTo('name', 'Moderator'); roleQuery.find().then(function(results) { // 如果角色存在 if (results.length > 0) { var moderatorRole = results[0]; roleQuery.equalTo('users', AV.User.current()); return roleQuery.find(); } }).then(function(userForRole) { //該角色存在,并且也擁有該角色 if (userForRole.length > 0) { // 剝奪角色 var relation= moderatorRole.getUsers(); relation.remove(AV.User.current()); return moderatorRole.save(); } }).then(function() { // 保存成功 }).catch(function(error) { // 輸出錯誤 console.log(error); }); ~~~ #### [角色的查詢](#角色的查詢) 除了在控制臺可以直接查看已有角色之外,通過代碼也可以直接查詢當前應用中已存在的角色。 注:`AVRole`?也繼承自?`AVObject`,因此熟悉了解?`AVQuery`?的開發者可以熟練的掌握關于角色查詢的各種方法。 ~~~ // 新建針對 Role 的查詢 var roleQuery = new AV.Query(AV.Role); // 查詢 name 等于 Administrator 的角色 roleQuery.equalTo('name', 'Administrator'); // 執行查詢 roleQuery.first().then(function(adminRole) { var userRelation = adminRole.relation('users'); return userRelation.query().find(); }).then(function (userList) { // userList 就是擁有該角色權限的所有用戶了。 var firstAdmin = userList[0]; }).catch(function(error) { console.log(error); }); ~~~ 查詢某一個用戶擁有哪些角色: ~~~ //第一種是通過 AV.User 的內置接口: user.getRoles().then(function(roles){ // roles 是一個 AV.Role 數組,這些 AV.Role 表示 user 擁有的角色 }); // 第二種是通過查詢: // 新建角色查詢 var roleQuery = new AV.Query(AV.Role); // 查詢當前用戶擁有的角色 roleQuery.equalTo('users', AV.User.current()); roleQuery.find().then(function(roles) { // roles 是一個 AV.Role 數組,這些 AV.Role 表示當前用戶所擁有的角色 }, function (error) { }); ~~~ 查詢哪些用戶都被賦予?`Moderator`?角色: ~~~ var roleQuery = new AV.Query(AV.Role); roleQuery.get('55f1572460b2ce30e8b7afde').then(function(role) { //獲取 Relation 實例 var userRelation= role.getUsers(); // 獲取查詢實例 var query = userRelation.query(); return query.find(); }).then(function(results) { // results 就是擁有 role 角色的所有用戶了 }).catch(function(error) { console.log(error); }); ~~~ #### [角色的從屬關系](#角色的從屬關系) 角色從屬關系是為了實現不同角色的權限共享以及權限隔離。 權限共享很好理解,比如管理員擁有論壇所有板塊的管理權限,而版主只擁有單一板塊的管理權限,如果開發一個版主使用的新功能,都要同樣的為管理員設置該項功能權限,代碼就會冗余,因此,我們通俗的理解是:管理員也是版主,只是他是所有板塊的版主。因此,管理員在角色從屬的關系上是屬于版主的,只不過 TA 是特殊的版主。 ~~~ // 建立版主和論壇管理員之間的從屬關系 var administratorRole = new AV.Role('Administrator'); var administratorRole.save().then(function(administratorRole) { //新建版主角色 var moderatorRole = new AV.Role('Moderator'); // 將 Administrator 作為 moderatorRole 子角色 moderatorRole.getRoles().add(administratorRole); return moderatorRole.save(); }).then(function (role) { chai.assert.isNotNull(role.id); done(); }).catch(function(error) { console.log(error); }); ~~~ 權限隔離也就是兩個角色不存在從屬關系,但是某些權限又是共享的,此時不妨設計一個中間角色,讓前面兩個角色從屬于中間角色,這樣在邏輯上可以很快梳理,其實本質上還是使用了角色的從屬關系。 比如,版主 A 是攝影器材板塊的版主,而版主 B 是手機平板板塊的版主,現在新開放了一個電子數碼版塊,而需求規定 A 和 B 都同時具備管理電子數碼板塊的權限,但是 A 不具備管理手機平板版塊的權限,反之亦然,那么就需要設置一個電子數碼板塊的版主角色(中間角色),同時讓 A 和 B 擁有該角色即可。 ~~~ //新建攝影器材版主角色 var photographicRole = new AV.Role('Photographic'); //新建手機平板版主角色 var mobileRole=new AV.Role('Mobile'); //新建電子數碼版主角色 var digitalRole=new AV.Role('Digital'); AV.Promise.all([ // 先行保存 photographicRole 和 mobileRole photographicRole.save(), mobileRole.save(), ]).then(function([r1, r2]) { // 將 photographicRole 和 mobileRole 設為 digitalRole 一個子角色 digitalRole.getRoles().add(photographicRole); digitalRole.getRoles().add(mobileRole); digitalRole.save(); // 新建一個帖子對象 var Post = AV.Object.extend('Post'); // 新建攝影器材板塊的帖子 var photographicPost = new Post(); photographicPost.set('title', '我是攝影器材板塊的帖子!'); // 新建手機平板板塊的帖子 var mobilePost = new Post(); mobilePost.set('title', '我是手機平板板塊的帖子!'); // 新建電子數碼板塊的帖子 var digitalPost = new Post(); digitalPost.set('title', '我是電子數碼板塊的帖子!'); // 新建一個攝影器材版主可寫的 ACL 實例 var photographicACL = new AV.ACL(); photographicACL.setPublicReadAccess(true); photographicACL.setRoleWriteAccess(photographicRole,true); // 新建一個手機平板版主可寫的 ACL 實例 var mobileACL = new AV.ACL(); mobileACL.setPublicReadAccess(true); mobileACL.setRoleWriteAccess(mobileRole,true); // 新建一個手機平板版主可寫的 ACL 實例 var digitalACL = new AV.ACL(); digitalACL.setPublicReadAccess(true); digitalACL.setRoleWriteAccess(digitalRole,true); // photographicPost 只有 photographicRole 可以讀寫 // mobilePost 只有 mobileRole 可以讀寫 // 而 photographicRole,mobileRole,digitalRole 均可以對 digitalPost 進行讀寫 photographicPost.setACL(photographicACL); mobilePost.setACL(mobileACL); digitalPost.setACL(digitalACL); return AV.Promise.all([ photographicPost.save(), mobilePost.save(), digitalPost.save(), ]); }).then(function([r1, r2, r3]) { // 保存成功 }, function(errors) { // 保存失敗 });; ~~~ ### [權限的分級](#權限的分級) 在日常生活中,我們也遇到過權限分級的問題,例如新的系統又一次升級,引入了超級管理員的概念,這個超級管理員可以對系統里面任何的對象進行「讀寫操作」,按照前文的做法,需要用代碼實現如下步驟: 1. 創建超級管理員角色 2. 遍歷云端現有的帖子,為所有對象添加超級管理員的「ACL 讀寫權限」 3. 保存數據 開發者一旦面對這種邏輯重復的代碼,一般都會想到:有沒有一個快捷的操作可以一次性為某一個角色添加整個 Class 添加權限? 當然,LeanCloud 也已經提供了便捷的可視化的操作。打開?控制臺?>?存儲?>?Post?>?其他?>?權限設置,如下圖所示: ![acl_in_console](http://ac-lhzo7z96.clouddn.com/1442281757400) * 在這里你可以設置某一個角色對?`Post`?的操作權限:選擇?指定用戶,在指定角色中輸入?`superAdmin`,并且點擊添加即可。 如此設置,無需書寫代碼,在項目迭代過程中有角色加入都可以用這種便捷的方式進行操作。 權限設置的參數以及操作解釋如下: | 參數名 | 含義 | | --- | --- | | add_fields | 添加新字段到 class | | create | 保存一個從未創建過的新對象 | | delete | 刪除一個對象 | | find | 發起一次對象列表查詢 | | get | 通過 objectId 獲取對象 | | update | 保存一個已經存在并且被修改的對象 | | 權限對象名 | 含義 | | --- | --- | | 所有用戶 | 任意用戶均有權限 | | 登錄用戶 | 用戶登錄之后,具有權限 | | 指定用戶 | 可以指定具體的用戶(`AVUser`)也可以指定具體的角色(`AVRole`) | ## [超級權限](#超級權限) ACL 可以滿足常見的需求,但是?`_User`?表比較特殊,它會忽略 ACL 的設置,表現為:任何用戶都無法修改其他用戶的屬性,比如當前登錄的用戶是 A,而他想通過請求去修改 B 用戶的用戶名,密碼或者其他自定義屬性,是不會生效的。 但是有時一些應用的需求較為特殊,比如,論壇的管理員可以修改某些用戶的昵稱,性別(假設昵稱和性別是存儲在?`_User`?的?`gender`,`age`?的字段上),此時通過設置管理員擁有該用戶的 ACL 寫的權限是無法實現預想效果的。因此,我們提供了一種方式去提高操作的權限,在 SDK 中的實現方式是在初始化的時候,增加一個 Master Key 的字段作為提高權限的接口。Master Key 可以在?`控制臺`?->?`設置`?->?`應用 Key`?中獲取。 在 Node.js 運行時中可以使用如下代碼初始化 SDK: ~~~ AV.init({ appId: APP_ID, appKey: APP_KEY, masterKey: MASTER_KEY, }) AV.Cloud.useMasterKey(); ~~~ ## [最佳實踐](#最佳實踐) 本章節的目的是介紹如何在?[云引擎](https://leancloud.cn/docs/acl_guide_leanengine.html)?里面使用 ACL 。 我們先來探索一個需求:某個應用它擁有眾多客戶端,iOS、Andorid、Windows 等,還有 Web 版,未來可能還會有手環,手表客戶端,那么關于 ACL 的代碼會遍布在所有客戶端,那么開發者就會需要不斷的升級和維護邏輯十分類似的客戶端代碼,到了這一步,我們更推薦,開發者在服務端定義一段 ACL 的邏輯,統一處理 ACL 權限分配的問題。 【總結】假如應用的平臺比較固定,那么就可以考慮采取本文前面所介紹的客戶端代碼實現 ACL 代碼。如果應用的平臺比較多,多平臺多客戶端就推薦使用?[云引擎 Hook 函數使用 ACL](https://leancloud.cn/docs/acl_guide_leanengine.html)。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看