嗯,昨天面試讓講我的專案,讓我講講專案裡許可權控制那一塊的,講的很爛。所以整理一下。
按照面試官的提問流程來講:
一、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路徑的情況時,對於登入使用者的每一個請求,都會通過鑑權處理,分析角色.最後通過許可權的判斷分析是否可以訪問選單資源.
使用者表:
角色表:
使用者角色對映表:
權資源表: