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
角色和资源的两头表,同样的利用两个一对多建设多对多关系
表关系
原表 | 指标表 | 关系 |
---|---|---|
user | userRoleLine | 一对多 |
userRoleLine | role | 多对一 |
role | roleResourceLine | 一对多 |
roleResourceLine | resource | 多对一 |
权限管制原理
依据登录用户首选获取角色列表,每个角色对应多个资源,最终用户的权限为多个角色对应的资源叠加。如果领有某个资源权限就返回数据,否则提醒无权限。
默认如果没有匹配任何资源,示意该资源无需特地权限,只须要登录用户即可。
验证
增加客户资源,ANT url 为 /api/business/customer/*,操作为 ,示意 GET,PATCH,DELETE,POST 都须要受权。
如果操作为 DELETE,示意值管制 DELETE 操作,其它操作不限度。
通过 UI 拜访客户时候提醒没有权限,和冀望的成果统一
增加角色“客户管理员”,该角色领有客户拜访权限
给“超级管理员”增加“客户管理员”角色,这样“超级管理员”就领有了客户拜访权限
因为用户重新分配了角色,须要须要登记从新登录,登录之后又能够失常拜访客户资源了。
外围源码
@Slf4j
@Component
public 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
@Component
public 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