嗯,昨天面试让讲我的项目,让我讲讲项目里权限控制那一块的,讲的很烂。所以整理一下。

按照面试官的提问流程来讲:

一、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<org.springframework.security.access.ConfigAttribute> * 返回值是 Collection<ConfigAttribute>,表示当前请求 URL 所需的角色。
* @Author Liruilong
* @Description 当前请求需要的角色,该方法的参数是一个 FilterInvocation, 开发者可以从 Filterlnvocation 中提取出当前请求的 URL,
* @Date 18:13 2019/12/24
* @Param [object]
**/
@Override
public Collection<ConfigAttribute> getAttributes(Object object) throws IllegalArgumentException {
//获取当前请求路径
String requestUrl = ((FilterInvocation) object).getRequestUrl();
logger.warning(requestUrl);
//获取所有的菜单url路径
List<Menu> menus = menuService.getAllMenusWithRole();
// AntPathMatcher,主要用来实现 ant 风格的 URL 匹配。
for (Menu menu : menus) {
if (antPathMatcher.match(menu.getUrl(), requestUrl)) {
//拥有当前菜单权限的角色
List<Role> roles = menu.getRoles();
String[] strings = new String[roles.size()];
for (int i = 0; i < roles.size(); i++) {
strings[i] = roles.get(i).getName();
}
return SecurityConfig.createList(strings);
}
}
// 没匹配上的资源都是登录,或者为公共资源
return SecurityConfig.createList("ROLE_LOGIN");
}
 @Override
public void decide(Authentication authentication, Object object, Collection<ConfigAttribute> configAttributes)
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路径的情况时,对于登录用户的每一个请求,都会通过鉴权处理,分析角色.最后通过权限的判断分析是否可以访问菜单资源.

用户表:

角色表:

用户角色映射表:

权资源表:

最新文章

  1. Difference between _, __ and __xx__ in Python
  2. Codeforces 235C
  3. Postfix性能测试(PHP版)
  4. 试用阿里云RDS的MySQL压缩存储引擎TokuDB
  5. 【原创】java中的父进程子进程 —— 坑爹的java Runtime.getRuntime().exec
  6. 正则表达式-linux基础
  7. Java面试题积累
  8. 如何使用 RESTClient 调试微信支付接口
  9. VK Cup 2017 - Квалификация 1
  10. PHP实现表单提交发送邮件
  11. 引擎设计跟踪(九.14.2 final) Inverse Kinematics: CCD 在Blade中的实现
  12. Java核心技术及面试指南 数据库方面的面试题归纳以及总结
  13. transform:scale()妙用——当下拉列表,图片无缝拉升 动画效果
  14. Java中重写与重载
  15. Spring之AOP在XML中的配置方法
  16. CSRF与SSRF区别
  17. 论文笔记:Concept Mask: Large-Scale Segmentation from Semantic Concepts
  18. drf3 Serializers 序列化组件
  19. AOP技术基础(转)
  20. git代码统计

热门文章

  1. 题目分享J
  2. ASP.NET Core3.x 基础—注册服务(2)
  3. libevent(四)event_base 2
  4. 聊聊算法——BFS和DFS
  5. Coursera课程笔记----计算导论与C语言基础----Week 6
  6. Coursera课程笔记----计算导论与C语言基础----Week 2
  7. Day_09【常用API】扩展案例8_计算字符'j'和字符串'java'在字符串中出现的次数
  8. [hdu2112]最短路
  9. 【疑问】SQLServer_DNS注入数据库因为点号不能显示数据库的库名的方法[语音和音乐]
  10. Appium自动化(9) - appium元素定位的快速入门