1
0
wiki/Technology/ComputerSecurity/用户安全/权限设计/主流权限系统的设计.html

197 lines
477 KiB
HTML
Raw Normal View History

2024-09-05 22:26:11 +08:00
<!DOCTYPE html>
<html><head><title>主流权限系统的设计</title><meta charSet="utf-8"/><meta name="viewport" content="width=device-width, initial-scale=1.0"/><meta property="og:title" content="主流权限系统的设计"/><meta property="og:description" content="主流权限系统的设计."/><meta property="og:image" content="https://wiki.7wate.com/static/og-image.png"/><meta property="og:width" content="1200"/><meta property="og:height" content="675"/><link rel="icon" href="../../../../static/icon.png"/><meta name="description" content="主流权限系统的设计."/><meta name="generator" content="Quartz"/><link rel="preconnect" href="https://fonts.googleapis.com"/><link rel="preconnect" href="https://fonts.gstatic.com"/><script async src="https://umami.7wate.com/script.js" data-website-id="c061efdc-95dd-4d21-9d04-a1ffda0a85b9"></script><script>
var _hmt = _hmt || [];
(function() {
var hm = document.createElement("script");
hm.src = "https://hm.baidu.com/hm.js?94d8ccb156eb7c65abf317e6e01cdba9";
var s = document.getElementsByTagName("script")[0];
s.parentNode.insertBefore(hm, s);
})();
</script><script async src="https://www.googletagmanager.com/gtag/js?id=G-MHMEL0F832"></script><script>
(function() {
window.dataLayer = window.dataLayer || [];
function gtag() {
window.dataLayer.push(arguments);
}
gtag('js', new Date());
gtag('config', 'G-MHMEL0F832');
})();
</script><link href="../../../../index.css" rel="stylesheet" type="text/css" spa-preserve/><link href="https://cdn.jsdelivr.net/npm/katex@0.16.0/dist/katex.min.css" rel="stylesheet" type="text/css" spa-preserve/><link href="https://fonts.googleapis.com/css2?family=IBM Plex Mono&amp;family=Schibsted Grotesk:wght@400;700&amp;family=Source Sans Pro:ital,wght@0,400;0,600;1,400;1,600&amp;display=swap" rel="stylesheet" type="text/css" spa-preserve/><script src="../../../../prescript.js" type="application/javascript" spa-preserve></script><script type="application/javascript" spa-preserve>const fetchData = fetch(`../../../../static/contentIndex.json`).then(data => data.json())</script></head><body data-slug="Technology/ComputerSecurity/用户安全/权限设计/主流权限系统的设计"><div id="quartz-root" class="page"><div id="quartz-body"><div class="left sidebar"><h1 class="page-title "><a href="../../../..">📚 X·Eden</a></h1><div class="spacer mobile-only"></div><div class="search "><div id="search-icon"><p>Search</p><div></div><svg tabIndex="0" aria-labelledby="title desc" role="img" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 19.9 19.7"><title id="title">Search</title><desc id="desc">Search</desc><g class="search-path" fill="none"><path stroke-linecap="square" d="M18.5 18.3l-5.4-5.4"></path><circle cx="8" cy="8" r="7"></circle></g></svg></div><div id="search-container"><div id="search-space"><input autocomplete="off" id="search-bar" name="search" type="text" aria-label="Search for something" placeholder="Search for something"/><div id="results-container"></div></div></div></div><div class="darkmode "><input class="toggle" id="darkmode-toggle" type="checkbox" tabIndex="-1"/><label id="toggle-label-light" for="darkmode-toggle" tabIndex="-1"><svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" version="1.1" id="dayIcon" x="0px" y="0px" viewBox="0 0 35 35" style="enable-background:new 0 0 35 35;" xmlSpace="preserve"><title>Light mode</title><path d="M6,17.5C6,16.672,5.328,16,4.5,16h-3C0.672,16,0,16.672,0,17.5 S0.672,19,1.5,19h3C5.328,19,6,18.328,6,17.5z M7.5,26c-0.414,0-0.789,0.168-1.061,0.439l-2,2C4.168,28.711,4,29.086,4,29.5 C4,30.328,4.671,31,5.5,31c0.414,0,0.789-0.168,1.06-0.44l2-2C8.832,28.289,9,27.914,9,27.5C9,26.672,8.329,26,7.5,26z M17.5,6 C18.329,6,19,5.328,19,4.5v-3C19,0.672,18.329,0,17.5,0S16,0.672,16,1.5v3C16,5.328,16.671,6,17.5,6z M27.5,9 c0.414,0,0.789-0.168,1.06-0.439l2-2C30.832,6.289,31,5.914,31,5.5C31,4.672,30.329,4,29.5,4c-0.414,0-0.789,0.168-1.061,0.44 l-2,2C26.168,6.711,26,7.086,26,7.5C26,8.328,26.671,9,27.5,9z M6.439,8.561C6.711,8.832,7.086,9,7.5,9C8.328,9,9,8.328,9,7.5 c0-0.414-0.168-0.789-0.439-1.061l-2-2C6.289,4.168,5.914,4,5.5,4C4.672,4,4,4.672,4,5.5c0,0.414,0.168,0.789,0.439,1.06 L6.439,8.561z M33.5,16h-3c-0.828,0-1.5,0.672-1.5,1.5s0.672,1.5,1.5,1.5h3c0.828,0,1.5-0.672,1.5-1.5S34.328,16,33.5,16z M28.561,26.439C28.289,26.168,27.914,26,27.5,26c-0.828,0-1.5,0.672-1.5,1.5c0,0.414,0.168,0.789,0.439,1.06l2,2 C28.711,30.832,29.086,31,29.5,31c0.828,0,1.5-0.672,1.5-1.5c0-0.414-0.168-0.789-0.439-1.061L28.561,26.439z M17.5,29 c-0.829,0-1.5,0.672-1.5,1.5v3c0,0.828,0.671,1.5,1.5,1.5s1.5-0.672,1.5-1.5v-3C19,29.672,18.329,29,17.5,29z M17.5,7 C11.71,7,7,11.71,7,17.5S11.71,28,17.5,28S28,23.29,28,17.5S23.29,7,17.5,7z M17.5,25c-4.136,0-7.5-3.364-7.5-7.5 c0-4.136,3.364-7.5,7.5-7.5c4.136,0,7.5,3.364,7.5,7.5C25,21.636,21.636,25,17.5,25z"></path></svg></label><label id="toggle-label-dark" for="darkmode-toggle" tabIndex="-1"><svg xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" version="1.1" id="nightIcon" x="0px" y="0px" viewBox="0 0 100 100" style="enable-background='new 0 0 100 100'" xmlSpace="preserve"><title>Dark mode</title><path d="M96.76,66.458c-0.853-0.852-2.15-1.064-3.23-0.534c-6.063,2.991-12.858,4.571-19.655,4.571 C62.022,70.495,50.88,65.88,42.5,57.5C29.043,44.043,25.658,23.536,34.076,6.47c0.532-1.08,0.318-2.379-0.534-3.23 c-0.851-0.852-2.15-1.064-3.23-0.534c-4.918,2.427-9.375,5.619-13.246,9.491c-9
<p>主流的权限模型主要分为以下五种:</p>
<ul>
<li><strong>ACL 模型</strong>:访问控制列表</li>
<li><strong>DAC 模型</strong>:自主访问控制</li>
<li><strong>MAC 模型</strong>:强制访问控制</li>
<li><strong>ABAC 模型</strong>:基于属性的访问控制</li>
<li><strong>RBAC 模型</strong>:基于角色的权限访问控制</li>
</ul>
<h2 id="acl-模型访问控制列表">ACL 模型:访问控制列表<a aria-hidden="true" tabindex="-1" href="#acl-模型访问控制列表" class="internal"> §</a></h2>
<p><strong>Access Control List</strong>ACL 是最早的、最基本的一种访问控制机制,是基于客体进行控制的模型,在其他模型中也有 ACL 的身影。为了解决相同权限的用户挨个配置的问题,后来也采用了用户组的方式。</p>
<p><strong>原理</strong>:每一个客体都有一个列表,列表中记录的是哪些主体可以对这个客体做哪些行为,非常简单。</p>
<p><strong>例如</strong>:当用户 A 要对一篇文章进行编辑时ACL 会先检查一下文章编辑功能的控制列表中有没有用户 A有就可以编辑无则不能编辑。再例如不同等级的会员在产品中可使用的功能范围不同。</p>
<p><strong>缺点</strong>:当主体的数量较多时,配置和维护工作就会成本大、易出错。</p>
<h2 id="dac-模型自主访问控制">DAC 模型:自主访问控制<a aria-hidden="true" tabindex="-1" href="#dac-模型自主访问控制" class="internal"> §</a></h2>
<p>Discretionary Access ControlDAC 是 ACL 的一种拓展。</p>
<p><strong>原理</strong>:在 ACL 模型的基础上,允许主体可以将自己拥有的权限自主地授予其他主体,所以权限可以任意传递。</p>
<p><strong>例如</strong>常见于文件系统LINUXUNIX、WindowsNT 版本的操作系统都提供 DAC 的支持。</p>
<p><strong>缺点</strong>:对权限控制比较分散,例如无法简单地将一组文件设置统一的权限开放给指定的一群用户。主体的权限太大,无意间就可能泄露信息。</p>
<h2 id="mac-模型强制访问控制">MAC 模型:强制访问控制<a aria-hidden="true" tabindex="-1" href="#mac-模型强制访问控制" class="internal"> §</a></h2>
<p><strong>Mandatory Access Control</strong>MAC 模型中主要的是双向验证机制。常见于机密机构或者其他等级观念强烈的行业,如军用和市政安全领域的软件。</p>
<p><strong>原理</strong>:主体有一个权限标识,客体也有一个权限标识,而主体能否对该客体进行操作取决于双方的权限标识的关系。</p>
<p><strong>例如</strong>:将军分为上将 > 中将 > 少将,军事文件保密等级分为绝密 > 机密 > 秘密,规定不同军衔仅能访问不同保密等级的文件,如少将只能访问秘密文件;当某一账号访问某一文件时,系统会验证账号的军衔,也验证文件的保密等级,当军衔和保密等级相对应时才可以访问。</p>
<p><strong>缺点</strong>:控制太严格,实现工作量大,缺乏灵活性。</p>
<h2 id="abac-模型基于属性的访问控制">ABAC 模型:基于属性的访问控制<a aria-hidden="true" tabindex="-1" href="#abac-模型基于属性的访问控制" class="internal"> §</a></h2>
<p><strong>Attribute-Based Access Control</strong>,能很好地解决 RBAC 的缺点,在新增资源时容易维护。</p>
<p><strong>原理</strong>:通过动态计算一个或一组属性是否满足某种机制来授权,是一种很灵活的权限模型,可以按需实现不同颗粒度的权限控制。</p>
<p>属性通常有四类:</p>
<ol>
<li>主体属性,如用户年龄、性别等;</li>
<li>客体属性,如一篇文章等;</li>
<li>环境属性,即空间限制、时间限制、频度限制;</li>
<li>操作属性,即行为类型,如读写、只读等。</li>
</ol>
<p><strong>例如</strong>:早上 9:0011:00 期间 A、B 两个部门一起以考生的身份考试,下午 14:0017:00 期间 A、B 两个部门相互阅卷。</p>
<p><strong>缺点</strong>:规则复杂,不易看出主体与客体之间的关系,实现非常难,现在应用的很少。</p>
<h2 id="rbac-基于角色的权限访问控制">RBAC 基于角色的权限访问控制<a aria-hidden="true" tabindex="-1" href="#rbac-基于角色的权限访问控制" class="internal"> §</a></h2>
<p><strong>Role-Based Access Control</strong>,核心在于用户只和角色关联,而角色代表对了权限,是一系列权限的集合。</p>
<p>RBAC 三要素:</p>
<ol>
<li><strong>用户</strong>:系统中所有的账户</li>
<li><strong>角色</strong>:一系列权限的集合(如:管理员,开发者,审计管理员等)</li>
<li><strong>权限</strong>:菜单,按钮,数据的增删改查等详细权限。</li>
</ol>
<p>在 **RBAC **中,权限与角色相关联,用户通过成为适当角色的成员而得到这些角色的权限。</p>
<p>角色是为了完成各种工作而创造,用户则依据它的责任和资格来被指派相应的角色,用户可以很容易地从一个角色被指派到另一个角色。</p>
<p>角色可依新的需求和系统的合并而赋予新的权限,而权限也可根据需要而从某角色中回收。角色与角色的关系同样也存在继承关系防止越权。</p>
<p><strong>优点</strong>:便于角色划分,更灵活的授权管理;最小颗粒度授权;</p>
<p><img src="https://static.7wate.com/img/2022/08/30/2fb0d9ad61795.png" alt="RBAC"/></p>
<h2 id="rbac-的深度拓展">RBAC 的深度拓展<a aria-hidden="true" tabindex="-1" href="#rbac-的深度拓展" class="internal"> §</a></h2>
<p>RBAC 模型可以分为:<strong>RBAC0</strong><strong>RBAC1</strong><strong>RBAC2</strong><strong>RBAC3</strong> 四个阶段,一般公司使用 <strong>RBAC0</strong> 的模型就可以。另外,<strong>RBAC0</strong> 相当于底层逻辑,后三者都是在 <strong>RBAC0</strong> 模型上的拔高。</p>
<p>我先简单介绍下这四个 RBAC 模型:</p>
<h3 id="1-rbac0-模型">1. RBAC0 模型<a aria-hidden="true" tabindex="-1" href="#1-rbac0-模型" class="internal"> §</a></h3>
<p>用户和角色、角色和权限多对多关系。</p>
<p>简单来说就是一个用户拥有多个角色,一个角色可以被多个用户拥有,这是用户和角色的多对多关系;同样的,角色和权限也是如此。</p>
<p><strong>RBAC0</strong> 模型如下图:没有画太多线,但是已经能够看出多对多关系。</p>
<p><img src="https://static.7wate.com/img/2022/08/30/704178e086081.png" alt="RBAC0"/></p>
<h3 id="2-rbac1-模型">2. RBAC1 模型<a aria-hidden="true" tabindex="-1" href="#2-rbac1-模型" class="internal"> §</a></h3>
<p>相对于 <strong>RBAC0 <strong>模型,增加了</strong>角色分级</strong>的逻辑,类似于树形结构,下一节点继承上一节点的所有权限,如 <strong>role1</strong> 根节点下有 <strong>role1.1</strong><strong>role1.2</strong> 两个子节点</p>
<p><img src="https://static.7wate.com/img/2022/08/30/ab50d1c150699.png" alt="RABC1"/></p>
<p>角色分级的逻辑可以有效的规范角色创建(主要得益于权限继承逻辑),我之前做过 BD 工具(类 CRM BD 之间就有分级(经理、主管、专员),如果采用 RBAC0 模型做权限系统,我可能需要为经理、主管、专员分别创建一个角色(角色之间权限无继承性),极有可能出现一个问题,由于权限配置错误,主管拥有经理都没有权限。</p>
<p>而 RBAC1 模型就很好解决了这个问题,创建完经理角色并配置好权限后,主管角色的权限继承经理角色的权限,并且支持针对性删减主管权限。</p>
<h3 id="3-rbac2-模型">3. RBAC2 模型<a aria-hidden="true" tabindex="-1" href="#3-rbac2-模型" class="internal"> §</a></h3>
<p>基于 <strong>RBAC0</strong> 模型,对角色增加了更多约束条件。</p>
<p><img src="https://static.7wate.com/img/2022/08/30/adc688e2b7f77.png" alt="RBAC2"/></p>
<p><strong>角色互斥</strong>,比较经典的案例是财务系统中出纳不得兼管稽核,那么在赋予财务系统操作人员角色时,同一个操作员不能同时拥有出纳和稽核两个角色。</p>
<p><strong>角色数量限制</strong>,例如:一个角色专门为公司 CEO 创建的,最后发现公司有 10 个人拥有 CEO 角色,一个公司有 10 个 CEO ?这就是对角色数量的限制,它指的是有多少用户能拥有这个角色。</p>
<p><strong>RBAC2</strong> 模型主要是为了增加角色赋予的限制条件,这也符合权限系统的目标:权责明确,系统使用安全、保密。</p>
<h3 id="4-rbac3-模型">4. RBAC3 模型<a aria-hidden="true" tabindex="-1" href="#4-rbac3-模型" class="internal"> §</a></h3>
<p>同样是基于 <strong>RBAC0</strong> 模型,但是综合了 <strong>RBAC1</strong><strong>RBAC2</strong> 的所有特点</p>
<p>这里就不在多描述,读者返回去看 <strong>RBAC1</strong><strong>RBAC2</strong> 模型的描述即可。</p>
<h2 id="rbac-权限管理的在实际系统中的应用">RBAC 权限管理的在实际系统中的应用<a aria-hidden="true" tabindex="-1" href="#rbac-权限管理的在实际系统中的应用" class="internal"> §</a></h2>
<p>RBAC 权限模型由三大部分构成,即<strong>用户管理</strong><strong>角色管理</strong><strong>权限管理</strong></p>
<p>用户管理按照企业架构或业务线架构来划分,这些结构本身比较清晰,扩展性和可读性都非常好。</p>
<p>角色管理一定要在深入理解业务逻辑后再来设计,一般使用各部门真实的角色作为基础,再根据业务逻辑进行扩展。</p>
<p>权限管理是前两种管理的再加固,做太细容易太碎片,做太粗又不够安全,这里我们需要根据经验和实际情况来设计。</p>
<h3 id="1-用户管理">1. 用户管理<a aria-hidden="true" tabindex="-1" href="#1-用户管理" class="internal"> §</a></h3>
<p>用户管理中的用户,是企业里每一位员工,他们本身就有自己的组织架构,我们可以直接使用企业部门架构或者业务线架构来作为线索,构建用户管理系统。</p>
<p><img src="https://static.7wate.com/img/2022/08/30/887a6f017f7e3.png" alt="用户管理系统"/></p>
<p><strong>需要特殊注意</strong>:实际业务中的组织架构可能与企业部门架构、业务线架构不同,需要考虑数据共享机制,一般的做法为授权某个人、某个角色组共享某个组织层级的某个对象组数据。</p>
<h3 id="2-角色管理">2. 角色管理<a aria-hidden="true" tabindex="-1" href="#2-角色管理" class="internal"> §</a></h3>
<p>在设计系统角色时,我们应该深入理解公司架构、业务架构后,再根据需求设计角色及角色内的等级。</p>
<p>一般角色相对于用户来说是固定不变的,每个角色都有自己明确的权限和限制,这些权限在系统设计之处就确定了,之后也轻易不会再变动。</p>
<h4 id="1-自动获得基础角色">1. 自动获得基础角色<a aria-hidden="true" tabindex="-1" href="#1-自动获得基础角色" class="internal"> §</a></h4>
<p>当员工入职到某部门时,该名员工的账号应该自动被加入该部门对应的基础角色中,并拥有对应的基础权限。这种操作是为了保证系统安全的前提下,减少了管理员大量手动操作。使新入职员工能快速使用系统,提高工作效率。</p>
<h4 id="2-临时角色与失效时间">2. 临时角色与失效时间<a aria-hidden="true" tabindex="-1" href="#2-临时角色与失效时间" class="internal"> §</a></h4>
<p>公司业务有时需要外援来支持,他们并不属于公司员工,也只是在某个时段在公司做支持。此时我们需要设置临时角色,来应对这种可能跨多部门协作的临时员工。</p>
<p>如果公司安全级别较高,此类账号默认有固定失效时间,到达失效时间需再次审核才能重新开启。避免临时账号因为流程不完善,遗忘在系统中,引起安全隐患。</p>
<h4 id="3-虚拟角色">3. 虚拟角色<a aria-hidden="true" tabindex="-1" href="#3-虚拟角色" class="internal"> §</a></h4>
<p>部门角色中的等级,可以授权同等级的员工拥有相同的权限,但某些员工因工作原因,需要调用角色等级之外的权限,相同等级不同员工需要使用的权限还不相同。</p>
<p>这种超出角色等级又合理的权限授予,我们可以设置虚拟角色。这一虚拟角色可集成这一工作所需的所有权限,然后将它赋予具体的员工即可。这样即不用调整组织架构和对应的角色,也可以满足工作中特殊情况的权限需求。</p>
<h4 id="4-黑白名单">4. 黑白名单<a aria-hidden="true" tabindex="-1" href="#4-黑白名单" class="internal"> §</a></h4>
<p><strong>白名单</strong>:某些用户自身不拥有某部门的顶级角色,但处于业务需求,需要给他角色外的高级权限,那么我们可以设计限制范围的白名单,将需要的用户添加进去即可。</p>
<p>在安全流程中,我们仅需要对白名单设计安全流程,即可审核在白名单中的特殊用户,做到监控拥有特殊权限的用户,减少安全隐患。</p>
<p><strong>黑名单</strong>:比较常见的黑名单场景是某些犯了错误的员工,虽然在职,但已经不能给他们任何公司权限了。这种既不能取消角色关联,也不能完全停用账号的情况,可以设置黑名单,让此类用户可以登录账号,查看基本信息,但大多数关键权限已经被黑名单限制。</p>
<h3 id="3-权限管理">3. 权限管理<a aria-hidden="true" tabindex="-1" href="#3-权限管理" class="internal"> §</a></h3>
<p>权限管理一般从三个方面来做限制。<strong>页面/菜单权限</strong><strong>操作权限</strong><strong>数据权限</strong></p>
<p><img src="https://static.7wate.com/img/2022/08/30/8ad6abcc85524.png" alt="权限管理系统"/></p>
<h4 id="1-页面菜单权限">1. 页面/菜单权限<a aria-hidden="true" tabindex="-1" href="#1-页面菜单权限" class="internal"> §</a></h4>
<p>对于没有权限操作的用户,直接隐藏对应的页面入口或菜单选项。这种方法简单快捷直接,对于一些安全不太敏感的权限,使用这种方式非常高效。</p>
<h4 id="2-操作权限">2. 操作权限<a aria-hidden="true" tabindex="-1" href="#2-操作权限" class="internal"> §</a></h4>
<p>操作权限通常是指对同一组数据,不同的用户是否可以增删改查。对某些用户来说是只读浏览数据,对某些用户来说是可编辑的数据。</p>
<h4 id="3-数据权限">3. 数据权限<a aria-hidden="true" tabindex="-1" href="#3-数据权限" class="internal"> §</a></h4>
<p>对于安全需求高的权限管理,仅从前端限制隐藏菜单,隐藏编辑按钮是不够的,还需要在数接口上做限制。如果用户试图通过非法手段编辑不属于自己权限下的数据,服务器端会识别、记录并限制访问。</p>
<h4 id="4-数据权限如何管控">4. 数据权限如何管控<a aria-hidden="true" tabindex="-1" href="#4-数据权限如何管控" class="internal"> §</a></h4>
<p>数据权限可以分为行权限和列权限。行权限控制:看多少条数据。列权限控制:看一条数据的多少个字段。</p>
<p>简单系统中可以通过组织架构来管控行权限,按照角色来配置列权限,但是遇到复杂情况,组织架构是承载不了复杂行权限管控,角色也更不能承载列的特殊化展示。</p>
<p>目前行业的做法是提供行列级数据权规则配置,把规则当成类似权限点配置赋予某个角色或者某个用户。</p>
<p><img src="https://static.7wate.com/img/2022/08/08/900928128de9c.png" alt="新建规则"/></p>
<p><img src="https://static.7wate.com/img/2022/08/08/d81016b4c7467.png" alt="角色管理"/></p>
<h2 id="用户管理系统权限设计中的更多实践细节">用户管理系统权限设计中的更多实践细节<a aria-hidden="true" tabindex="-1" href="#用户管理系统权限设计中的更多实践细节" class="internal"> §</a></h2>
<h3 id="1-超级管理员">1. 超级管理员<a aria-hidden="true" tabindex="-1" href="#1-超级管理员" class="internal"> §</a></h3>
<p>超级管理员是用来启动系统,配置系统的账号。这个账号应该在配置好系统,创建管理员之后被隐藏起来。超级管理员账号拥有系统中全部权限,可穿梭查看各部门数据,如果使用不恰当,是系统管理的安全隐患。</p>
<h3 id="2-互斥角色如何处理">2. 互斥角色如何处理<a aria-hidden="true" tabindex="-1" href="#2-互斥角色如何处理" class="internal"> §</a></h3>
<p>当用户已经有用的角色和即将添加的角色互相互斥时,应该在添加新角色时,提示管理员因角色互斥的原因,无法进行新角色添加。如需添加,要先撤销掉前一个角色,再添加新角色。</p>
<h3 id="3-用户管理权限系统设计一定要简单清晰">3. 用户管理权限系统设计一定要简单清晰<a aria-hidden="true" tabindex="-1" href="#3-用户管理权限系统设计一定要简单清晰" class="internal"> §</a></h3>
<p>在设计权限系统之处,一定要理清思路,一切从简,能不增加的多余角色和权限逻辑,就一定不要增加。因为随着公司业务的扩大,权限和角色也会随之增多,如果初期设计思路不严谨,那么权限系统会随着业务的扩大而无限混乱下去,此时再来整理权限,已经太晚了。所以初期设计就一定要条理清晰,简单明了,能避免后续非常多不必要的麻烦。</p>
<h3 id="4-无权提示页">4. 无权提示页<a aria-hidden="true" tabindex="-1" href="#4-无权提示页" class="internal"> §</a></h3>
<p>有时员工 A 会直接给员工 B 分享他当下正在操作的页面,但有可能员工 B 无权查看。此时我们应该在这里考虑添加「无权提示页」,避免粗暴的 404 页面让员工 B 以为是系统出错了。</p></article></div><div class="right sidebar"><div class="graph "><h3>Graph View</h3><div class="graph-outer"><div id="graph-container" data-cfg="{&quot;drag&quot;:true,&quot;zoom&quot;:true,&quot;depth&quot;:1,&quot;scale&quot;:1.1,&quot;repelForce&quot;:0.5,&quot;centerForce&quot;:0.3,&quot;linkDistance&quot;:30,&quot;fontSize&quot;:0.6,&quot;opacityScale&quot;:1,&quot;showTags&quot;:true,&quot;removeTags&quot;:[]}"></div><svg version="1.1" id="global-graph-icon" xmlns="http://www.w3.org/2000/svg" xmlnsXlink="http://www.w3.org/1999/xlink" x="0px" y="0px" viewBox="0 0 55 55" fill="currentColor" xmlSpace="preserve"><path d="M49,0c-3.309,0-6,2.691-6,6c0,1.035,0.263,2.009,0.726,2.86l-9.829,9.829C32.542,17.634,30.846,17,29,17
s-3.542,0.634-4.898,1.688l-7.669-7.669C16.785,10.424,17,9.74,17,9c0-2.206-1.794-4-4-4S9,6.794,9,9s1.794,4,4,4
c0.74,0,1.424-0.215,2.019-0.567l7.669,7.669C21.634,21.458,21,23.154,21,25s0.634,3.542,1.688,4.897L10.024,42.562
C8.958,41.595,7.549,41,6,41c-3.309,0-6,2.691-6,6s2.691,6,6,6s6-2.691,6-6c0-1.035-0.263-2.009-0.726-2.86l12.829-12.829
c1.106,0.86,2.44,1.436,3.898,1.619v10.16c-2.833,0.478-5,2.942-5,5.91c0,3.309,2.691,6,6,6s6-2.691,6-6c0-2.967-2.167-5.431-5-5.91
v-10.16c1.458-0.183,2.792-0.759,3.898-1.619l7.669,7.669C41.215,39.576,41,40.26,41,41c0,2.206,1.794,4,4,4s4-1.794,4-4
s-1.794-4-4-4c-0.74,0-1.424,0.215-2.019,0.567l-7.669-7.669C36.366,28.542,37,26.846,37,25s-0.634-3.542-1.688-4.897l9.665-9.665
C46.042,11.405,47.451,12,49,12c3.309,0,6-2.691,6-6S52.309,0,49,0z M11,9c0-1.103,0.897-2,2-2s2,0.897,2,2s-0.897,2-2,2
S11,10.103,11,9z M6,51c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4S8.206,51,6,51z M33,49c0,2.206-1.794,4-4,4s-4-1.794-4-4
s1.794-4,4-4S33,46.794,33,49z M29,31c-3.309,0-6-2.691-6-6s2.691-6,6-6s6,2.691,6,6S32.309,31,29,31z M47,41c0,1.103-0.897,2-2,2
s-2-0.897-2-2s0.897-2,2-2S47,39.897,47,41z M49,10c-2.206,0-4-1.794-4-4s1.794-4,4-4s4,1.794,4,4S51.206,10,49,10z"></path></svg></div><div id="global-graph-outer"><div id="global-graph-container" data-cfg="{&quot;drag&quot;:true,&quot;zoom&quot;:true,&quot;depth&quot;:-1,&quot;scale&quot;:0.9,&quot;repelForce&quot;:0.5,&quot;centerForce&quot;:0.3,&quot;linkDistance&quot;:30,&quot;fontSize&quot;:0.6,&quot;opacityScale&quot;:1,&quot;showTags&quot;:true,&quot;removeTags&quot;:[]}"></div></div></div><div class="toc desktop-only"><button type="button" id="toc" class><h3>Table of Contents</h3><svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" class="fold"><polyline points="6 9 12 15 18 9"></polyline></svg></button><div id="toc-content"><ul class="overflow"><li class="depth-0"><a href="#acl-模型访问控制列表" data-for="acl-模型访问控制列表">ACL 模型:访问控制列表</a></li><li class="depth-0"><a href="#dac-模型自主访问控制" data-for="dac-模型自主访问控制">DAC 模型:自主访问控制</a></li><li class="depth-0"><a href="#mac-模型强制访问控制" data-for="mac-模型强制访问控制">MAC 模型:强制访问控制</a></li><li class="depth-0"><a href="#abac-模型基于属性的访问控制" data-for="abac-模型基于属性的访问控制">ABAC 模型:基于属性的访问控制</a></li><li class="depth-0"><a href="#rbac-基于角色的权限访问控制" data-for="rbac-基于角色的权限访问控制">RBAC 基于角色的权限访问控制</a></li><li class="depth-0"><a href="#rbac-的深度拓展" data-for="rbac-的深度拓展">RBAC 的深度拓展</a></li><li class="depth-1"><a href="#1-rbac0-模型" data-for="1-rbac0-模型">1. RBAC0 模型</a></li><li class="depth-1"><a href="#2-rbac1-模型" data-for="2-rbac1-模型">2. RBAC1 模型</a></li><li class="depth-1"><a href="#3-rbac2-模型" data-for="3-rbac2-模型">3. RBAC2 模型</a></li><li class="depth-1"><a href="#4-rbac3-模型" data-for="4-rbac3-模型">4. RBAC3 模型</a></li><li class="depth-0"><a href="#rbac-权限管理的在实际系统中的应用" data-for="rbac-权限管理的在实际系统中的应用">RBAC 权限管理的在实际系统中的应用</a></li><li class="depth-1"><a href="#1-用户管理" data-for="1-用户管理">1. 用户管理</a></li><li class="depth-1"><a href="#2-角色管理" data-for="2-角色管理">2. 角色管理</a></li><li class="depth-1"><a href="#3-权限管理" data-for="3-权限管理">3. 权限管理</a></li><li class="depth-0"><a href="#用户管理系统权限设计中的更多实践细节" data-for="用户管理系统权限设计中的更多实践细节">用户管理系统权限设计中的更多实践细节</a></li><li class="depth-1"><a href="#1-超级管理员" data-for="1-超级管理员">1. 超级管理员</a></li><li class="depth-1"><a href="#2-互斥角色如何处理" data-for="2-互斥角色如何处理">2. 互斥角色如何处理</a></li><li class="depth-1"><a href="#3-用户管理权限系统设计一定要简单清晰" data-for="3-用户管理权限系统设计一定要简单清晰">3. 用户管理权限系统设计一定要简单清晰</a></li><li class="depth-1"><a href="#4-无权提示页" data-for="4-无权提示页">4. 无权提示页</a></li></ul></div></div><div class="backlinks "><h3>Backlinks</h3><ul class="overflow"><li>No backlinks found</li></ul></div><div class="explorer mobile-only"><button type="button" id="explorer" data-behavior="collapse" data-collapsed="collapsed" data-savestate="true" data-tree="[{&quot;path&quot;:&quot;Obsidian&quot;,&quot;collapsed&quot;:true},{&quot;path&quot;:&quot;Obsidian/Templates&quot;,&quot;collapsed&quot;:true},{&quot;path&quot;:&quot;Personal&quot;,&quot;collapsed&quot;:true},{&quot;path&quot;:&quot;Personal/Blog&quot;,&quot;collapsed&quot;:true},{&quot;path&quot;:&quot;Personal/Blog/2018&quot;,&quot;collapsed&quot;:true},{&quot;path&quot;:&quot;Personal/Blog/2020&quot;,&quot;collapsed&
function toggleCallout() {
const outerBlock = this.parentElement;
outerBlock.classList.toggle(`is-collapsed`);
const collapsed = outerBlock.classList.contains(`is-collapsed`);
const height = collapsed ? this.scrollHeight : outerBlock.scrollHeight;
outerBlock.style.maxHeight = height + `px`;
let current = outerBlock;
let parent = outerBlock.parentElement;
while (parent) {
if (!parent.classList.contains(`callout`)) {
return;
}
const collapsed2 = parent.classList.contains(`is-collapsed`);
const height2 = collapsed2 ? parent.scrollHeight : parent.scrollHeight + current.scrollHeight;
parent.style.maxHeight = height2 + `px`;
current = parent;
parent = parent.parentElement;
}
}
function setupCallout() {
const collapsible = document.getElementsByClassName(
`callout is-collapsible`
);
for (const div of collapsible) {
const title = div.firstElementChild;
if (title) {
title.removeEventListener(`click`, toggleCallout);
title.addEventListener(`click`, toggleCallout);
const collapsed = div.classList.contains(`is-collapsed`);
const height = collapsed ? title.scrollHeight : div.scrollHeight;
div.style.maxHeight = height + `px`;
}
}
}
document.addEventListener(`nav`, setupCallout);
window.addEventListener(`resize`, setupCallout);
</script><script type="module">
import mermaid from 'https://cdn.jsdelivr.net/npm/mermaid/dist/mermaid.esm.min.mjs';
const darkMode = document.documentElement.getAttribute('saved-theme') === 'dark'
mermaid.initialize({
startOnLoad: false,
securityLevel: 'loose',
theme: darkMode ? 'dark' : 'default'
});
document.addEventListener('nav', async () => {
await mermaid.run({
querySelector: '.mermaid'
})
});
</script><script src="https://cdn.jsdelivr.net/npm/katex@0.16.7/dist/contrib/copy-tex.min.js" type="application/javascript"></script><script src="../../../../postscript.js" type="module"></script></html>