中文字幕av专区_日韩电影在线播放_精品国产精品久久一区免费式_av在线免费观看网站

溫馨提示×

溫馨提示×

您好,登錄后才能下訂單哦!

密碼登錄×
登錄注冊×
其他方式登錄
點擊 登錄注冊 即表示同意《億速云用戶服務條款》

Spring Security角色繼承分析

發布時間:2020-08-24 17:07:05 來源:腳本之家 閱讀:171 作者:江南一點雨 欄目:編程語言

今天想和小伙伴們來聊一聊 Spring Security 中的角色繼承問題。

角色繼承實際上是一個很常見的需求,因為大部分公司治理可能都是金字塔形的,上司可能具備下屬的部分甚至所有權限,這一現實場景,反映到我們的代碼中,就是角色繼承了。

Spring Security 中為開發者提供了相關的角色繼承解決方案,但是這一解決方案在最近的 Spring Security 版本變遷中,使用方法有所變化。今天除了和小伙伴們分享角色繼承外,也來順便說說這種變化,避免小伙伴們踩坑,同時購買了我的書的小伙伴也需要留意,書是基于 Spring Boot2.0.4 這個版本寫的,這個話題和最新版 Spring Boot 的還是有一點差別。

以前的寫法

這里說的以前寫法,就是指 SpringBoot2.0.8(含)之前的寫法,在之前的寫法中,角色繼承只需要開發者提供一個 RoleHierarchy 接口的實例即可,例如下面這樣:

@Bean
RoleHierarchy roleHierarchy() {
  RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
  String hierarchy = "ROLE_dba > ROLE_admin ROLE_admin > ROLE_user";
  roleHierarchy.setHierarchy(hierarchy);
  return roleHierarchy;
}

在這里我們提供了一個 RoleHierarchy 接口的實例,使用字符串來描述了角色之間的繼承關系, ROLE_dba 具備 ROLE_admin 的所有權限,而 ROLE_admin 則具備 ROLE_user 的所有權限,繼承與繼承之間用一個空格隔開。提供了這個 Bean 之后,以后所有具備 ROLE_user 角色才能訪問的資源, ROLE_dba 和 ROLE_admin 也都能訪問,具備 ROLE_amdin 角色才能訪問的資源, ROLE_dba 也能訪問。

現在的寫法

但是上面這種寫法僅限于 Spring Boot2.0.8(含)之前的版本,在之后的版本中,這種寫法則不被支持,新版的寫法是下面這樣:

@Bean
RoleHierarchy roleHierarchy() {
  RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
  String hierarchy = "ROLE_dba > ROLE_admin \n ROLE_admin > ROLE_user";
  roleHierarchy.setHierarchy(hierarchy);
  return roleHierarchy;
}

變化主要就是分隔符,將原來用空格隔開的地方,現在用換行符了。這里表達式的含義依然和上面一樣,不再贅述。

上面兩種不同寫法都是配置角色的繼承關系,配置完成后,接下來指定角色和資源的對應關系即可,如下:

@Override
protected void configure(HttpSecurity http) throws Exception {
  http.authorizeRequests().antMatchers("/admin/**")
      .hasRole("admin")
      .antMatchers("/db/**")
      .hasRole("dba")
      .antMatchers("/user/**")
      .hasRole("user")
      .and()
      .formLogin()
      .loginProcessingUrl("/doLogin")
      .permitAll()
      .and()
      .csrf().disable();
}

這個表示 /db/** 格式的路徑需要具備 dba 角色才能訪問, /admin/** 格式的路徑則需要具備 admin 角色才能訪問, /user/** 格式的路徑,則需要具備 user 角色才能訪問,此時提供相關接口,會發現,dba 除了訪問 /db/** ,也能訪問 /admin/** 和 /user/** ,admin 角色除了訪問 /admin/** ,也能訪問 /user/** ,user 角色則只能訪問 /user/** 。

源碼分析

這樣兩種不同的寫法,其實也對應了兩種不同的解析策略,角色繼承關系的解析在 RoleHierarchyImpl 類的 buildRolesReachableInOneStepMap 方法中,Spring Boot2.0.8(含)之前該方法的源碼如下:

private void buildRolesReachableInOneStepMap() {
	Pattern pattern = Pattern.compile("(\\s*([^\\s>]+)\\s*>\\s*([^\\s>]+))");
	Matcher roleHierarchyMatcher = pattern
			.matcher(this.roleHierarchyStringRepresentation);
	this.rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
	while (roleHierarchyMatcher.find()) {
		GrantedAuthority higherRole = new SimpleGrantedAuthority(
				roleHierarchyMatcher.group(2));
		GrantedAuthority lowerRole = new SimpleGrantedAuthority(
				roleHierarchyMatcher.group(3));
		Set<GrantedAuthority> rolesReachableInOneStepSet;
		if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
			rolesReachableInOneStepSet = new HashSet<>();
			this.rolesReachableInOneStepMap.put(higherRole,
					rolesReachableInOneStepSet);
		}
		else {
			rolesReachableInOneStepSet = this.rolesReachableInOneStepMap
					.get(higherRole);
		}
		addReachableRoles(rolesReachableInOneStepSet, lowerRole);
		logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole
				+ " one can reach role " + lowerRole + " in one step.");
	}
}

從這段源碼中我們可以看到,角色的繼承關系是通過正則表達式進行解析,通過空格進行切分,然后構建相應的 map 出來。

Spring Boot2.1.0(含)之后該方法的源碼如下:

private void buildRolesReachableInOneStepMap() {
	this.rolesReachableInOneStepMap = new HashMap<GrantedAuthority, Set<GrantedAuthority>>();
	try (BufferedReader bufferedReader = new BufferedReader(
			new StringReader(this.roleHierarchyStringRepresentation))) {
		for (String readLine; (readLine = bufferedReader.readLine()) != null;) {
			String[] roles = readLine.split(" > ");
			for (int i = 1; i < roles.length; i++) {
				GrantedAuthority higherRole = new SimpleGrantedAuthority(
						roles[i - 1].replaceAll("^\\s+|\\s+$", ""));
				GrantedAuthority lowerRole = new SimpleGrantedAuthority(roles[i].replaceAll("^\\s+|\\s+$
				Set<GrantedAuthority> rolesReachableInOneStepSet;
				if (!this.rolesReachableInOneStepMap.containsKey(higherRole)) {
					rolesReachableInOneStepSet = new HashSet<GrantedAuthority>();
					this.rolesReachableInOneStepMap.put(higherRole, rolesReachableInOneStepSet);
				} else {
					rolesReachableInOneStepSet = this.rolesReachableInOneStepMap.get(higherRole);
				}
				addReachableRoles(rolesReachableInOneStepSet, lowerRole);
				if (logger.isDebugEnabled()) {
					logger.debug("buildRolesReachableInOneStepMap() - From role " + higherRole
							+ " one can reach role " + lowerRole + " in one step.");
				}
			}
		}
	} catch (IOException e) {
		throw new IllegalStateException(e);
	}
}

從這里我們可以看到,這里并沒有一上來就是用正則表達式,而是先將角色繼承字符串轉為一個 BufferedReader ,然后一行一行的讀出來,再進行解析,最后再構建相應的 map。從這里我們可以看出為什么前后版本對此有不同的寫法。

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持億速云。

向AI問一下細節

免責聲明:本站發布的內容(圖片、視頻和文字)以原創、轉載和分享為主,文章觀點不代表本網站立場,如果涉及侵權請聯系站長郵箱:is@yisu.com進行舉報,并提供相關證據,一經查實,將立刻刪除涉嫌侵權內容。

AI

莱芜市| 中超| 台南县| 常山县| 普格县| 黔江区| 浦城县| 宝鸡市| 于都县| 吴川市| 玉田县| 赣州市| 沁阳市| 贞丰县| 木兰县| 民县| 永胜县| 杭锦旗| 奉节县| 敖汉旗| 安丘市| 饶阳县| 盐亭县| 黎城县| 兖州市| 若尔盖县| 类乌齐县| 宜兰县| 上饶市| 陇西县| 博客| 泰顺县| 松潘县| 丹江口市| 金山区| 许昌市| 炎陵县| 永新县| 封开县| 麟游县| 玛多县|