<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0"
	xmlns:content="http://purl.org/rss/1.0/modules/content/"
	xmlns:wfw="http://wellformedweb.org/CommentAPI/"
	xmlns:dc="http://purl.org/dc/elements/1.1/"
	xmlns:atom="http://www.w3.org/2005/Atom"
	xmlns:sy="http://purl.org/rss/1.0/modules/syndication/"
	xmlns:slash="http://purl.org/rss/1.0/modules/slash/"
	>

<channel>
	<title>潘锦的空间 &#187; 权限体系</title>
	<atom:link href="https://www.phppan.com/tag/%e6%9d%83%e9%99%90%e4%bd%93%e7%b3%bb/feed/" rel="self" type="application/rss+xml" />
	<link>https://www.phppan.com</link>
	<description>SaaS SaaS架构 团队管理 技术管理 技术架构 PHP 内核 扩展 项目管理</description>
	<lastBuildDate>Sat, 25 Apr 2026 00:56:17 +0000</lastBuildDate>
	<language>zh-CN</language>
		<sy:updatePeriod>hourly</sy:updatePeriod>
		<sy:updateFrequency>1</sy:updateFrequency>
	<generator>https://wordpress.org/?v=3.9.40</generator>
	<item>
		<title>做了 10 年SaaS 产品后，我总结的权限设计避坑指南</title>
		<link>https://www.phppan.com/2025/06/saas-permission-design/</link>
		<comments>https://www.phppan.com/2025/06/saas-permission-design/#comments</comments>
		<pubDate>Sat, 28 Jun 2025 08:39:10 +0000</pubDate>
		<dc:creator><![CDATA[admin]]></dc:creator>
				<category><![CDATA[架构和远方]]></category>
		<category><![CDATA[SaaS]]></category>
		<category><![CDATA[权限体系]]></category>

		<guid isPermaLink="false">https://www.phppan.com/?p=2387</guid>
		<description><![CDATA[做 SaaS 产品这么多年，我发现权限控制是个特别有意思的话题。说它简单吧，很多团队都做得奇奇怪怪；说它复杂吧 [&#8230;]]]></description>
				<content:encoded><![CDATA[<p style="color: #000000;" data-tool="mdnice编辑器">做 SaaS 产品这么多年，我发现权限控制是个特别有意思的话题。说它简单吧，很多团队都做得奇奇怪怪；说它复杂吧，掌握了核心原理后其实也就那么回事。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">如果你是产品经理、技术负责人，或者正在做 B 端产品的创业者，这篇文章可能会对你有一些帮助。今天咱们就聊聊 SaaS 产品里的权限控制，怎么设计、怎么实施、怎么避坑。</p>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">1 为什么权限控制这么重要</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">说个数据：2022 年 SaaS 安全报告显示，43% 的企业因为权限配置错误导致过数据泄露。而业内人士都知道，实际比例可能高达63%——很多公司出了事都选择悄悄处理，不对外声张（也能理解的）。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">再看一下 2020 年，微盟删库事件，一个运维人员因为跟公司有矛盾，趁着自己还有生产环境的管理员权限，直接把核心数据库给删了。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">300 万商家的店铺全部瘫痪，整整 7 天无法营业。正值疫情期间，很多商家本来就靠线上维持生计，这一下彻底断了收入来源。最后微盟赔偿了1.5亿，股价暴跌，品牌信誉更是一落千丈。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">事后复盘发现问题出在哪？</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">一个人就能删除生产数据库，没有任何审批流程</section>
</li>
<li>
<section style="color: #010101;">删除操作没有双人复核机制</section>
</li>
<li>
<section style="color: #010101;">权限过度集中，运维人员的权限大到离谱</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">以此作为警示：对 SaaS 行业来说，权限管理不是技术问题，是生死问题。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">为什么说权限问题往往比较致命？</p>
<p style="color: #000000;" data-tool="mdnice编辑器">做了这么多年 ToB 产品，我发现权限问题有几个特点：</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">1. 爆发性强</strong>：不像性能问题是逐渐恶化，权限问题是突然爆发。今天还好好的，明天就可能因为一个配置错误，导致全部客户数据泄露。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">2. 影响面广</strong>：一个权限漏洞，可能影响所有客户。特别是多租户架构，一个 bug 就能让所有租户的数据混在一起（如果在多租户逻辑中使用的是字段隔离，而且大部分 SaaS 产品是这样做的）。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">3. 修复成本高</strong>：早期设计不好，后期改造就是噩梦。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">4. 信任难恢复</strong>：客户把核心数据放在你的系统里，是基于信任。一旦出现权限问题，这种信任很难恢复。哪怕你后来改得再好，客户心里也会有阴影。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">权限控制是基础，这就像盖房子，地基不牢，楼盖得越高越危险。</p>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">2 权限控制的核心概念</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">在深入讨论之前，咱们先把几个基本概念理清楚。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">2.1 权限的本质是什么</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">说白了，权限就是回答一个问题：谁能对什么做什么操作？</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">谁：用户、角色、部门</section>
</li>
<li>
<section style="color: #010101;">什么：功能模块、数据对象、页面按钮</section>
</li>
<li>
<section style="color: #010101;">操作：查看、创建、编辑、删除、审批</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">这三个要素组合起来，就构成了权限控制的基础。比如「财务主管可以查看所有部门的报销单」，这就是一条权限规则。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">2.2 功能权限和数据权限</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">很多人容易把这俩混在一起，其实它们解决的是不同维度的问题。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">功能权限控制的是「能不能用这个功能」。比如普通员工看不到薪资管理模块，这就是功能权限。实现起来相对简单，一般在前端控制菜单显示，后端做接口校验就行。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">数据权限控制的是「能看到哪些数据」。同样是查看订单列表，销售 A 只能看自己的订单，销售主管能看整个团队的订单，老板能看全公司的订单。这就是数据权限，实现起来要复杂得多。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">有一个典型案例：某 CRM 系统，销售经理发现自己看不到下属的客户数据，一查才发现只做了功能权限，忘了做数据权限。结果所有销售经理都只能看到自己作为销售时录入的客户，管理功能形同虚设。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">2.3 权限的安全边界</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">做权限控制，安全永远是第一位的。我总结了几个容易踩坑的地方：</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">前端权限不可信</strong>：永远不要只在前端做权限判断，哪怕把按钮隐藏了，懂技术的人照样能通过开发者工具发请求。所有权限判断必须在后端再做一遍。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">默认拒绝原则</strong>：权限设计应该是「没有明确允许的都是禁止的」，而不是「没有明确禁止的都是允许的」。这个原则能避免很多安全漏洞。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">最小权限原则</strong>：给用户的权限应该刚好够用就行，不要为了方便给过多权限。特别是生产环境的管理员权限，能不给就不给，给了也要有审计日志。</p>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">3 三种主流权限模型</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">聊完基础概念，咱们来看看业界常用的几种权限模型。每种模型都有自己的适用场景，没有绝对的好坏。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">3.1 ACL</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">ACL，访问控制列表，是最直观的权限模型，直接定义「用户-资源-权限」的对应关系。比如：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">张三可以编辑文档 A</section>
</li>
<li>
<section style="color: #010101;">李四可以查看文件夹 B</section>
</li>
<li>
<section style="color: #010101;">王五可以删除报表 C</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">优点是简单直接，实现容易。早期的文件系统、简单的内容管理系统多用这种模型。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">缺点也很明显：用户一多就没法管理了。假设你有 1000 个用户，100 个资源，每个资源有 5 种操作权限，理论上你需要维护 50 万条权限记录。更要命的是，新员工入职你得一个个配置权限，员工离职你得一个个回收权限，运维成本极高。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">所以 ACL 一般只适合用户量少、权限关系简单的场景。如果你的 SaaS 产品用户量大，还是趁早换其他模型。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">3.2 RBAC</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">RBAC，基于角色的访问控制，是目前最主流的权限模型，核心思想是引入「角色」这个中间层。用户不直接拥有权限，而是通过角色来获得权限。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">比如定义几个角色：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">销售员：可以查看和编辑自己的客户、订单</section>
</li>
<li>
<section style="color: #010101;">销售主管：可以查看和编辑本部门所有客户、订单，可以查看销售报表</section>
</li>
<li>
<section style="color: #010101;">财务人员：可以查看所有订单，可以开具发票，可以查看财务报表</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">新员工入职，只需要给他分配对应角色就行了。角色的权限变了，所有该角色的用户权限自动更新。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">RBAC 还可以细分为四种类型，实际应用中按需选择：</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">RBAC0（基本模型）</strong>：最简单的实现，用户-角色-权限三层结构。大部分中小型 SaaS 产品用这个就够了。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">RBAC1（角色分层模型）</strong>：角色可以继承。比如「销售主管」自动继承「销售员」的所有权限，再加上管理权限。这样可以减少重复配置。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">RBAC2（角色限制模型）</strong>：增加了约束条件。比如「角色互斥」（一个用户不能既是采购员又是审批员），「角色数量限制」（一个用户最多只能有 3 个角色）等。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">RBAC3（统一模型）</strong>：集成了 RBAC1 和 RBAC2 的所有特性，最完整但也最复杂。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">我的建议是从 RBAC0 开始，随着业务发展再考虑升级。过度设计只会增加系统复杂度。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">3.3 ABAC</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">ABAC，基于属性的访问控制，是相对较新的模型，通过属性组合来判断权限。这些属性可以来自：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">用户属性：部门、职级、工龄、地域</section>
</li>
<li>
<section style="color: #010101;">资源属性：类型、创建者、敏感度、标签</section>
</li>
<li>
<section style="color: #010101;">环境属性：时间、地点、设备类型</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">举个例子：&#8221;华东区的销售经理在工作时间可以查看本区域高价值客户的信息&#8221;。这条规则涉及了用户的地域属性、角色属性，资源的地域属性、价值属性，以及时间这个环境属性。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">ABAC 的优势是灵活性极高，可以实现非常精细的权限控制。缺点是实现复杂，性能开销大，权限规则难以理解和调试。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">一般来说，如果你的业务场景确实需要这么复杂的权限控制（比如医疗、金融等强监管行业），可以考虑 ABAC。否则 RBAC 就足够了。</p>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">4 SaaS 产品的特殊挑战</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">相比传统的企业内部系统，SaaS 产品在权限控制上面临一些独特的挑战。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">4.1 多租户隔离</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">这是 SaaS 最核心的需求。同一套系统里住着几百上千家企业，必须保证数据完全隔离。A 公司的员工绝对不能看到 B 公司的任何数据。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">常见的隔离方案有三种：</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">独立数据库</strong>：每个租户一个数据库。隔离性最好，但成本高，难以维护。适合大客户少量部署的场景。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">共享数据库、独立 Schema</strong>：每个租户一个 Schema。隔离性不错，成本适中。适合中等规模的 SaaS 产品。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">共享数据库、共享表</strong>：所有租户的数据都在同一张表里，通过 tenant_id 字段区分。成本最低，但要特别小心 SQL 注入和权限泄露。这是大部分 SaaS 产品的选择。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">如果采用第三种方案，一定要在所有 SQL 查询中强制加上 tenant_id 条件。我见过的好做法是在 ORM 层面做全局过滤器，或者在数据库层面用行级安全策略（Row Level Security）。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">4.2 组织架构的映射</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">企业客户通常都有复杂的组织架构，我们的权限系统必须能够映射这种结构。常见的需求包括：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">树形部门结构，支持多层级</section>
</li>
<li>
<section style="color: #010101;">一个人可能属于多个部门（兼职、虚拟团队）</section>
</li>
<li>
<section style="color: #010101;">临时授权（代理、请假）</section>
</li>
<li>
<section style="color: #010101;">按项目组、按地域等多维度的权限控制</section>
</li>
<li>
<section style="color: #010101;">集团，公公司等逻辑</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">我的经验是，组织架构不要做得太复杂，够用就行。很多企业其实就是简单的部门层级 + 角色，硬要上矩阵式组织、事业部制这些复杂结构，反而增加了使用成本。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">4.3 权限的动态性</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">SaaS 产品的权限需求经常变化：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">新功能上线，需要新的权限点</section>
</li>
<li>
<section style="color: #010101;">客户要求定制化的权限规则</section>
</li>
<li>
<section style="color: #010101;">不同行业、不同规模的客户，权限需求差异很大</section>
</li>
</ul>
<p style="color: #000000;" data-tool="mdnice编辑器">所以权限系统必须设计得足够灵活。我推荐的做法是：</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">权限点动态化</strong>：不要把权限点写死在代码里，而是存在数据库里，通过配置来管理。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">规则引擎</strong>：对于复杂的权限判断逻辑，可以引入规则引擎，让权限规则可以通过配置来调整。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">权限模板</strong>：为不同类型的客户准备权限模板，新客户注册时可以快速初始化。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">4.4 性能优化</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">权限判断是高频操作，一个页面可能要判断几十上百个权限点。如果每次都查数据库，性能肯定扛不住。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">常用的优化手段：</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">缓存</strong>：用户登录时把权限信息缓存到 Redis，设置合理的过期时间。权限变更时主动刷新缓存。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">权限位图</strong>：把权限用位图来表示，一个 long 型变量可以表示 64 个权限点，判断权限只需要位运算。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">懒加载</strong>：不要一次性加载所有权限，而是按需加载。比如用户进入某个模块才加载该模块的权限。</p>
<p style="color: #000000;" data-tool="mdnice编辑器"><strong style="color: #0e88eb;">预计算</strong>：对于数据权限，可以预先计算好用户能访问的数据 ID 列表，查询时直接用 IN 条件。</p>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">5 设计一个权限系统</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">说了这么多理论，咱们来点实际的。假设你要为一个 SaaS CRM 系统设计权限控制，应该怎么做？</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">5.1 需求分析</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">首先要搞清楚业务需求：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">系统有哪些功能模块？客户管理、订单管理、报表分析等</section>
</li>
<li>
<section style="color: #010101;">有哪些角色？销售员、销售主管、客服、财务、管理员等</section>
</li>
<li>
<section style="color: #010101;">数据权限如何划分？按部门、按区域、按客户等级等</section>
</li>
<li>
<section style="color: #010101;">有哪些特殊需求？审批流程、临时授权、数据导出限制等</section>
</li>
</ul>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">5.2 模型选择</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">对于 CRM 这种相对标准的业务系统，RBAC 是首选。具体用 RBAC0 还是 RBAC1，看企业规模：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">中小企业：RBAC0 足够，角色数量有限，权限关系简单</section>
</li>
<li>
<section style="color: #010101;">大型企业：考虑 RBAC1，利用角色继承减少配置工作</section>
</li>
</ul>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">5.3 数据库设计</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">核心表结构：</p>
<pre style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><code style="color: #abb2bf;"><span style="font-style: italic; color: #5c6370;">-- 用户表</span>
<span style="color: #c678dd;">CREATE</span><span style="color: #c678dd;">TABLE</span><span style="color: #c678dd;">users</span> (
    <span style="color: #c678dd;">id</span><span style="color: #e6c07b;">BIGINT</span> PRIMARY <span style="color: #c678dd;">KEY</span>,
    tenant_id <span style="color: #e6c07b;">BIGINT</span><span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    username <span style="color: #e6c07b;">VARCHAR</span>(<span style="color: #d19a66;">50</span>) <span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    <span style="font-style: italic; color: #5c6370;">-- 其他字段...</span>
    <span style="color: #c678dd;">INDEX</span> idx_tenant (tenant_id)
);

<span style="font-style: italic; color: #5c6370;">-- 角色表</span>
<span style="color: #c678dd;">CREATE</span><span style="color: #c678dd;">TABLE</span><span style="color: #c678dd;">roles</span> (
    <span style="color: #c678dd;">id</span><span style="color: #e6c07b;">BIGINT</span> PRIMARY <span style="color: #c678dd;">KEY</span>,
    tenant_id <span style="color: #e6c07b;">BIGINT</span><span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    role_name <span style="color: #e6c07b;">VARCHAR</span>(<span style="color: #d19a66;">50</span>) <span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    parent_id <span style="color: #e6c07b;">BIGINT</span>, <span style="font-style: italic; color: #5c6370;">-- 用于角色继承</span>
    <span style="font-style: italic; color: #5c6370;">-- 其他字段...</span>
    <span style="color: #c678dd;">INDEX</span> idx_tenant (tenant_id)
);

<span style="font-style: italic; color: #5c6370;">-- 权限表</span>
<span style="color: #c678dd;">CREATE</span><span style="color: #c678dd;">TABLE</span> permissions (
    <span style="color: #c678dd;">id</span><span style="color: #e6c07b;">BIGINT</span> PRIMARY <span style="color: #c678dd;">KEY</span>,
    permission_code <span style="color: #e6c07b;">VARCHAR</span>(<span style="color: #d19a66;">100</span>) <span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>, <span style="font-style: italic; color: #5c6370;">-- 如 'customer.view'</span>
    permission_name <span style="color: #e6c07b;">VARCHAR</span>(<span style="color: #d19a66;">100</span>) <span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    <span style="color: #c678dd;">module</span><span style="color: #e6c07b;">VARCHAR</span>(<span style="color: #d19a66;">50</span>), <span style="font-style: italic; color: #5c6370;">-- 所属模块</span>
    <span style="font-style: italic; color: #5c6370;">-- 其他字段...</span>
    <span style="color: #c678dd;">UNIQUE</span><span style="color: #c678dd;">KEY</span> uk_code (permission_code)
);

<span style="font-style: italic; color: #5c6370;">-- 用户-角色关联表</span>
<span style="color: #c678dd;">CREATE</span><span style="color: #c678dd;">TABLE</span> user_roles (
    user_id <span style="color: #e6c07b;">BIGINT</span><span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    role_id <span style="color: #e6c07b;">BIGINT</span><span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    PRIMARY <span style="color: #c678dd;">KEY</span> (user_id, role_id)
);

<span style="font-style: italic; color: #5c6370;">-- 角色-权限关联表</span>
<span style="color: #c678dd;">CREATE</span><span style="color: #c678dd;">TABLE</span> role_permissions (
    role_id <span style="color: #e6c07b;">BIGINT</span><span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    permission_id <span style="color: #e6c07b;">BIGINT</span><span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    PRIMARY <span style="color: #c678dd;">KEY</span> (role_id, permission_id)
);

<span style="font-style: italic; color: #5c6370;">-- 数据权限规则表</span>
<span style="color: #c678dd;">CREATE</span><span style="color: #c678dd;">TABLE</span> data_permissions (
    <span style="color: #c678dd;">id</span><span style="color: #e6c07b;">BIGINT</span> PRIMARY <span style="color: #c678dd;">KEY</span>,
    role_id <span style="color: #e6c07b;">BIGINT</span><span style="color: #c678dd;">NOT</span><span style="color: #56b6c2;">NULL</span>,
    resource_type <span style="color: #e6c07b;">VARCHAR</span>(<span style="color: #d19a66;">50</span>), <span style="font-style: italic; color: #5c6370;">-- 如 'customer', 'order'</span>
    rule_type <span style="color: #e6c07b;">VARCHAR</span>(<span style="color: #d19a66;">50</span>), <span style="font-style: italic; color: #5c6370;">-- 如 'self', 'department', 'all'</span>
    rule_value <span style="color: #e6c07b;">TEXT</span>, <span style="font-style: italic; color: #5c6370;">-- 具体规则，可以是 JSON</span>
    <span style="color: #c678dd;">INDEX</span> idx_role (role_id)
);
</code></pre>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">6 避坑指南</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">做了这么多项目，我总结了一些常见的坑，希望你能避开：</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">6.1 过度设计</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">最常见的错误就是一上来就想做一个「完美」的权限系统。支持 ABAC、支持动态规则、支持工作流集成&#8230; 结果做了半年还没上线，业务等不及了。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">记住，权限系统是为业务服务的，不是为了秀技术。先满足基本需求，再逐步迭代。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">6.2 忽视性能</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">另一个常见问题是只关注功能，不关注性能。权限判断是高频操作，如果每次都要查十几张表，系统很快就会崩溃。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">一定要做好缓存，关键接口要做压测。我的经验是，权限判断的响应时间应该控制在 10ms 以内。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">6.3 权限配置过于复杂</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">有些系统的权限配置界面，复杂得连开发人员都搞不清楚。这样的系统，客户是不会用的。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">权限配置要尽量简化，提供合理的默认值和模板。最好能提供权限检查工具，让管理员可以模拟某个用户的权限，看看到底能访问哪些功能和数据。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">6.4 缺少审计日志</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">权限系统必须有完善的审计日志，记录谁在什么时候做了什么操作。特别是权限的授予和回收，必须有据可查。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">这不仅是安全需要，很多行业还有合规要求。审计日志最好是独立存储，防止被篡改。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">6.5 数据权限的 N+1 问题</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">实现数据权限时，很容易出现 N+1 查询问题。比如查询订单列表，每个订单都要判断一次是否有权限查看，结果一个列表页产生了上百次数据库查询。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">解决方案是在列表查询时就加入权限过滤条件，而不是查出来再过滤。这需要在 SQL 层面就考虑权限问题。</p>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">7 其它一些变化</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">权限控制这个领域，这几年也有一些新的发展趋势：</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">7.1 Zero Trust 模型</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">Zero Trust 模型就是我们常说的零信任模型。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">传统的权限模型是「城堡式」的：进了城门（登录系统）就基本畅通无阻。Zero Trust 模型要求每次访问都要验证权限，不管你是内部用户还是外部用户。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">这对 SaaS 产品来说特别重要，因为用户可能从任何地方、任何设备访问系统。</p>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">7.2 AI 辅助的权限管理</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">利用机器学习来优化权限配置，比如：</p>
<ul class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">根据用户行为自动推荐合适的角色</section>
</li>
<li>
<section style="color: #010101;">检测异常的权限使用，可能是账号被盗用</section>
</li>
<li>
<section style="color: #010101;">自动发现权限配置中的冲突和冗余</section>
</li>
</ul>
<h2 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">7.3 细粒度的数据权限</span></h2>
<p style="color: #000000;" data-tool="mdnice编辑器">不仅控制能不能看某条数据，还要控制能看到数据的哪些字段。比如普通销售能看到客户的基本信息，但看不到信用额度；财务能看到信用额度，但看不到跟进记录。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">这需要在字段级别做权限控制，实现起来更复杂，但确实是一些行业的刚需。</p>
<h1 style="color: rgba(0, 0, 0, 0.9);" data-tool="mdnice编辑器"><span style="font-weight: bold; color: #0e8aeb;">8 写在最后</span></h1>
<p style="color: #000000;" data-tool="mdnice编辑器">权限控制是 SaaS 产品的基础设施，做好了用户感知不到，做不好用户骂声一片。它不是一个能带来直接收益的功能，但却是产品能否长期发展的关键。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">我的建议是：</p>
<ol class="list-paddingleft-1" style="color: #000000;">
<li>
<section style="color: #010101;">不要等到出问题才重视权限，一开始就要规划好</section>
</li>
<li>
<section style="color: #010101;">选择适合自己业务的权限模型，不要过度设计</section>
</li>
<li>
<section style="color: #010101;">功能权限和数据权限要分开考虑，都很重要</section>
</li>
<li>
<section style="color: #010101;">做好性能优化和安全防护，这是基本要求</section>
</li>
<li>
<section style="color: #010101;">保持系统的灵活性，因为需求一定会变</section>
</li>
</ol>
<p style="color: #000000;" data-tool="mdnice编辑器">技术是为业务服务的。不要为了炫技而把简单问题复杂化，也不要为了省事而在安全问题上偷懒。在这两者之间找到平衡，才是一个成熟的技术方案。</p>
<p style="color: #000000;" data-tool="mdnice编辑器">以上。</p>
]]></content:encoded>
			<wfw:commentRss>https://www.phppan.com/2025/06/saas-permission-design/feed/</wfw:commentRss>
		<slash:comments>0</slash:comments>
		</item>
	</channel>
</rss>
