Spring Security 实战干货:基于配置的接口角色访问控制

1. 前言

欢迎阅读 Spring Security 实战干货 系列文章 。对于受限的访问资源,并非对全部认证经过的用户开放的。好比 A 用户的角色是会计,那么他就能够访问财务相关的资源。B 用户是人事,那么他只能访问人事相关的资源。咱们在RBAC概念 一文中也对基于角色的访问控制的相关概念进行了探讨。在实际开发中咱们如何对资源进行角色粒度的管控呢?今天我来告诉你 Spring Security 是如何来解决这个问题的。html

2. 将角色写入 UserDetails

咱们使用 UserDetailsService 加载 UserDetails 时也会把用户的 GrantedAuthority 权限集写入其中。你能够将角色持久化并在这个点进行注入而后配置访问策略,后续的问题交给 Spring Securityjava

3. 在 HttpSecurity 中进行配置角色访问控制

咱们能够经过配置 WebSecurityConfigurerAdapter 中的 HttpSecurity 来控制接口的角色访问。spring

3.1 经过判断用户是否持有角色来进行访问控制

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasRole("ADMIN")安全

表示 持有 ROLE_ADMIN 角色的用户才能访问 /foo/test 接口。注意:hasRole(String role) 方法入参不能携带前缀 ROLE_ 。咱们来查看 SecurityExpressionRoot 中相关源码:spa

public final boolean hasRole(String role) {
		return hasAnyRole(role);
	}

复制代码

很明显 hasRole 方法源于 hasAnyRole (持有任何其中角色之一,就能知足访问条件,用于一个接口开放给多个角色访问时) :code

public final boolean hasAnyRole(String... roles) {
		return hasAnyAuthorityName(defaultRolePrefix, roles);
	}
复制代码

若是一个接口开放给多个角色,好比 /foo/test 开放给了 ROLE_APPROLE_ADMIN 能够这么写:cdn

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAnyRole("APP","ADMIN")htm

hasAnyRole 方法最终的实现为 hasAnyAuthorityName(String prefix, String... roles):blog

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;
	}
复制代码

上面才是根本的实现, 须要一个 prefix 和每个 role 进行拼接,而后用户的角色集合 roleSet 中包含了就返回true 放行,不然就 false 拒绝。默认的 prefixdefaultRolePrefix= ROLE_接口

3.2 经过判断用户的 GrantedAuthority 来进行访问控制

咱们也能够经过 hasAuthorityhasAnyAuthority 来断定。 其实底层实现和 hasAnyRole 方法同样,只不过 prefixnull 。也就是你写入的 GrantedAuthority 是什么样子的,这里传入参数的就是什么样子的,再也不受 ROLE_ 前缀的制约。

2.1 章节的写法等同以下的写法:

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAuthority("ROLE_ADMIN")

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAnyAuthority("ROLE_APP","ROLE_ADMIN")

4. 匿名访问

匿名身份验证的用户和未经身份验证的用户之间没有真正的概念差别。Spring Security 的匿名身份验证只是为您提供了一种更方便的方式来配置访问控制属性。全部的匿名用户都持有角色 ROLE_ANONYMOUS 。因此你可使用 2.12.2 章节的方法来配置匿名访问:

httpSecurity.authorizeRequests().antMatchers("/foo/test").hasAuthority("ROLE_ANONYMOUS")

你也能够经过如下方式进行配置:

httpSecurity.authorizeRequests().antMatchers("/foo/test").anonymous()

5. 开放请求

开放请求能够这么配置:

httpSecurity.authorizeRequests().antMatchers("/foo/test").permitAll()

6. permitAll 与 anonymous 的一些探讨

开放请求 其实一般状况下跟 匿名请求 有交叉。它们的主要区别在于: 当前的 AuthenticationnullpermitAll 是放行的,而 anonymous 须要 AuthenticationAnonymousAuthenticationToken 。这里是比较难以理解的,下面是来自 Spring 文档中的一些信息:

一般,采用“默认拒绝”的作法被认为是一种良好的安全作法,在该方法中,您明确指定容许的内容,并禁止其余全部内容。定义未经身份验证的用户能够访问的内容的状况与此相似,尤为是对于Web应用程序。许多站点要求用户必须经过身份验证才能使用少数几个URL(例如,主页和登陆页面)。在这种状况下,最简单的是为这些特定的URL定义访问配置属性,而不是为每一个受保护的资源定义访问配置属性。换句话说,有时很高兴地说默认状况下须要ROLE_SOMETHING,而且只容许该规则的某些例外,例如应用程序的登陆,注销和主页。您还能够从过滤器链中彻底忽略这些页面,从而绕过访问控制检查, 这就是咱们所说的匿名身份验证。

使用 permitAll() 将配置受权,以便在该特定路径上容许全部请求(来自匿名用户和已登陆用户),anonymous() 主要是指用户的状态(是否登陆)。基本上,直到用户被“认证”为止,它就是“匿名用户”。就像每一个人都有“默认角色”同样。

7. 总结

基于配置来解决基于角色的访问控制是经常使用的方案之一。也是最容易入门的 **Spring Security ** 访问控制技术。下一期咱们将介绍基于方法的访问控制。敬请关注 felord.cn。

关注公众号:Felordcn获取更多资讯

我的博客:https://felord.cn

相关文章
相关标签/搜索