2018/04/26

SampleCMS 網頁內容發佈系統元件說明:自訂帳號授權結果

接續前一篇 元件提供的功能與使用方式 ,
本篇說明「網站架構管理」的權限判斷規則以及實作方式。

下圖為「網站架構管理」的權限判斷規則活動圖,

下列項目為活動圖中星號 * 數字的對應說明,
  1. 指定的網頁節點若為根節點,則延用帳號與權限元件已暫存的授權設定值。
     
  2. 若登入者身分為管理者,則延用帳號與權限元件已暫存的授權設定值(系統允許管理者使用任何功能)。
     
  3. 檢查指定的網頁節點是否有被建立為作業選項。
     
  4. 若指定的網頁節點有被建立為作業選項,檢查登入者身分與這個作業選項的授權設定值,若登入者身分被授權 CanRead = true(可閱讀這個作業選項),取回這個授權設定值並且回傳給帳號與權限元件。
     
  5. 續項目 4 ,若無法取得登入者身分與這個作業選項的授權設定值,或者沒被授權 CanRead = true(可閱讀這個作業選項),改為檢查上一層的網頁節點是否有被建立為作業選項,繼續使用項目 4 的規則,直到上一層的網頁節點是根節點為止。
     
  6. 續項目 5,若最後上一層的網頁節點是根節點,則延用帳號與權限元件已暫存的授權設定值。
     
  7. (本項目不在活動圖中)
    若最後找出的授權設定值不是從原本指定的網頁節點對應的作業選項取得,而是從其他的任一上層網頁節點對應的作業選項取得(包括根節點),則必須通知帳號與權限元件將 isTopPageOfOperation 從 true 改為 false,從「使用作業選項的授權值」改為「使用作業選項的子項目授權值」。


以下為網頁內容發佈元件 ArticlePublisherLogic 實作介面 ICustomEmployeeAuthorizationResult 的相關程式碼,
    public class ArticlePublisherLogic : ICustomEmployeeAuthorizationResult
    {
        // ...略...

        #region ICustomEmployeeAuthorizationResult

        public EmployeeAuthorizationsWithOwnerInfoOfDataExamined InitialAuthorizationResult(bool isTopPageOfOperation, EmployeeAuthorizations authorizations)
        {
            EmployeeAuthorizationsWithOwnerInfoOfDataExamined authAndOwner = new EmployeeAuthorizationsWithOwnerInfoOfDataExamined(authorizations);

            bool gotOpAuth = false;
            Guid initArticleId= authCondition.GetArticleId();
            Guid curArticleId = initArticleId;
            Guid? curParentId = null;
            int curArticleLevelNo;
            string linkUrl = "";
            bool isRoot = false;
            bool isRoleAdmin = authCondition.IsInRole("admin");

            // get article info
            DataSet dsArticle = GetArticleDataForBackend(curArticleId);

            if (dsArticle != null && dsArticle.Tables[0].Rows.Count > 0)
            {
                DataRow drArticle = dsArticle.Tables[0].Rows[0];

                if (Convert.IsDBNull(drArticle["ParentId"]))
                {
                    isRoot = true;
                }
                else
                {
                    curParentId = (Guid)drArticle["ParentId"];
                }

                curArticleLevelNo = Convert.ToInt32(drArticle["ArticleLevelNo"]);

                authAndOwner.OwnerAccountOfDataExamined = drArticle.ToSafeStr("PostAccount");
                authAndOwner.OwnerDeptIdOfDataExamined = Convert.ToInt32(drArticle["PostDeptId"]);
            }

            if (isRoot || isRoleAdmin)
            {
                return authAndOwner;
            }

            do
            {
                DataSet dsOpInfo = null;
                IDataAccessCommand cmd = DataAccessCommandFactory.GetDataAccessCommand(DBs.MainDB);

                if (curParentId.HasValue)
                {
                    // get opId by LinkUrl
                    linkUrl = string.Format("Article-Node.aspx?artid={0}", curArticleId);

                    Common.DataAccess.EmployeeAuthority.spOperations_GetOpInfoByLinkUrl opCmdInfo = new DataAccess.EmployeeAuthority.spOperations_GetOpInfoByLinkUrl()
                    {
                        LinkUrl = linkUrl
                    };
                    dsOpInfo = cmd.ExecuteDataset(opCmdInfo);
                }
                else
                {
                    // get opId of root
                    Common.DataAccess.EmployeeAuthority.spOperations_GetOpInfoByCommonClass opCmdInfo = new DataAccess.EmployeeAuthority.spOperations_GetOpInfoByCommonClass()
                    {
                        CommonClass = "ArticleCommonOfBackend"
                    };
                    dsOpInfo = cmd.ExecuteDataset(opCmdInfo);
                }

                if (dsOpInfo != null && dsOpInfo.Tables[0].Rows.Count > 0)
                {
                    DataRow drOpInfo = dsOpInfo.Tables[0].Rows[0];
                    int opId = Convert.ToInt32(drOpInfo["OpId"]);

                    // get authorizations

                    Common.DataAccess.EmployeeAuthority.spEmployeeRoleOperationsDesc_GetDataOfOp cmdInfo = new DataAccess.EmployeeAuthority.spEmployeeRoleOperationsDesc_GetDataOfOp()
                    {
                        OpId = opId,
                        RoleName = authCondition.GetRoleName()
                    };
                    DataSet dsRoleOp = cmd.ExecuteDataset(cmdInfo);

                    if (dsRoleOp != null && dsRoleOp.Tables[0].Rows.Count > 0)
                    {
                        //檢查權限, 只允許 CanRead=true

                        DataRow drRoleOp = dsRoleOp.Tables[0].Rows[0];
                        bool canRead = drRoleOp.To<bool>("CanRead", false);

                        if (canRead)
                        {
                            authAndOwner = (EmployeeAuthorizationsWithOwnerInfoOfDataExamined)LoadRoleAuthorizationsFromDataSet(authAndOwner, dsRoleOp, isRoleAdmin);
                            gotOpAuth = true;
                        }
                    }
                }

                if (!gotOpAuth)
                {
                    if (!curParentId.HasValue)
                    {
                        // this is root
                        break;
                    }

                    // get parent info
                    DataSet dsParent = GetArticleDataForBackend(curParentId.Value);

                    if (dsParent == null || dsParent.Tables[0].Rows.Count == 0)
                    {
                        logger.Error(string.Format("can not get article data of {0}", curParentId.Value));
                        break;
                    }

                    // move to parent level
                    DataRow drParent = dsParent.Tables[0].Rows[0];
                    curArticleId = curParentId.Value;

                    if (Convert.IsDBNull(drParent["ParentId"]))
                    {
                        curParentId = null;
                    }
                    else
                    {
                        curParentId = (Guid)drParent["ParentId"];
                    }

                    curArticleLevelNo = Convert.ToInt32(drParent["ArticleLevelNo"]);
                }
            } while (!gotOpAuth);

            if (isTopPageOfOperation && curArticleId != initArticleId)
            {
                // notice that the authorizations belong to parent, so this page is not top page of operation.
                authAndOwner.IsTopPageOfOperation = false;
                authAndOwner.IsTopPageOfOperationChanged = true;
            }

            return authAndOwner;
        }

        #endregion
    }

Line 9: 預設要回傳的授權結果 EmployeeAuthorizationsWithOwnerInfoOfDataExamined 物件,預設值同傳入的 EmployeeAuthorizations 物件。

Line 12: 透過介面 IAuthenticationConditionProvider 取得展示層網頁程式指定的網頁代碼 articleId。

Line 18: 透過介面 IAuthenticationConditionProvider 確認登入者身分是否為管理者。

Line 21~40: 從資料庫取得網頁代碼對應的網頁資料,從中取得上層網頁代碼、本節點是否為根節點、資料擁有者資訊。

Line 42, 44: 若本節點為根節點或者登入者身分為管理者,將傳入的授權設定值原封不動回傳。(對應上述規則項目 1, 2)

Line 47~134: 從指定的網頁節點開始找相關的授權設定,若無符合的就再往上一層網頁節點找,直到有符合的資料或者到根節點為止。(對應上述規則項目 3, 4, 5, 6)

Line 52~62: 以字串 "Article-Node.aspx?artid=網頁代碼" 到資料庫找出對應的作業選項資料。
(對應上述規則項目 3)
(字串規則對應 操作手冊 - 「4.6. 使用情境:將「網站架構管理」指定網頁建立為作業選項,並且設定權限」新增作業選項資料時,輸入在欄位「超連結網址」的值。


Line 63~71: 若本節點為根節點,取得根節點網頁資料。但是因為 Line 42, 44 的關係,這一段應該不會被執行到。

Line 73~100: 從資料庫取回指定登入者身分與作業選項關聯的授權設定值,並且檢查可否閱讀這個作業選項, CanRead = true 才算是符合的資料,記下這份授權設定值做為回傳結果。(對應上述規則項目 4)

Line 102~133: 若指定的網頁節點找不到符合的授權設定,就從資料庫取回上一層網頁資料繼續比對。(對應上述規則項目 5)

Line 104, 107: 若最後上一層的網頁節點是根節點就不需要繼續找下去,後續會將傳入的授權設定值原封不動回傳。(對應上述規則項目 6)

Line 136~141: 若最後找出的授權設定值不是從原本指定的網頁節點對應的作業選項取得,而是從其他的任一上層網頁節點對應的作業選項取得(包括根節點),則必須通知帳號與權限元件將 isTopPageOfOperation 從 true 改為 false,從「使用作業選項的授權值」改為「使用作業選項的子項目授權值」。(對應上述規則項目 7)




沒有留言:

張貼留言