2. 身份认证与访问控制:OAuth2.0与SSO集成、RBAC/ABAC权限模型、多因素认证(MFA)实现

好,咱们进入第二个核心章节。身份认证和访问控制,说白了就是解决两个问题:「你是谁」「你能干什么」。在低代码平台里,这两个问题尤其棘手——因为你的用户可能是内部员工,也可能是外部客户,甚至可能是第三方系统。

我见过不少团队,一开始图省事,直接用用户名密码加一个简单的角色判断。结果呢?上线不到三个月,权限漏洞就爆出来了。嗯,这里咱们得把地基打牢。

2.1 OAuth2.0 与 SSO 集成:别让用户反复登录

先聊单点登录(SSO)。你想想看,一个企业用低代码平台搭了十几个应用,用户每进一个应用就要输一次密码,这体验得多糟糕。SSO 就是为了解决这个痛点——一次登录,全网通行

我个人习惯用 OAuth2.0 作为 SSO 的底层协议。为什么?因为它成熟、灵活,而且各大云厂商都支持。

2.1.1 OAuth2.0 的四种授权模式

这里我简单列一下,你心里有个数就行:

授权模式 适用场景 安全等级
授权码模式(Authorization Code) 有后端的 Web 应用
隐式模式(Implicit) 纯前端 SPA 应用(已不推荐)
密码模式(Resource Owner Password) 高度信任的第一方应用
客户端模式(Client Credentials) 服务间调用、M2M 通信

我在项目中遇到过最典型的坑:有人把密码模式用在第三方登录上。结果用户的密码明文传到了第三方服务器,这等于把家门的钥匙直接给了外人。千万别这么干。

2.1.2 集成 SSO 的推荐做法

我建议低代码平台优先支持 授权码模式 + PKCE(Proof Key for Code Exchange)。PKCE 是给移动端和 SPA 用的增强方案,能防止授权码被拦截。

下面是一个简化的集成流程:

// 前端发起登录请求
GET /oauth2/authorize?
  response_type=code&
  client_id=lowcode_app&
  redirect_uri=https://app.example.com/callback&
  code_challenge=xxxxx&
  code_challenge_method=S256

// 用户授权后,后端用 code 换取 token
POST /oauth2/token
Content-Type: application/x-www-form-urlencoded

grant_type=authorization_code&
code=授权码&
client_id=lowcode_app&
client_secret=客户端密钥&
redirect_uri=https://app.example.com/callback&
code_verifier=原始验证码
我的经验: 记得给 token 设置合理的过期时间。Access Token 建议 15-30 分钟,Refresh Token 可以长一些,比如 7 天。太短了用户频繁重登,太长了安全风险大。

2.2 RBAC/ABAC 权限模型:精细到按钮级别

权限模型这块,低代码平台比传统应用复杂得多。因为你的用户可能是动态创建的,角色也可能是自定义的。我一般把权限分为两层:粗粒度用 RBAC,细粒度用 ABAC

2.2.1 RBAC:角色是权限的集合

RBAC(基于角色的访问控制)是最常用的模型。核心思想很简单:用户 → 角色 → 权限。你给用户分配一个「管理员」角色,他就拥有了管理员的所有权限。

在低代码平台里,我建议这样设计数据表:

-- 用户表
CREATE TABLE users (
  id INT PRIMARY KEY,
  username VARCHAR(50),
  department_id INT
);

-- 角色表
CREATE TABLE roles (
  id INT PRIMARY KEY,
  role_name VARCHAR(50),  -- 如:admin, editor, viewer
  description TEXT
);

-- 用户-角色关联表
CREATE TABLE user_roles (
  user_id INT,
  role_id INT,
  PRIMARY KEY (user_id, role_id)
);

-- 权限表
CREATE TABLE permissions (
  id INT PRIMARY KEY,
  resource VARCHAR(100),  -- 如:report, dashboard
  action VARCHAR(50)      -- 如:create, read, update, delete
);

-- 角色-权限关联表
CREATE TABLE role_permissions (
  role_id INT,
  permission_id INT,
  PRIMARY KEY (role_id, permission_id)
);
避坑指南: 我曾经见过一个项目,角色和权限直接硬编码在代码里。结果客户说「我要给张三加一个导出报表的权限,但不给他看报表详情」。嗯,改代码吧。所以权限一定要做成可配置的。

2.2.2 ABAC:基于属性的动态控制

RBAC 有个硬伤:它只能控制「谁」能做什么,但控制不了「在什么条件下」能做。比如:「销售经理只能查看自己部门的订单」,这就不是 RBAC 能简单搞定的。

这时候就需要 ABAC(基于属性的访问控制)。ABAC 的决策依据是属性,包括:

  • 用户属性: 部门、职级、区域
  • 资源属性: 数据所属部门、创建时间、敏感等级
  • 环境属性: 访问时间、IP 地址、设备类型

举个例子,一条 ABAC 策略可以写成:

// 策略:销售经理只能在工作时间查看本部门的订单
{
  "effect": "allow",
  "condition": {
    "user.department": "sales",
    "user.role": "manager",
    "resource.department": "user.department",
    "environment.time": "09:00-18:00"
  }
}

我建议低代码平台这样设计:RBAC 做主体框架,ABAC 做补充规则。先通过 RBAC 判断用户有没有「查看订单」的权限,再通过 ABAC 判断他能不能看「这个订单」。

2.3 多因素认证(MFA)实现:加一把锁

光靠密码认证,说实话,风险太大了。密码泄露、撞库攻击、钓鱼网站……随便一个就能让平台沦陷。MFA 就是再加一把锁——你知道的(密码)+ 你拥有的(手机/硬件密钥)+ 你本身的(指纹/人脸)

2.3.1 常见的 MFA 方式

因素类型 常见实现 安全等级 用户体验
短信验证码 发送 6 位数字到手机
TOTP(基于时间的一次性密码) Google Authenticator、Authy 较好
推送通知 Duo Security、Microsoft Authenticator 优秀
硬件密钥 YubiKey、FIDO2 极高 一般

我个人最推荐 TOTP + 推送通知 的组合。短信验证码虽然方便,但容易被 SIM 卡劫持。硬件密钥最安全,但部署成本高,适合高安全场景。

2.3.2 在低代码平台中集成 TOTP

TOTP 的实现其实不复杂,核心就是共享一个密钥,然后基于当前时间生成 6 位数字。下面是一个简化的 Java 实现:

import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.security.GeneralSecurityException;
import java.time.Instant;

public class TOTPGenerator {

    // 生成 TOTP 码
    public static String generateTOTP(String secret, long timeStep) {
        try {
            // 1. 将 Base32 编码的密钥解码
            byte[] key = Base32.decode(secret);
            
            // 2. 计算时间计数器
            long counter = Instant.now().getEpochSecond() / timeStep;
            
            // 3. 使用 HMAC-SHA1 生成哈希
            Mac mac = Mac.getInstance("HmacSHA1");
            SecretKeySpec spec = new SecretKeySpec(key, "HmacSHA1");
            mac.init(spec);
            byte[] hash = mac.doFinal(longToBytes(counter));
            
            // 4. 截取 6 位数字
            int offset = hash[hash.length - 1] & 0x0F;
            int binary = ((hash[offset] & 0x7F) << 24) |
                         ((hash[offset + 1] & 0xFF) << 16) |
                         ((hash[offset + 2] & 0xFF) << 8) |
                         (hash[offset + 3] & 0xFF);
            int otp = binary % 1000000;
            
            return String.format("%06d", otp);
        } catch (GeneralSecurityException e) {
            throw new RuntimeException("TOTP 生成失败", e);
        }
    }
}
注意: 密钥的存储一定要加密。我曾经见过有人把密钥明文存在数据库里,结果数据库被拖库,所有用户的 TOTP 密钥都暴露了。建议使用 AES-256 加密存储,或者用硬件安全模块(HSM)。

2.3.3 MFA 的降级与恢复

这里有个现实问题:用户手机丢了怎么办?你不能让他永远登不进去。我建议提供以下恢复机制:

  • 备用恢复码: 在启用 MFA 时生成 10 个一次性恢复码,让用户保存好
  • 管理员重置: 通过工单系统,由管理员验证身份后重置 MFA
  • 备用邮箱验证: 发送验证码到备用邮箱,临时绕过 MFA

嗯,这里要特别提醒:恢复流程本身也要安全。不能随便一个人打电话说「我手机丢了」就给重置,必须有多重验证。

2.4 总结一下

身份认证和访问控制,是低代码平台安全的第一道防线。我个人的建议是:

  1. SSO 用 OAuth2.0 授权码模式 + PKCE,别图省事用密码模式
  2. 权限模型用 RBAC 打底,ABAC 做精细化控制,别把所有逻辑写死在代码里
  3. MFA 必须上,优先 TOTP 或推送通知,同时准备好恢复机制

下一章咱们聊聊数据安全——加密、脱敏、审计日志,这些才是真正让攻击者头疼的东西。