前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Spring Security 实战干货:基于配置的接口角色访问控制

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

作者头像
码农小胖哥
发布2019-12-10 17:19:19
1.1K0
发布2019-12-10 17:19:19
举报

1. 前言

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

2. 将角色写入 UserDetails

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

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

我们可以通过配置 WebSecurityConfigurerAdapter 中的 HttpSecurity 来控制接口的角色访问。

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

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

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

代码语言:javascript
复制

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

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

代码语言:javascript
复制

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

如果某接口开放给多个角色,比如 /foo/test 开放了 ROLE_APPROLE_ADMIN 可以这么写:

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

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

代码语言:javascript
复制
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.1 和 2.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。

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2019-11-14,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 码农小胖哥 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 1. 前言
  • 2. 将角色写入 UserDetails
  • 3. 在 HttpSecurity 中进行配置角色访问控制
    • 3.1 通过判断用户是否持有角色来进行访问控制
      • 3.2 通过判断用户的 GrantedAuthority 来进行访问控制
      • 4. 匿名访问
      • 5. 开放请求
      • 6. permitAll 与 anonymous 的一些探讨
      • 7. 总结
      相关产品与服务
      多因子身份认证
      多因子身份认证(Multi-factor Authentication Service,MFAS)的目的是建立一个多层次的防御体系,通过结合两种或三种认证因子(基于记忆的/基于持有物的/基于生物特征的认证因子)验证访问者的身份,使系统或资源更加安全。攻击者即使破解单一因子(如口令、人脸),应用的安全依然可以得到保障。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档