复杂场景下的权限系统该怎么玩?ABAC权限模型帮你搞定它!

ABAC - 基于属性的访问控制 - 复杂场景下访问控制解决之道 引言 引言 在一个典型的软件开发场景中,你作为一名开发人员加入到某个项目后,假设是“超人组”,你往往需要访问这个项目的代码库然后才能开始工作。当你的 Team Lead 将你加入 Git Organization 后,你自然可以访问到“超人组”的代码仓库,然后就可以愉快的进行开发工作了。但是,当你的任务完成后,可能你需要参与另一个项目,你自然就没有权利去访问“超人组”的代码库,所以你的 TL 会将... 阅读详情

点击上方“芋道源码”,选择“设为星标”

管她前浪,还是后浪?

能浪的浪,才是好浪!

每天 10:33 更新文章,每天掉亿点点头发...

源码精品专栏

 

来源:Java知音


ABAC授权模型

基于属性的访问控制(ABAC)- 阿里云IDaaS:

  • https://help.aliyun.com/document_detail/174235.html

ABAC- 百度百科:

  • https://baike.baidu.com/item/abac/3555041?fr=aladdin

个人觉得这两篇文章已经完美描述了ABAC模型的原理

常用的授权模型

此节摘自基于属性的访问控制(ABAC)- 阿里云IDaaS

  • ACL(Access Control List)

在ACL中,包含用户、资源、资源操作 三个关键要素。通过将资源以及资源操作授权给用户而使用户获取对资源进行操作的权限。

  • RBAC(Role-Based Access Control )

是把用户按角色进行归类,通过用户的角色来确定用户能否针对某项资源进行某项操作。RBAC相对于ACL最大的优势就是它简化了用户与权限的管理,通过对用户进行分类,使得角色与权限关联起来,而用户与权限变成了间接关联。

  • ABAC(Attribute Base Access Control)

基于属性的权限控制不同于常见的将用户通过某种方式关联到权限的方式,ABAC则是通过动态计算一个或一组属性来是否满足某种条件来进行授权判断(可以编写简单的逻辑)。

属性通常来说分为四类:用户属性(如用户年龄),环境属性(如当前时间),操作属性(如读取)和对象属性,所以理论上能够实现非常灵活的权限控制,几乎能满足所有类型的需求。

ABAC的访问控制

基于ABAC访问控制需要动态计算实体的属性、操作类型、相关的环境来控制是否有对操作对象的权限,所以在设计的时候需要考虑的条件判断的灵活性、通用性、易用性,用户只需要通过web页面即可配置授权,这需要减少硬编码似得逻辑变得简单通用,那么这需要满足一些运算符来实现。

类型运算符
算术运算符+, -, *, /, %, ^, div, mod
关系运算符<, >, ==, !=, <=, >=, lt, gt, eq, ne, le, ge
逻辑运算符and, or, not, &&,  ||, !
条件?:

使用场景

用户只需要配置 user.age > 20 的条件即可获得特定的权限。

表达式语言

正如上一节所说的需要对某种条件进行解析那么就需要表达式语言,这让我想起了Spring Framework的@Value注解和MyBatis的<if test=“”>

// 相信很多 Java boy都使用过的吧
@Value("A?B:C")
private String A;
<select id = "XXX">
    <if test="user != null">
        XXXX
    </if>
</select>

看到这里大家应该大致猜到了ABAC的的核心就是Expression Language(EL),虽然上面的代码演示是使用Java生态作为演示,但是可以大胆的相信其他的编程语言都是有着自己的EL框架的。

java EL框架列表

  • spring-expression

  • OGNL

  • MVEL

  • JBoss EL

这里就不一一列举了感兴趣可以查看 Java EL生态排名:

https://mvnrepository.com/open-source/expression-languages

SpEL性能

Spring Expression Language (SpEL)官方文档:

https://docs.spring.io/spring-framework/docs/current/reference/html/core.html#expressions

Spring官方文档摘取 翻译

Spring Framework 4.1 包含一个基本的表达式编译器。表达式通常被解释,这在评估期间提供了很多动态灵活性,但没有提供最佳性能。对于偶尔的表达式使用,这很好,但是,当由其他组件(如 Spring Integration)使用时,性能可能非常重要,并且没有真正需要动态性。

SpEL 编译器旨在满足这一需求。在求值期间,编译器生成一个 Java 类,它体现了运行时的表达式行为,并使用该类来实现更快的表达式求值。由于缺少表达式周围的类型,编译器在执行编译时使用在表达式的解释评估期间收集的信息。例如,它不能纯粹从表达式中知道属性引用的类型,但在第一次解释评估期间,它会找出它是什么。当然,如果各种表达式元素的类型随时间发生变化,基于此类派生信息进行编译可能会在以后造成麻烦。出于这个原因,编译最适合其类型信息在重复计算时不会改变的表达式。

考虑以下基本表达式:

someArray[0].someProperty.someOtherProperty < 0.1

由于前面的表达式涉及数组访问、某些属性取消引用和数字操作,因此性能提升非常显着。在一个运行 50000 次迭代的微型基准测试示例中,使用解释器评估需要 75 毫秒,使用表达式的编译版本仅需要 3 毫秒。

有关SpEL的性能Spring官方描述说SpEL的性能很棒(个人感觉Spring对自己的测试结果是不是少打了一个0啊,3ms的时间有点无法理解)

基于 Spring Boot + MyBatis Plus + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能

  • 项目地址:https://github.com/YunaiV/ruoyi-vue-pro

  • 视频教程:https://doc.iocoder.cn/video/

ABAC实践

本章仅实现ABAC的原理,不会对Spring Security和 Apache Shiro做任何的集成

因为笔者本人是一位Spring boy,所以工程项目会以Spring Boot框架作为基础,使用其它编程语言的同学可能需要受苦一下了😂, 大家看懂原理就可以了。

  • Java 8

  • Spring Boot 2.7.6

  • MyBatis Plus 3.5.2

  • MySQL 8.0

数据库设计

80009fe4d705fdae87dced3657b66eb1.png
图片
表名作用
user用户表(ACL和RBAC都有这张表)
user_contribution用户的附属信息 (用户属性之类的,不能不一定只有这张表)
permission权限表达式(ACL和RBAC都有这张表)
abacrbac表达式
abac_permissionrbac表达式和权限的绑定关系, o2m
> 基于 Spring Cloud Alibaba + Gateway + Nacos + RocketMQ + Vue & Element 实现的后台管理系统 + 用户小程序,支持 RBAC 动态权限、多租户、数据权限、工作流、三方登录、支付、短信、商城等功能
>
> * 项目地址:<https://github.com/YunaiV/yudao-cloud>
> * 视频教程:<https://doc.iocoder.cn/video/>

# 用户表
DROP TABLE if EXISTS user;
CREATE TABLE user (
    id bigint(20) NOT NULL COMMENT '主键ID',
    name varchar(30) NULL DEFAULT NULL COMMENT '姓名',
    age int(11) NULL DEFAULT NULL COMMENT '年龄',
    email varchar(50) NULL DEFAULT NULL COMMENT '邮箱',
    PRIMARY KEY (id)
);
# 用户边缘数据
DROP TABLE if EXISTS user_contribution;
CREATE TABLE user_contribution (
    id bigint(20) NOT NULL COMMENT '主键ID',
    user_id bigint(20)  NOT NULL COMMENT '用户表ID',
    repository varchar(100) NOT NULL COMMENT '仓库',
    PRIMARY KEY (id)
);
# 权限表
DROP TABLE if EXISTS permission;
CREATE TABLE permission (
    id bigint(20) NOT NULL COMMENT '主键ID',
    permission varchar(100) NOT NULL COMMENT '权限名称',
    PRIMARY KEY (id)
);
# abac表达式表
DROP TABLE if EXISTS abac;
CREATE TABLE abac (
    id bigint(20) NOT NULL COMMENT '主键ID',
    expression varchar(100) NOT NULL COMMENT 'abac表达式',
    PRIMARY KEY (id)
);
# abac表和权限表的关联表, o2m
DROP TABLE if EXISTS abac_permission;
CREATE TABLE abac_permission (
    id bigint(20) NOT NULL COMMENT '主键ID',
    abac_id bigint(20) NOT NULL COMMENT 'abac表ID',
    permission_id bigint(20) NOT NULL COMMENT 'permission表ID',
    PRIMARY KEY (id)
);

java程序

因为篇幅问题, 只会使用必要的代码, 代码文件结构

|src
 | |test
 | | |java
 | | | |plus.wcj.abac.AbacApplicationTests.java  测试类代码
 | |main
 | | |resources
 | | | |application.yml
 | | | |db
 | | | | |schema-h2.sql // DDL
 | | | | |data-h2.sql // DML
 | | |java
 | | | |plus.wcj.abac
 | | | | | | |AbacApplication.java // Spring Boot启动类
 | | | | | | |security
 | | | | | | | |MetadataCustomizer.java // 自定义user信息
 | | | | | | | |SecurityContext.java  // Security上下文
 | | | | | | |entity
 | | | | | | | |Abac.java
 | | | | | | | |User.java
 | | | | | | |dao
 | | | | | | | |UserDao.java
 | | | | | | | |AbacDao.java
 | | | | | | |service
 | | | | | | | |UserService.java
 | | | | | | | |AbacService.java
 |pom.xml
crud代码

pom.xml

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter</artifactId>
    </dependency>

    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-test</artifactId>
        <scope>test</scope>
    </dependency>

    <dependency>
        <groupId>com.baomidou</groupId>
        <artifactId>mybatis-plus-boot-starter</artifactId>
        <version>3.5.2</version>
    </dependency>

    <dependency>
        <groupId>mysql</groupId>
        <artifactId>mysql-connector-java</artifactId>
    </dependency>

    <dependency>
        <groupId>org.projectlombok</groupId>
        <artifactId>lombok</artifactId>
        <scope>compile</scope>
    </dependency>
</dependencies>

entity类

/**
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
@Data
public class Abac {
    private Long id;
    private String expression;

    /** expression对应的permissions列表 */
    @TableField(exist = false)
    private List<String> permissions;
}

@Data
public class User {
    private Long id;
    private String name;
    private Integer age;
    private String email;

    /** 用户提交过仓库 */
    @TableField(exist = false)
    private List<String> contributions = new ArrayList<>();

    /** 存放一些乱七八糟的数据,当然contributions字段也放在这里 */
    @TableField(exist = false)
    private Map<String, Object> metadata = new HashMap<>();
}

dao类

/**
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
@Mapper
public interface AbacDao extends BaseMapper<Abac> {

    /** 获取abacId关联权限 */
    @Select("SELECT p.permission\n" +
            "FROM abac_permission ap LEFT JOIN permission p ON p.id = ap.permission_id\n" +
            "WHERE ap.abac_id = #{abacId}")
    List<String> selectPermissions(Long abacId);

}

/**
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
@Mapper
public interface UserDao extends BaseMapper<User> {

    /** 获取用户的仓库信息 */
    @Select("SELECT repository FROM user_contribution WHERE user_id = #{userId}")
    List<String> selectRepository(@Param("userId") Long userId);
}

service类

/**
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
@Service
@RequiredArgsConstructor
public class AbacService {
    private final AbacDao abacDao;

    /** 获取abac表达式详细信息列表 */
    public List<Abac> getAll() {
        List<Abac> abacs = abacDao.selectList(null);
        for (Abac abac : abacs) {
            List<String> permissions = abacDao.selectPermissions(abac.getId());
            abac.setPermissions(permissions);
        }
        return abacs;
    }
}


/**
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
@Service
@RequiredArgsConstructor
public class UserService {
    private final UserDao userDao;

    /** 根据userId获取用户详细信息 */
    public User get(Long userId) {
        User user = userDao.selectById(userId);
        List<String> repository = userDao.selectRepository(userId);
        user.setContributions(repository);
        return user;
    }
}
security上下文
/**
 * 自定义用户元数据  用于获取一些实体的属性、操作类型、相关的环境
 *
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
public interface MetadataCustomizer {

    /** 自定义用户元数据 */
    void customize(User user);
}

/**
 * 解析abac表达式
 *
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
@Component
public class SecurityContext {
    /** SpEL表达式解析器 */
    private final ExpressionParser expressionParser = new SpelExpressionParser();

    /**
     *  解析abac表达式
     * @param user 用户详细信息
     * @param abacs abac表达式详细信息集合
     * @return expressions集合, 将这个结果集存放到 Spring Security 或者Apache APISIX的userDetail上下文中
     */
    public List<String> rbacPermissions(User user, List<Abac> abacs) {
        return this.rbacPermissions(user, abacs, Collections.emptyList());
    }

    /**
     * 解析abac表达式
     * @param user 用户详细信息
     * @param abacs abac表达式详细信息集合
     * @param metadataCustomizers  自定义用户元数据  用于获取一些实体的属性、操作类型、相关的环境
     * @return expressions集合, 将这个结果集存放到 Spring Security 或者Apache APISIX的userDetail上下文中
     */
    public List<String> rbacPermissions(User user, List<Abac> abacs, List<MetadataCustomizer> metadataCustomizers) {
        // 处理自定义元数据
        metadataCustomizers.forEach(metadataCustomizer -> metadataCustomizer.customize(user));

        List<String> expressions = new ArrayList<>();
        for (Abac abac : abacs) {
            // 解析表达式的求值器
            Expression expression = expressionParser.parseExpression(abac.getExpression());
            // 创建环境上下文
            EvaluationContext context = new StandardEvaluationContext(user);
            // 获取expression的结果
            if (expression.getValue(context, boolean.class)) {
                expressions.addAll(abac.getPermissions());
            }
        }
        return expressions;
    }

}

测试类

/**
 * @author changjin wei(魏昌进)
 * @since 2022/11/26
 */
@SpringBootTest
class AbacApplicationTests {

    @Autowired
    private UserService userService;

    @Autowired
    private AbacService abacService;

    @Autowired
    private SecurityContext securityContext;

    /** 获取不同用户的abac权限 */
    @Test
    void testRbac() {
        User user = userService.get(1L);
        List<Abac> rbac = abacService.getAll();
        List<String> permissions = securityContext.rbacPermissions(user, rbac);
        System.out.println(permissions);


        user = userService.get(2L);
        permissions = securityContext.rbacPermissions(user, rbac);
        System.out.println(permissions);

        user = userService.get(3L);
        permissions = securityContext.rbacPermissions(user, rbac);
        System.out.println(permissions);

    }

    /**
     * 获取自定义权限
     */
    @Test
    void testMetadataCustomizer() {
        User user = userService.get(1L);
        List<Abac> rbac = abacService.getAll();

        List<String> permissions = securityContext.rbacPermissions(user, rbac);
        System.out.println(permissions);

        permissions = securityContext.rbacPermissions(user, rbac, getMetadataCustomizer());
        System.out.println(permissions);
    }

    /** 模拟网络ip */
    private List<MetadataCustomizer> getMetadataCustomizer() {
        return new ArrayList<MetadataCustomizer>() {{
            add(user -> user.getMetadata().put("ip", "192.168.0.1"));
        }};
    }
}
DELETE FROM user;
INSERT INTO user (id, name, age, email)
VALUES (1, '魏昌进', 26, 'mail@wcj.plus'),
       (2, 'test', 1, 'mail1@wcj.plus'),
       (3, 'admin', 1, 'mail2@wcj.plus');

DELETE FROM user_contribution;
INSERT INTO user_contribution (id, user_id, repository)
VALUES (1, 1, 'galaxy-sea/spring-cloud-apisix'),
       (2, 2, 'spring-cloud/spring-cloud-commons'),
       (3, 2, 'spring-cloud/spring-cloud-openfeign'),
       (4, 2, 'alibaba/spring-cloud-alibaba'),
       (5, 2, 'Tencent/spring-cloud-tencent'),
       (6, 2, 'apache/apisix-docker');

DELETE FROM permission;
INSERT INTO permission (id, permission)
VALUES (1, 'github:pr:merge'),
       (2, 'github:pr:close'),
       (3, 'github:pr:open'),
       (4, 'github:pr:comment');


DELETE FROM abac;
INSERT INTO abac (id, expression)
VALUES (1, 'contributions.contains(''galaxy-sea/spring-cloud-apisix'')'),
       (2, 'name == ''admin'''),
       (3, 'metadata.get(''ip'') == ''192.168.0.1''');

DELETE FROM abac_permission;
INSERT INTO abac_permission (id, abac_id, permission_id)
VALUES (1, 1, 1),

       (2, 2, 1),
       (3, 2, 2),
       (4, 2, 3),
       (5, 2, 4),

       (6, 3, 1),
       (7, 3, 2),
       (8, 3, 3),
       (9, 3, 4);

Spring Security 和 Apache Shiro整合

Spring Security只需要修改拦截器即可在获取到UserDetails将SecurityContext#rbacPermissions转换为GrantedAuthority即可

/**
 * 这里是伪代码, 展示一下大概逻辑
 *
 * @author changjin wei(魏昌进)
 * @since 2022/04/29
 */
public class IamOncePerRequestFilter implements OncePerRequestFilter {

  @Autowired
  private SecurityContext securityContext;

  @Autowired
  private AbacService abacService;

  @Autowired
  private List<MetadataCustomizer> metadataCustomizers;

  @Autowired
  public void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) {
    UserDetails user = toUser();
    List<String> permissions = securityContext.rbacPermissions(user, abacService.getAll(), metadataCustomizers);
    List<GrantedAuthority> abacAuthority = permissions.stream().map(SimpleGrantedAuthority::new).collect(Collectors.toList());
    user.getAuthorities().addAll(abacAuthority);
  }
}

项目源码:

  • https://github.com/galaxy-sea/galaxy-blogs/tree/master/code/abac



欢迎加入我的知识星球,一起探讨架构,交流源码。加入方式,长按下方二维码噢:

91c9f0f98dc5ec5b569679cc496f3e6a.png

已在知识星球更新源码解析如下:

40e19e844f1f1bab05c680f85ef2b57d.jpeg

4c56604505734e055fa0ebc62dcb4d1b.jpeg

5046943d5b0afc869d8a12e7b97ea684.jpeg

25376196817f3554c95d695e3a9756aa.jpeg

最近更新《芋道 SpringBoot 2.X 入门》系列,已经 101 余篇,覆盖了 MyBatis、Redis、MongoDB、ES、分库分表、读写分离、SpringMVC、Webflux、权限、WebSocket、Dubbo、RabbitMQ、RocketMQ、Kafka、性能测试等等内容。

提供近 3W 行代码的 SpringBoot 示例,以及超 4W 行代码的电商微服务项目。

获取方式:点“在看”,关注公众号并回复 666 领取,更多内容陆续奉上。

文章有帮助的话,在看,转发吧。
谢谢支持哟 (*^__^*)
权限设计,设计模型分析(DAC,MAC,RBAC,ABAC) 之 RBAC 权限设计,设计模型分析(DAC,MAC,RBAC,ABAC) 之 RBAC:角色的权限控制 阅读详情

相关推荐

别再只懂RBAC了!用ABAC模型搞定那些‘奇葩’的权限需求(附真实场景拆解)

本文深入探讨了ABAC(Attribute-Based Access Control)模型如何解决传统RBAC在动态权限管理中的局限性。通过真实场景拆解和核心架构解析,展示了ABAC在细粒度权限控制、动态业务规则处理方面的优势,并提供了从RBAC迁移到ABAC的渐进路径和典型行业解决方案。

weixin_30666401的博客 199

Spring Expression Language(SpEL)实现ABAC鉴权模型, 动态计算实体的属性、操作类型、相关的环境来控制是否有对操作对象的权限

基于ABAC访问控制动态计算实体的属性、操作类型、相关的环境来控制是否有对操作对象的权限

小魏的奇妙世界 4407

Casbin实战:如何用一张表搞定RBAC权限系统(附完整SQL配置)

本文详细介绍了如何使用Casbin的单表方案实现RBAC权限系统,仅需一张`lv_casbin_rule`表即可完成角色和权限的配置。通过实战示例和SQL配置,展示了如何高效管理用户权限,适用于电商后台等场景,显著提升系统性能和开发效率。

weixin_29315569的博客 177

权限系统设计详解(三):ABAC 基于属性的访问控制

ABAC(Attribute-Based Access Control,基于属性的访问控制)是一种灵活的访问控制机制,可以根据多个属性来控制用户对资源的访问。这些属性可以是用户属性(如职位、年龄、部门)、资源属性(如文档分类、创建日期)、环境属性(如访问时间、网络位置)和行为属性(如读取、写入、执行)等。ABAC 通过定义一系列的访问策略,这些策略基于属性进行评估,以决定是否允许用户执行特定的操作。ABAC 提供了比传统的访问控制模型(如基于角色的访问控制 RBAC)更高的灵活性和更细的粒度。

路多辛的所思所想 1万+

从钉钉、有赞看B端权限设计:如何用RBAC+搞定复杂组织架构与数据隔离

本文深入探讨了B端权限设计中RBAC+模型的应用,通过分析钉钉、有赞等头部产品的实践,展示了如何应对复杂组织架构与数据隔离的挑战。文章详细介绍了RBAC+的四大增强维度,包括组织维度扩展、数据维度细化等,并提供了性能优化策略和实施路线图,为企业级权限管理提供了实用指南。

weixin_33935636的博客 292

前端应用权限设计面面观

多租户场景适合用 ABAC,比如 { resource: 'order', action: 'edit', conditions: { tenantId: 'companyA', isOwner: true } }。咱得让界面元素乖乖听权限的指挥,别让用户看到不该看的东西,也别让按钮“勾引”用户去点没权限的操作。想象一下,用户点了个按钮,结果后端返回“无权限”,页面却傻乎乎地啥也没提示,或者更糟,压根儿不该显示的按钮还大大咧咧地摆在那儿——这体验能好吗?比如,只有管理员能改“订单状态”,普通用户只能看。

大模型大数据攻城狮的专栏 467

权限控制设计难题,资深架构师教你4步搞定复杂权限场景

解决复杂权限场景难题,四步掌握PHP权限控制设计精髓。适用于多角色、高并发系统,基于RBAC模型实现灵活授权,支持动态规则扩展,提升安全与性能。架构师实战经验总结,值得收藏。

FuncLens的博客 509

智能决策支持AI平台权限管理设计:架构师如何平衡安全性与易用性?

智能决策支持AI平台是企业数字化转型的“大脑”——它整合了数据、模型、决策流,支撑从客户分层到库存优化的核心业务决策。权限太严,业务人员因“拿不到钥匙”无法快速决策;权限太松,数据科学家可能误删核心模型,或高管意外泄露敏感报告。作为架构师,我们需要设计一套**“会思考的权限系统”:既像银行 vault 一样守好安全底线,又像智能门锁一样让用户“刷脸即进”。本文将从。

小白菜的博客 1155

别再只懂RBAC了!用ABAC搞定你项目中那些‘特殊’的权限需求(附Spring Security实战配置)

本文深入探讨了ABAC(基于属性的访问控制)在动态权限系统中的优势与应用,通过对比RBAC的局限性,展示了ABAC如何解决复杂业务场景下的权限需求。文章提供了Spring Security集成ABAC的实战配置,包括属性定义、策略语言、决策流程及性能优化策略,帮助开发者构建更灵活、高效的权限管理系统。

weixin_33743248的博客 396

使用TMS320F28335控制四位共阳数码管

简要阐述利用F28335控制四位共阳数码管的整个过程,包括原理、思路、部分代码以及调试过程。

liujunhaozuishuai的博客 2660

告别绕线!用Altium Designer从零设计一个PCB平面变压器(附3D模型)

本文详细介绍了如何使用Altium Designer从零设计一个PCB平面变压器,包括磁芯选型、电气参数计算、PCB设计实战技巧以及3D验证与生产输出。通过将绕组直接集成到PCB层中,配合嵌入式磁芯,实现了小型化、高功率密度的电源设计,适用于中低电流、高频应用场景。附3D模型,帮助读者快速掌握这一创新设计流程。

weixin_33716154的博客 443

企业云盘权限体系设计:从RBAC到ABAC的技术演进与实战落地

本文深入对比WebDAV、SDK、OIDC、SFTP四种企业云盘API集成方案,提供选型决策树和Python完整代码示例,帮助企业根据团队规模、安全需求和集成复杂度选择最适合的集成路径。

byoass的博客 420

【无标题】ReaxFF拟合参数以及算法安装

ReaxFF拟合参数以及算法安装

zmzyzm的博客 1421

别再只懂RBAC了!用ABAC搞定复杂业务权限,看这篇就够了(附Spring Security实战)

本文深入探讨了ABAC(基于属性的访问控制)在复杂业务权限管理中的应用,对比传统RBAC的局限性,详细解析了ABAC的动态决策优势。通过Spring Security实战案例,展示了如何实现精细化权限控制,包括属性收集、策略决策引擎配置及性能优化技巧,助力开发者构建下一代动态权限系统。

weixin_42539414的博客 326

在Window上安装和配置VTK9.x,并在QT项目中调试VTK是否可用

VTK+MSVC+Qt Creator + CMake配置

qq_42279379的博客 1000

python基础:工作会用到的90%的python代码都在这了(万字详解!)

Python 备忘单是 Python 3 编程语言的单页参考表 著名的“Hello World”程序在 Python 中的实现 Python 不能在没有赋值的情况下声明变量 变量可以存放不同类型的值 内置数据类型 序列指一批有序的元素,集合指一批无序且不重复的元素查看: 数据类型 查看: 字符串 查看: 列表 查看: 判断 查看: 循环 查看: 函数 查看: 文件处理 表示 x 和 y 的商, 表示 x 和 y 的底商,另见 StackOverflow f-字符串 (Python 3.6+) 查看

数据知道的博客 1万+

权限那点事儿

权限管理是企业数据安全的重要保障。文章首先阐述了权限管理的必要性,通过支付公司案例说明不当授权可能导致数据泄露或误操作风险。其次介绍了RBAC(基于角色的访问控制)模型,通过角色中介简化用户与权限的分配关系,解决了大规模用户权限维护难题。随后提出更灵活的ABAC(基于属性的访问控制)模型,该模型通过用户属性、资源属性、环境条件等动态计算权限,适用于复杂场景。最后文章提出了一种改进方案,在RBAC基础上允许直接分配独立权限,形成"角色权限+独立权限"的混合模式,既保持RBAC的易用性,又增

sunyingboaini的博客 1060

Open3D 可视化(1)——简单可视化【2026最新版】

简单可视化,博客长期更新,本文最新更新时间为:2026年5月10日。

点云侠的博客 5687

3分钟上手PyCasbin:为你的Python应用打造智能权限管理系统

还在为复杂的权限管理头疼吗?想象一下,你正在开发一个Web应用,需要控制不同用户对资源的访问权限。Alice可以读取数据,Bob可以写入数据,管理员则拥有所有权限。手动编写一堆if-else判断不仅代码臃肿,维护起来更是噩梦!😫 别担心,PyCasbin就是来解决这个问题的!它是一款强大而高效的Python访问控制库,让你轻松实现ACL、RBAC、ABAC等多种权限模型。今天,我就带你快速上手

gitblog_00950的博客 324

Microsemi Libero系列教程(四)——PLL的使用

文章目录PLL是什么Libero中PLL的使用官方文档 系列教程:Microsemi Libero系列教程 PLL是什么 PLL(Phase Locked Loop): 为锁相回路或锁相环,用来统一整合时钟信号,使高频器件正常工作,如内存的存取资料等。PLL用于振荡器中的反馈技术。 许多电子设备要正常工作,通常需要外部的输入信号与内部的振荡信号同步。一般的晶振由于工艺与成本原因,做不到很高的频率...

whik1194的博客 7216

OpenClaw对接本地大模型:Llama3/Qwen/ChatGLM全适配,完全私有化部署

OpenClaw对接本地大模型,是企业级AI智能体落地的必经之路——它不仅解决了数据隐私和合规问题,还能大幅降低成本、提升响应速度、实现定制化。这篇文章我给大家完整拆解了两套部署方案:Ollama(新手首选,5分钟搞定)和vLLM(生产环境首选,高性能),覆盖了Llama3/Qwen/ChatGLM三大主流模型,还有真实的落地案例、高级优化、踩坑避坑指南,看完你就能零代码完成完全私有化的部署。从零开发自定义工具,给OpenClaw添加专属业务能力;

专注于Python爬虫开发,分享爬虫技巧、项目实战与反爬经验,使用Scrapy、BeautifulSoup等工具,解决数据抓取难题。 809

权限失控太危险?Open-AutoGLM分级管控配置全攻略,一文搞定

权限失控太危险?本指南提供Open-AutoGLM权限分级管控配置指南,详解企业级AI系统中角色权限划分、数据访问控制与操作审计等核心方法,适用于多租户管理与合规场景,保障系统安全稳定,值得收藏。

InitFlow的博客 889

lwip-2.0.3

lwip是瑞典计算机科学院(SICS)的Adam Dunkels 开发的一个小型开源的TCP/IP协议栈。实现的重点是在保持TCP协议主要功能的基础上减少对RAM 的占用。

终极权限管理框架 Casbin:轻松掌握10+种访问控制模型的完整指南

Casbin 是一款功能强大的开源权限管理框架,专为开发者提供灵活且高效的访问控制解决方案。无论是简单的 RBAC 模型还是复杂的 ABAC 策略,Casbin 都能轻松应对,帮助项目构建安全可靠的权限系统。 ## 为什么选择 Casbin?5大核心优势解析 Casbin 凭借其独特的设计理念和强大的功能,在众多权限管理工具中脱颖而出。它不仅支持多种访问控制模型,还提供了丰富的扩展机制,让权限

gitblog_00463的博客 403

复分析 阿尔福斯(Ahlfors) 第三版答案 英文

答案分为十章,有部分习题没有答案,全英文复分析阿尔福斯(Ahlfors) 第三版答案

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

上一篇: SpringBoot 3.0正式发布,有这几个新变化!
下一篇: 从11s到170ms!看看人家的接口优化技巧,那叫一个优雅!
公众号-芋道源码
博客等级 码龄10年 1634粉丝 377原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值