主頁 > 企業開發 > 權限控制在數堆疊產品的實踐

權限控制在數堆疊產品的實踐

2023-01-13 06:53:28 企業開發

我們是袋鼠云數堆疊 UED 團隊,致力于打造優秀的一站式資料中臺產品,我們始終保持工匠精神,探索前端道路,為社區積累并傳播經驗價值,

前言

訪問控制(Access control)是指對訪問者向受保護資源進行訪問操作的控制管理,該控制管理保證被授權者可訪問受保護資源,未被授權者不能訪問受保護資源,

現實生活中的訪問控制可以由付費或者認證達成,例如:進電影院看電影,需要夠買電影票,否則檢票員就不讓你進去,

訪問控制有很多模型,比如:

  • 自主訪問控制模型 (Discretionary Access Control)
  • 強制訪問控制模型 (MAC: Mandatory Access Control)
  • 角色訪問控制模型 (RBAC: Role-based Access Control)
  • 屬性訪問控制模型 (ABAC: Attribute-Based Access Control)

DAC

自主訪問控制(DAC: Discretionary Access Control),系統會識別用戶,然后根據訪問物件的權限控制串列(ACL: Access Control List)或者權限控制矩陣(ACL: Access Control Matrix)的資訊來決定用戶是否能對其進行哪些操作,例如讀取或修改,而擁有物件權限的用戶,又可以將該物件的權限分配給其他用戶,所以稱之為“自主(Discretionary)”控制,

自主訪問控制模型是一種相對比較寬松但是卻很有效的保護資源不被非法訪問和使用的手段,說它寬松,是因為他是自主控制的,在保護資源的時候是以個人意志為轉移的;說它有效,是因為可以明確的顯式的指出主體在訪問或使用某個客體時究竟是以何種權限來實施的,任何超越規定權限的訪問行為都會被訪問控制串列判定后而被阻止,

比較典型的場景是在 Linux 的檔案系統中:
系統中的每個檔案(一些特殊檔案可能沒有,如塊設備檔案等)都有所有者,檔案的所有者是創建這個檔案的計算機的使用者(或事件,或另一個檔案),那么此檔案的自主訪問控制權限由它的創建者來決定如何設定和分配,檔案的所有者擁有訪問權限,并且可以將訪問權限分配給自己及其他用戶

MAC

強制訪問控制(MAC: Mandatory Access Control),用于將系統中的資訊分密級和類進行管理,以保證每個用戶只能訪問到那些被標 制訪問控制下,用戶(或其他主體)與檔案(或其他客體)都被標記了固定的安全屬性(如安全級、訪問權限等),在每次訪問發生時,系統檢測安全屬性以便確定一個用戶是否有權訪問該檔案,

MAC 最早主要用于軍方的應用中,通常與 DAC 結合使用,兩種訪問控制機制的過濾結果將累積,以此來達到更佳的訪問控制效果,也就是說,一個主體只有通過了 DAC 限制檢查與 MAC 限制檢查的雙重過濾裝置之后,才能真正訪問某個客體,一方面,用戶可以利用 DAC 來防范其它用戶對那些所有權歸屬于自己的客體的攻擊;另一方面,由于用戶不能直接改變 MAC 屬性,所以 MAC 提供了一個不可逾越的、更強的安全保護層以防止其它用戶偶然或故意地濫用 DAC,

RBAC

角色訪問控制 (RBAC: Role-based Access Control),各種權限不是直接授予具體的用戶,而是在用戶集合與權限集合之間建立一個角色集合, 每一種角色對應一組相應的權限, 一旦用戶被分配了適當的角色后,該用戶就擁有此角色的所有操作權限目前來說基于角色的訪問控制模型是應用較廣的一個,特別是 2B 方向 SAAS 領域,應用尤其常見,角色訪問也就是我們今天要介紹的重點,

RBAC 雖然簡化了權限的管理,但是對于復雜場景的角色管理,它依然不夠靈活,比如主體和客體之間的權限復雜多變,可能就需要維護大量的角色及其授權關系;新增客體也需要對所有相關角色進行處理,基于屬性的角色訪問控制就是為了解決這個問題,

ABAC

屬性訪問控制(Attributes-based Access Control)是一種非常靈活的訪問控制模型,屬性包括請求主體的屬性、請求客體的屬性、請求背景關系的屬性、操作的屬性等,如身為班主任(主體的屬性)的老張在上課(背景關系的屬性)時可以踢(操作屬性)身為普通學生(客體的屬性)的小明一腳,可以看到,只要對屬性進行精確定義及劃分,ABAC可以實作非常復雜的權限控制,

比如:大二(年級)計科(專業)二班(班級)的班干(職位)可以在學校內網(環境)上傳(操作)班級的照片,

但是由于 ABAC 比較復雜,對于目前的 SAAS 領域,就顯得有點大材小用了,所以在 SAAS 領域很少見到有使用ABAC 的平臺,目前使用 ABAC 比較多的就是一些云服務,

數堆疊中的 RBAC

我們產品中采用的是 RBAC 的權限方案,所以我們目前只對 RBAC 進行分析,

RBAC 是角色訪問控制,那么首先我們需要知道的是用戶的角色,在這個方面,我們專案中存在了用戶管理以及角色管理兩個模塊,

用戶管理

在登陸門戶的用戶管理中提供用戶賬戶的創建、編輯和洗掉等功能,

file

在數堆疊的產品中,存在租戶的概念,每個租戶下都有一個自己的用戶管理,對租戶內的用戶進行管理,能夠設定當前用戶的角色,這些角色包括租戶所有者、專案所有者和專案管理者等,

file

角色管理

在角色管理中可以看到角色的定義,以及它所擁有的訪問權限,

file

我們通過在用戶管理和角色管理中的用戶定義,可以得到當前用戶完整的產品訪問權限,當用戶進入某個功能時,我們就可以通過當前的準入權限以及用戶的訪問權限,進行比較,進而得出是否準入的結論,

對于我們前端開發者而言,我們需要的其實就是

  1. 用戶具體的角色權限
  2. 通過用戶具體的角色權限, 對權限進行校驗

那我們來看看 ant design pro 的權限方案是如何處理的,

ant design pro 中的權限方案

業界比較通用的 ant design pro 中的權限方案是如何設計的呢?

獲取用戶角色權限

一開始在進入頁面的同時,會進行登陸校驗,如果未登錄會跳轉到登錄頁面,進行登陸操作,登陸成功后,會把當前用戶的角色資料通過 setAuthority 方法存進 localStorage 中,方便我們重新進入頁面時獲取,

而對于已經登錄校驗通過的,會直接進入專案中,進行渲染頁面基礎布局 BasicLayout 組件,在 BasicLayout 組件中我們使用到了Authorized組件,在掛載Authorized的時候,觸發renderAuthorizeCURRENT進行賦值,后續的權限校驗都會使用CURRENT,比較關鍵,

下面是這兩種情況的方法呼叫流程圖:

file

renderAuthorize 方法是一個柯里化函式,在內部使用getAuthority獲取到角色資料時對 CURRENT
進行賦值,

let CURRENT: string | string[] = 'NULL';

type CurrentAuthorityType = string | string[] | (() => typeof CURRENT);
/**
 * use  authority or getAuthority
 * @param {string|()=>String} currentAuthority
 */
const renderAuthorize = (Authorized: any) => (currentAuthority: CurrentAuthorityType) => {
  if (currentAuthority) {
    if (typeof currentAuthority === 'function') {
      CURRENT = currentAuthority();
    }
    if (
      Object.prototype.toString.call(currentAuthority) === '[object String]' ||
      Array.isArray(currentAuthority)
    ) {
      CURRENT = currentAuthority as string[];
    }
  } else {
    CURRENT = 'NULL';
  }
  return Authorized;
};

export { CURRENT };
export default (Authorized: any) => renderAuthorize(Authorized);

到這,專案的權限獲取以及更新就完成了,接下來就是權限的校驗了

校驗權限

對于權限校驗,需要以下環境引數:

  1. authority:當前訪問權限也就是準入權限
  2. currentAuthority:當前用戶的角色,也就是 CURRENT
  3. target:校驗成功展示的組件
  4. Exception:校驗失敗展示的組件

對于需要進行權限校驗的組件,使用Authorized組件進行組合,在Authorized組件內部,實作了checkPermissions方法,用來校驗當前用戶角色,是否有權限的進行訪問,如果有權限,則直接展示當前的組件,如果沒有則展示無權限等訊息,

file

Authorized組件的實作,

type IAuthorizedType = React.FunctionComponent<AuthorizedProps> & {
  Secured: typeof Secured;
  check: typeof check;
  AuthorizedRoute: typeof AuthorizedRoute;
};

const Authorized: React.FunctionComponent<AuthorizedProps> = ({
  children,
  authority,
  noMatch = (
    <Result
      status="403"
      title="403"
      subTitle="Sorry, you are not authorized to access this page."
    />
  ),
}) => {
  const childrenRender: React.ReactNode = typeof children === 'undefined' ? null : children;
  const dom = check(authority, childrenRender, noMatch);
  return <>{dom}</>;
};

function check<T, K>(authority: IAuthorityType, target: T, Exception: K): T | K | React.ReactNode {
  return checkPermissions<T, K>(authority, CURRENT, target, Exception);
}
/**
 * 通用權限檢查方法
 * Common check permissions method
 * @param { 權限判定 | Permission judgment } authority
 * @param { 你的權限 | Your permission description } currentAuthority
 * @param { 通過的組件 | Passing components } target
 * @param { 未通過的組件 | no pass components } Exception
 */
const checkPermissions = <T, K>(
  authority: IAuthorityType,
  currentAuthority: string | string[],
  target: T,
  Exception: K,
): T | K | React.ReactNode => {
  // 沒有判定權限.默認查看所有
  // Retirement authority, return target;
  if (!authority) {
    return target;
  }
  // 陣列處理
  if (Array.isArray(authority)) {
    if (Array.isArray(currentAuthority)) {
      if (currentAuthority.some((item) => authority.includes(item))) {
        return target;
      }
    } else if (authority.includes(currentAuthority)) {
      return target;
    }
    return Exception;
  }
  // string 處理
  if (typeof authority === 'string') {
    if (Array.isArray(currentAuthority)) {
      if (currentAuthority.some((item) => authority === item)) {
        return target;
      }
    } else if (authority === currentAuthority) {
      return target;
    }
    return Exception;
  }
  // Promise 處理
  if (authority instanceof Promise) {
    return <PromiseRender<T, K> ok={target} error={Exception} promise={authority} />;
  }
  // Function 處理
  if (typeof authority === 'function') {
    const bool = authority(currentAuthority);
    // 函式執行后回傳值是 Promise
    if (bool instanceof Promise) {
      return <PromiseRender<T, K> ok={target} error={Exception} promise={bool} />;
    }
    if (bool) {
      return target;
    }
    return Exception;
  }
  throw new Error('unsupported parameters');
};

使用 Authorized 組件

在頁面上使用則非常的方便,對需要進行權限管控的組件,使用 Authorized組件進行組合即可,

function NoMatch = () => {
	return <div>404</div>
}

<Authorized authority={'admin'} noMatch={NoMatch}>
  {children}
</Authorized>

我們還可以利用路由進行組件的匹配,

<Authorized
    authority={authority}
    noMatch={<Route {...rest} render={() => <Redirect to={{ pathname: redirectPath }} />} />}
  >
    <Route
      {...rest}
      render={(props: any) => (Component ? <Component {...props} /> : render(props))}
    />
</Authorized>

我們的權限方案

舊權限方案

在舊方案中,通過介面請求后端維護的權限資料,這部分權限資料只維護了選單這一級別,將請求到的資料存入快取中,便于后續的使用,

在我們內部的業務工具包中監聽頁面地址的改變,根據快取的資料判斷是否有進入當前頁面的權限,根據結果來進行相應的處理,實際就是做了個路由守衛的功能,

而在子產品中,根據快取的資料來判斷是否顯示當前的選單入口,這兩者組合,形成了我們舊方案,

隨著數堆疊的成長,舊方案慢慢的也暴露出了許多的問題,

  • 對權限控制的范圍太小,我們只控制到了選單這一級別,而對于特殊頁面和某些場景下需要對功能的控制(如:編輯,新增、洗掉等),目前只有后端介面進行限制,頁面上并沒有進行限制,如果需要實作這個功能,就需要添加額外的介面和處理邏輯,
  • 我們把權限的處理分成兩部分,業務工具包和子產品中,但是兩者間的耦合度是非常高的,往往改動了一個地方,另一個也需要跟著更改,
  • 我們在研發程序中,每當需要增加一個選單,就需要增加一條對應的選單處理邏輯,增加一個產品,就需要增加這個產品對應的所有選單邏輯,目前數堆疊的子產品已經超過了 10+ ,可以想象這部分處理邏輯是有多么的臃腫,
  • ......

實際的問題不止以上列的三點,但是這三點就足夠我們進行新的權限方案的探索,

新權限方案

在新方案中,業務工具包只保留權限的公共方法,把頁面權限判斷的邏輯進行的下放,子產品自己維護自己的權限判斷邏輯,修改一條權限的邏輯也非常的容易

更改后的流程如下:

file

相比起 ant design pro 中通過角色進行判斷,新方案中我們把角色權限的判斷邏輯移交給了后端,后端經過了相應的處理后,回傳對應的 code 碼集合,

我們為每個需要設定準入權限的模塊,定義一個 code 碼,去比較后端回傳的集合中,是否能夠找到相同的 code,如果能找到說明就有訪問當前模塊的權限,反之則沒有,

經過這樣處理后,我們只需要關心是否能夠進入,

在獲取到權限點的時候,還會根據這個權限點,去快取有權限訪問的路由串列,當路由改變時,就可以去有權的路由串列里進行查找,如果沒有找到就進行重定向之類的操作,也就是路由守衛的功能,

總結

經過上面的介紹,我們對權限方案已經有所了解,主要分為兩個階段:

  1. 獲取權限階段:在獲取權限階段,往往是用戶登入或進入專案時,第一時間根據用戶資訊獲取相對應的權限
  2. 校驗權限階段:通過用戶的權限,與當前模塊的準入權限進行比對,在根據結果進行操作

知道了這些之后,就可以結合自身的場景,制定出相應的權限方案,

轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/541874.html

標籤:Html/Css

上一篇:CSS 奇思妙想之酷炫倒影

下一篇:當你輸入網址,小手一點,然后發生了什么?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • IEEE1588PTP在數字化變電站時鐘同步方面的應用

    IEEE1588ptp在數字化變電站時鐘同步方面的應用 京準電子科技官微——ahjzsz 一、電力系統時間同步基本概況 隨著對IEC 61850標準研究的不斷深入,國內外學者提出基于IEC61850通信標準體系建設數字化變電站的發展思路。數字化變電站與常規變電站的顯著區別在于程序層傳統的電流/電壓互 ......

    uj5u.com 2020-09-10 03:51:52 more
  • HTTP request smuggling CL.TE

    CL.TE 簡介 前端通過Content-Length處理請求,通過反向代理或者負載均衡將請求轉發到后端,后端Transfer-Encoding優先級較高,以TE處理請求造成安全問題。 檢測 發送如下資料包 POST / HTTP/1.1 Host: ac391f7e1e9af821806e890 ......

    uj5u.com 2020-09-10 03:52:11 more
  • 網路滲透資料大全單——漏洞庫篇

    網路滲透資料大全單——漏洞庫篇漏洞庫 NVD ——美國國家漏洞庫 →http://nvd.nist.gov/。 CERT ——美國國家應急回應中心 →https://www.us-cert.gov/ OSVDB ——開源漏洞庫 →http://osvdb.org Bugtraq ——賽門鐵克 →ht ......

    uj5u.com 2020-09-10 03:52:15 more
  • 京準講述NTP時鐘服務器應用及原理

    京準講述NTP時鐘服務器應用及原理京準講述NTP時鐘服務器應用及原理 安徽京準電子科技官微——ahjzsz 北斗授時原理 授時是指接識訓通過某種方式獲得本地時間與北斗標準時間的鐘差,然后調整本地時鐘使時差控制在一定的精度范圍內。 衛星導航系統通常由三部分組成:導航授時衛星、地面檢測校正維護系統和用戶 ......

    uj5u.com 2020-09-10 03:52:25 more
  • 利用北斗衛星系統設計NTP網路時間服務器

    利用北斗衛星系統設計NTP網路時間服務器 利用北斗衛星系統設計NTP網路時間服務器 安徽京準電子科技官微——ahjzsz 概述 NTP網路時間服務器是一款支持NTP和SNTP網路時間同步協議,高精度、大容量、高品質的高科技時鐘產品。 NTP網路時間服務器設備采用冗余架構設計,高精度時鐘直接來源于北斗 ......

    uj5u.com 2020-09-10 03:52:35 more
  • 詳細解讀電力系統各種對時方式

    詳細解讀電力系統各種對時方式 詳細解讀電力系統各種對時方式 安徽京準電子科技官微——ahjzsz,更多資料請添加VX 衛星同步時鐘是我京準公司開發研制的應用衛星授時時技術的標準時間顯示和發送的裝置,該裝置以M國全球定位系統(GLOBAL POSITIONING SYSTEM,縮寫為GPS)或者我國北 ......

    uj5u.com 2020-09-10 03:52:45 more
  • 如何保證外包團隊接入企業內網安全

    不管企業規模的大小,只要企業想省錢,那么企業的某些服務就一定會采用外包的形式,然而看似美好又經濟的策略,其實也有不好的一面。下面我通過安全的角度來聊聊使用外包團的安全隱患問題。 先看看什么服務會使用外包的,最常見的就是話務/客服這種需要大量重復性、無技術性的服務,或者是一些銷售外包、特殊的職能外包等 ......

    uj5u.com 2020-09-10 03:52:57 more
  • PHP漏洞之【整型數字型SQL注入】

    0x01 什么是SQL注入 SQL是一種注入攻擊,通過前端帶入后端資料庫進行惡意的SQL陳述句查詢。 0x02 SQL整型注入原理 SQL注入一般發生在動態網站URL地址里,當然也會發生在其它地發,如登錄框等等也會存在注入,只要是和資料庫打交道的地方都有可能存在。 如這里http://192.168. ......

    uj5u.com 2020-09-10 03:55:40 more
  • [GXYCTF2019]禁止套娃

    git泄露獲取原始碼 使用GET傳參,引數為exp 經過三層過濾執行 第一層過濾偽協議,第二層過濾帶引數的函式,第三層過濾一些函式 preg_replace('/[a-z,_]+\((?R)?\)/', NULL, $_GET['exp'] (?R)參考當前正則運算式,相當于匹配函式里的引數 因此傳遞 ......

    uj5u.com 2020-09-10 03:56:07 more
  • 等保2.0實施流程

    流程 結論 ......

    uj5u.com 2020-09-10 03:56:16 more
最新发布
  • 使用Django Rest framework搭建Blog

    在前面的Blog例子中我們使用的是GraphQL, 雖然GraphQL的使用處于上升趨勢,但是Rest API還是使用的更廣泛一些. 所以還是決定回到傳統的rest api framework上來, Django rest framework的官網上給了一個很好用的QuickStart, 我參考Qu ......

    uj5u.com 2023-04-20 08:17:54 more
  • 記錄-new Date() 我忍你很久了!

    這里給大家分享我在網上總結出來的一些知識,希望對大家有所幫助 大家平時在開發的時候有沒被new Date()折磨過?就是它的諸多怪異的設定讓你每每用的時候,都可能不小心踩坑。造成程式意外出錯,卻一下子找不到問題出處,那叫一個煩透了…… 下面,我就列舉它的“四宗罪”及應用思考 可惡的四宗罪 1. Sa ......

    uj5u.com 2023-04-20 08:17:47 more
  • 使用Vue.js實作文字跑馬燈效果

    實作文字跑馬燈效果,首先用到 substring()截取 和 setInterval計時器 clearInterval()清除計時器 效果如下: 實作代碼如下: <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <meta ......

    uj5u.com 2023-04-20 08:12:31 more
  • JavaScript 運算子

    JavaScript 運算子/運算子 在 JavaScript 中,有一些運算子可以使代碼更簡潔、易讀和高效。以下是一些常見的運算子: 1、可選鏈運算子(optional chaining operator) ?.是可選鏈運算子(optional chaining operator)。?. 可選鏈操 ......

    uj5u.com 2023-04-20 08:02:25 more
  • CSS—相對單位rem

    一、概述 rem是一個相對長度單位,它的單位長度取決于根標簽html的字體尺寸。rem即root em的意思,中文翻譯為根em。瀏覽器的文本尺寸一般默認為16px,即默認情況下: 1rem = 16px rem布局原理:根據CSS媒體查詢功能,更改根標簽的字體尺寸,實作rem單位隨螢屏尺寸的變化,如 ......

    uj5u.com 2023-04-20 08:02:21 more
  • 我的第一個NPM包:panghu-planebattle-esm(胖虎飛機大戰)使用說明

    好家伙,我的包終于開發完啦 歡迎使用胖虎的飛機大戰包!! 為你的主頁添加色彩 這是一個有趣的網頁小游戲包,使用canvas和js開發 使用ES6模塊化開發 效果圖如下: (覺得圖片太sb的可以自己改) 代碼已開源!! Git: https://gitee.com/tang-and-han-dynas ......

    uj5u.com 2023-04-20 08:01:50 more
  • 如何在 vue3 中使用 jsx/tsx?

    我們都知道,通常情況下我們使用 vue 大多都是用的 SFC(Signle File Component)單檔案組件模式,即一個組件就是一個檔案,但其實 Vue 也是支持使用 JSX 來撰寫組件的。這里不討論 SFC 和 JSX 的好壞,這個仁者見仁智者見智。本篇文章旨在帶領大家快速了解和使用 Vu ......

    uj5u.com 2023-04-20 08:01:37 more
  • 【Vue2.x原始碼系列06】計算屬性computed原理

    本章目標:計算屬性是如何實作的?計算屬性快取原理以及洋蔥模型的應用?在初始化Vue實體時,我們會給每個計算屬性都創建一個對應watcher,我們稱之為計算屬性watcher ......

    uj5u.com 2023-04-20 08:01:31 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:01:10 more
  • http1.1與http2.0

    一、http是什么 通俗來講,http就是計算機通過網路進行通信的規則,是一個基于請求與回應,無狀態的,應用層協議。常用于TCP/IP協議傳輸資料。目前任何終端之間任何一種通信方式都必須按Http協議進行,否則無法連接。tcp(三次握手,四次揮手)。 請求與回應:客戶端請求、服務端回應資料。 無狀態 ......

    uj5u.com 2023-04-20 08:00:32 more