写点什么

基于角色访问控制 RBAC 权限模型的动态资源访问权限管理实现

用户头像
crudapi
关注
发布于: 2021 年 04 月 03 日
基于角色访问控制RBAC权限模型的动态资源访问权限管理实现

RBAC 权限模型(Role-Based Access Control)

前面主要介绍了元数据管理和业务数据的处理,通常一个系统都会有多个用户,不同用户具有不同的权限,本文主要介绍基于 RBAC 动态权限管理在 crudapi 中的实现。

概要

RBAC 简介

RBAC 权限模型(Role-Based Access Control)即:基于角色的权限控制。模型中有几个关键的术语:


用户:系统接口及访问的操作者


权限:能够访问某接口或者做某操作的授权资格


角色:具有一类相同操作权限的用户的总称

用户角色权限关系

一个用户有一个或多个角色


一个角色包含多个用户


一个角色有多种权限


一个权限属于多个角色

Spring security

Spring Security 是 Spring 项目组中用来提供安全认证服务的框架,可以很方便的实现动态权限管理。

表单配置

系统内置 5 个表单,这些表单和权限相关,和具体业务无关

资源 resource


其中 url 是 ANT 格式表达式,用于配置 url 来确定是否拥有某个资源的权限。

用户 user


用户表记录登录用户信息

角色 role


角色

用户角色行 userRoleLine


用户和角色的中间表,参考之前表关系管理,利用两个一对多建立多对多关系,

角色资源行 roleResourceLine


角色和资源的中间表,同样的利用两个一对多建立多对多关系

表关系


权限控制原理

根据登录用户首选获取角色列表,每个角色对应多个资源,最终用户的权限为多个角色对应的资源叠加。如果拥有某个资源权限就返回数据,否则提示无权限。


默认如果没有匹配任何资源,表示该资源无需特别权限,只需要登录用户即可。

验证


添加客户资源,ANT url 为/api/business/customer/**,操作为*,表示 GET,PATCH,DELETE,POST 都需要授权。如果操作为 DELETE,表示值控制 DELETE 操作,其它操作不限制。



通过 UI 访问客户时候提示没有权限,和期望的效果一致



添加角色“客户管理员”,该角色拥有客户访问权限



给“超级管理员”添加“客户管理员”角色,这样“超级管理员”就拥有了客户访问权限



因为用户重新分配了角色,需要需要注销重新登录,登录之后又可以正常访问客户资源了。

核心源码

@Slf4j@Componentpublic class DynamicSecurityMetadataSource implements FilterInvocationSecurityMetadataSource {
private static Map<String, ConfigAttribute> configAttributeMap = null; @Autowired private DynamicSecurityService dynamicSecurityService;
@PostConstruct public void loadDataSource() { configAttributeMap = dynamicSecurityService.loadDataSource(); }
public void clearDataSource() { log.info("DynamicSecurityMetadataSource clearDataSource"); configAttributeMap.clear(); configAttributeMap = null; }
@Override public Collection<ConfigAttribute> getAttributes(Object o) throws IllegalArgumentException { if (configAttributeMap == null) { this.loadDataSource(); } List<ConfigAttribute> configAttributes = new ArrayList<>(); FilterInvocation fi = (FilterInvocation) o; String method = fi.getRequest().getMethod(); log.info("getAttributes method = " + method); //获取当前访问的路径 String url = fi.getRequestUrl(); String path = URLUtil.getPath(url) + "_"+ method; log.info("getAttributes url = " + url); log.info("getAttributes path = " + path); PathMatcher pathMatcher = new AntPathMatcher(); Iterator<String> iterator = configAttributeMap.keySet().iterator(); //获取访问该路径所需资源 while (iterator.hasNext()) { String pattern = iterator.next(); if (pathMatcher.match(pattern, path)) { log.info("match success = " + pattern + ", " + path); configAttributes.add(configAttributeMap.get(pattern)); } } // 未设置操作请求权限,返回空集合 return configAttributes; }
@Override public Collection<ConfigAttribute> getAllConfigAttributes() { return null; }
@Override public boolean supports(Class<?> aClass) { return true; }
}
复制代码


继承 FilterInvocationSecurityMetadataSource,实现 getAttributes 接口,通过 http url 加 http method 进行匹配


@Slf4j@Componentpublic class DynamicAccessDecisionManager implements AccessDecisionManager {
@Override public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes) throws AccessDeniedException, InsufficientAuthenticationException { // 当接口未被配置资源时直接放行 if (CollUtil.isEmpty(configAttributes)) { log.info("empty configAttributes decide passed!"); return; } FilterInvocation fi = (FilterInvocation) object; String method = fi.getRequest().getMethod(); log.info("decide method = " + method); List<String> needAuthorityList = new ArrayList<String>(); Iterator<ConfigAttribute> iterator = configAttributes.iterator(); while (iterator.hasNext()) { ConfigAttribute configAttribute = iterator.next(); //将访问所需资源或用户拥有资源进行比对 String needAuthority = configAttribute.getAttribute(); needAuthorityList.add(needAuthority); for (GrantedAuthority grantedAuthority : authentication.getAuthorities()) { if (needAuthority.trim().equals(grantedAuthority.getAuthority())) { return; } } } throw new AccessDeniedException("对不起,您没有资源:" + String.join(",", needAuthorityList) +"的访问权限!"); }
@Override public boolean supports(ConfigAttribute configAttribute) { return true; }
@Override public boolean supports(Class<?> aClass) { return true; }}
复制代码


继承 AccessDecisionManager,实现 decide 接口,将访问所需资源或用户拥有资源进行比对,如果拥有权限则放行,否则提示无权限。

小结

本文介绍了 RBAC 在 crudapi 中的实现原理,首先引入 Spring security 框架,然后利用配置生成用户,角色,资源等表单,通过配置实现基本的 CRUD 功能,最终实现了动态权限精细化管理。因为用户,角色等表与业务无关,所以会作为系统内置表单。

附 demo 演示

本系统属于产品级的零代码平台,不同于自动代码生成器,不需要生成 Controller、Service、Repository、Entity 等业务代码,程序运行起来就可以使用,真正 0 代码,可以覆盖基本的和业务无关的 CRUD RESTful API。


官网地址:https://crudapi.cn


测试地址:https://demo.crudapi.cn/crudapi/login

发布于: 2021 年 04 月 03 日阅读数: 64
用户头像

crudapi

关注

crudapi是crud+api组合,表示增删改查接口 2019.06.19 加入

使用crudapi可以告别枯燥无味的增删改查代码,让您更加专注业务,节约大量成本,从而提高工作效率。crudapi的目标是让处理数据变得更简单!官网:https://crudapi.cn 演示:https://demo.crudapi.cn/crudapi/login

评论 (1 条评论)

发布
用户头像
基于组织和岗位的RBAC如何管理
2021 年 04 月 14 日 23:01
回复
没有更多了
基于角色访问控制RBAC权限模型的动态资源访问权限管理实现