基于RBAC的权限控制浅析(结合Spring Security)
按照面试官的提问流程来讲:
一、RBAC是个啥东西了?
RBAC (
Role-Based Access Control
),即基于角色的访问控制模型,我的项目是
基于
RBAC0 模型
.
由于之相对应的数据实体构成
.
由用户表
,
角色映射表
,
角色表
,
权限表
,
权限映射表构成
.
图
1 RBAC0 模型图
二、你可以讲讲权限控制大概执行流程吗?
用户登录之后首先进行身份验证,成功之后获取当前用户的所有角色,之后根据角色加载对应的权限菜单,这里默认不加载没有权限的菜单,当存在直接输入URL路径的情况时,对于登录用户的每一个请求,都会通过鉴权处理,分析角色.最后通过权限的判断分析是否可以访问菜单资源.
在 spring Security,对用登录的请先通过
FilterInvocationSecurityMetadataSource
的实现类获取当前
请求,分析需要的角色,该类的主要功能就是通过当前的请求地址,获取该地址需要的用户角色。
1、获取当前访问路径的URL路径
2、获取所有资源URL,即所有的菜单URL路径
3、当前的访问URL和返回的每个URL基于Ant风格比较,如果相等,获取当前访问URL的所有角色。如果没有相等的,定义资源为公告资源,并且给予一个公告资源的角色。
4、当为公共资源时,判断用户是否登录。登录放行。返回资源
5、当为角色资源时,登录用户的角色列表和该资源的角色列表进行比较,如果有相同角色,放行,返回资源
6、当即不是公共资源也没有相匹配的角色的时候。抛异常,没有权限
图2 系统访问控制流程图
代码:
鉴权:
@Component public class CustomFilterInvocationSecurityMetadataSource implements FilterInvocationSecurityMetadataSource { @Autowired MenuService menuService; //路径比较工具 AntPathMatcher antPathMatcher = new AntPathMatcher(); Logger logger = Logger.getLogger("com.liruilong.hros.config.ustomFilterInvocationSecurityMetadataSource"); /** * @return java.util.Collection* 返回值是 Collection ,表示当前请求 URL 所需的角色。 * @Author Liruilong * @Description 当前请求需要的角色,该方法的参数是一个 FilterInvocation, 开发者可以从 Filterlnvocation 中提取出当前请求的 URL, * @Date 18:13 2019/12/24 * @Param [object] **/ @Override public Collection getAttributes(Object object) throws IllegalArgumentException { //获取当前请求路径 String requestUrl = ((FilterInvocation) object).getRequestUrl(); logger.warning(requestUrl); //获取所有的菜单url路径 List
@Override public void decide(Authentication authentication, Object object, CollectionconfigAttributes) throws AccessDeniedException, InsufficientAuthenticationException { for (ConfigAttribute configAttribute : configAttributes) { String needRole = configAttribute.getAttribute(); if ("ROLE_LOGIN".equals(needRole)) { if (authentication instanceof AnonymousAuthenticationToken) { throw new AccessDeniedException("尚未登录,请登录!"); } else { return; } } Collection extends GrantedAuthority> authorities = authentication.getAuthorities(); for (GrantedAuthority authority : authorities) { if (authority.getAuthority().equals(needRole)) { return; } } } throw new AccessDeniedException("权限不足,请联系管理员!"); }
三、你可以把对应的SQL和表结构写一下吗?
加载所有的菜单资源;返回所有的菜单资源和对应的角色集合,Service端和访问的URL的比较,存在判断角色。(鉴权)
select m.*,r.`id` as rid,r.`name` as rname,r.`namezh` as rnamezh from menu m,menu_role mr,role r where m.`id`=mr.`mid` and mr.`rid`=r.`id` order by m.`id`
根据用户ID返回当前用户的全部菜单资源(授权)
select m1.`id`,m1.url,m1.`path`,m1.`component`,m1.`iconCls`,m1.`name`,m1.`requireAuth`,m1.keepAlive,m1.enabled, m2.id as id2,m2.url as url2,m2.name as name2,m2.`component` as component2,m2.`iconCls` as iconCls2,m2.`keepAlive` as keepAlive2,m2.`path` as path2,m2.`requireAuth` as requireAuth2,m2.enabled as enabled2,m2.parentId as parentId2 from menu m1,menu m2 where m1.`id`=m2.`parentId` and m1.`id`!=1 and m2.`id` in(select mr.`mid` from hr_role h_r,menu_role mr where h_r.`rid`=mr.`rid` and h_r.`hrid`=#{hrId}) and m2.`enabled`=true order by m1.`id`,m2.`id`
图
2 ERBAC数据实体关系图
用户登录之后首先进行身份验证
,
成功之后获取当前用户的所有角色
,
之后根据角色加载对应的权限菜单
,
这里默认不加载没有权限的菜单
,
当存在直接输入
URL
路径的情况时
,
对于登录用户的每一个请求
,
都会通过鉴权处理
,
分析角色
.
最后通过权限的判断分析是否可以访问菜单资源
.
用户表:
角色表:
用户角色映射表:
权资源表: