Spring Security FilterSecurityInterceptor身份验证时如何让Hierarchical Roles生效

基于spring-security-4.1.0.RELEASE和spring-security-oauth2-2.3.5.RELEASE

如果Spring提供的对外访问的某个接口需要具备某种角色才可以访问时,例如需要具备普通用户(user)角色,你可以配置为如下代码,假设访问的地址为/api/testInterface

@EnableResourceServer
@Configuration
public class ResourceConfig extends ResourceServerConfigurerAdapter {

	@Override
	public void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				.antMatchers("/api/testInterface").hasRole("user");
	}
}

但你也可能希望管理员(admin)角色能够执行普通用户可以执行的所有操作时,这就牵扯的一个层级角色的问题,也就是Spring Security中提到的Hierarchical Roles,所以这里我们这样配置:

@EnableResourceServer
@Configuration
public class ResourceConfig extends ResourceServerConfigurerAdapter {

	@Bean
	public RoleHierarchy roleHierarchy() {
		RoleHierarchyImpl roleHierarchy = new RoleHierarchyImpl();
		// 该>符号可以被认为是“包括”的意思admin包括user
		roleHierarchy.setHierarchy("ROLE_admin > ROLE_user");
		return roleHierarchy;
	}
	
	public OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler() {
		OAuth2WebSecurityExpressionHandler oAuth2WebSecurityExpressionHandler = new OAuth2WebSecurityExpressionHandler();
		oAuth2WebSecurityExpressionHandler.setRoleHierarchy(roleHierarchy());
		return oAuth2WebSecurityExpressionHandler;
	}

	@Override
	public void configure(ResourceServerSecurityConfigurer resources) throws Exception {
		resources.expressionHandler(oAuth2WebSecurityExpressionHandler());
	}
	
	@Override
	public void configure(HttpSecurity http) throws Exception {
		http.authorizeRequests()
				.antMatchers("/api/testInterface").hasRole("user");
	}
}

为啥要设置一个expressionHandler,因为Spring Security中在ResourceServerSecurityConfigurer 中有一个默认的expressionHandler就是OAuth2WebSecurityExpressionHandler,但OAuth2WebSecurityExpressionHandler它的roleHierarchy属性并没有默认的实现,也就是为null,如果我们不手动给它设置,在进行判断认证对象是否包含指定角色时,它只会判断认证对象是否具备user,它不会获取user具备层级角色的关系在进行判断,从而导致通过admin来访问时,被拒绝访问。相关的判断的逻辑大体如下:

public abstract class SecurityExpressionRoot implements SecurityExpressionOperations {
	private String defaultRolePrefix = "ROLE_";
	
	/** 上面省略部分代码 */
	
	public final boolean hasRole(String role) {
		return hasAnyRole(role);
	}

	public final boolean hasAnyRole(String... roles) {
		return hasAnyAuthorityName(defaultRolePrefix, roles);
	}
	
	private boolean hasAnyAuthorityName(String prefix, String... roles) {
		Set<String> roleSet = getAuthoritySet();

		for (String role : roles) {
			String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
			if (roleSet.contains(defaultedRole)) {
				return true;
			}
		}

		return false;
	}
	
	/** 中间省略部分代码 */
	
	private Set<String> getAuthoritySet() {
		if (roles == null) {
			roles = new HashSet<String>();
			Collection<? extends GrantedAuthority> userAuthorities = authentication
					.getAuthorities();

			if (roleHierarchy != null) {
				userAuthorities = roleHierarchy
						.getReachableGrantedAuthorities(userAuthorities);
			}

			roles = AuthorityUtils.authorityListToSet(userAuthorities);
		}

		return roles;
	}
	
	/** 下面省略部分代码 */
}

可以看到在getAuthoritySet方法中有一行针对roleHierarchy判断是否为空,如果不为空会把user对应的层级关系添加到roles集合中,这时roles中存在两个角色[ROLE_admin, ROLE_user],这时在通过admin来访问时就没有问题了。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值