最新公告
  • 新注册用户请前往个人中心绑定邮箱以便接收相关凭证邮件!!!点击前往个人中心
  • Spring Security 实战:基于配置的接口角色访问控制

    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 中相关源码:
    publicfinalbooleanhasRole(String role) {
    return hasAnyRole(role);
    }
    很明显 hasRole 方法源于 hasAnyRole (持有任何其中角色之一,就能满足访问条件,用于一个接口开放给多个角色访问时) :
    publicfinalbooleanhasAnyRole(String… roles) {
    return hasAnyAuthorityName(defaultRolePrefix, roles);
    }
    如果某接口开放给多个角色,比如 /foo/test 开放了 ROLE_APP 和 ROLE_ADMIN 可以这么写:
    httpSecurity.authorizeRequests().antMatchers(“/foo/test”).hasAnyRole(“APP”,”ADMIN”)
    hasAnyRole 方法最终的实现为 hasAnyAuthorityName(String prefix, String… roles):
    privatebooleanhasAnyAuthorityName(String prefix, String… roles) {
    Set<String> roleSet = getAuthoritySet();
    for (String role : roles) {
    String defaultedRole = getRoleWithDefaultPrefix(prefix, role);
    if (roleSet.contains(defaultedRole)) {
    returntrue;
    }
    }
    returnfalse;
    }
    上面才是根本的实现, 需要一个 prefix 和每一个 role 进行拼接,然后用户的角色集合 roleSet 中包含了就返回true 放行,否则就 false 拒绝。默认的 prefix 为 defaultRolePrefix= ROLE_ 。

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

    我们也可以通过 hasAuthority 和 hasAnyAuthority 来判定。 其实底层实现和 hasAnyRole 方法一样,只不过 prefix 为 null 。也就是你写入的 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 的一些探讨

    开放请求 其实通常情况下跟 匿名请求 有交叉。它们的主要区别在于: 当前的 Authentication 为 null 时 permitAll 是放行的,而 anonymous 需要 Authentication 为 AnonymousAuthenticationToken 。这里是比较难以理解的,下面是来自 Spring 文档中的一些信息:
    通常,采用“默认拒绝”的做法被认为是一种良好的安全做法,在该方法中,您明确指定允许的内容,并禁止其他所有内容。定义未经身份验证的用户可以访问的内容的情况与此类似,尤其是对于Web应用程序。许多站点要求用户必须通过身份验证才能使用少数几个URL(例如,主页和登录页面)。在这种情况下,最简单的是为这些特定的URL定义访问配置属性,而不是为每个受保护的资源定义访问配置属性。换句话说,有时很高兴地说默认情况下需要ROLE_SOMETHING,并且只允许该规则的某些例外,例如应用程序的登录,注销和主页。您还可以从过滤器链中完全忽略这些页面,从而绕过访问控制检查, 这就是我们所说的匿名身份验证。
    使用 permitAll() 将配置授权,以便在该特定路径上允许所有请求(来自匿名用户和已登录用户),anonymous() 主要是指用户的状态(是否登录)。基本上,直到用户被“认证”为止,它就是“匿名用户”。就像每个人都有“默认角色”一样。
    本站所有文章均由网友分享,仅用于参考学习用,请勿直接转载,如有侵权,请联系网站客服删除相关文章。若由于商用引起版权纠纷,一切责任均由使用者承担
    极客文库 » Spring Security 实战:基于配置的接口角色访问控制

    常见问题FAQ

    如果资源链接失效了怎么办?
    本站用户分享的所有资源都有自动备份机制,如果资源链接失效,请联系本站客服QQ:2580505920更新资源地址。
    如果用户分享的资源与描述不符怎么办?
    可以联系客服QQ:2580505920,如果要求合理可以安排退款或者退赞助积分。
    如何分享个人资源获取赞助积分或其他奖励?
    本站用户可以分享自己的资源,但是必须保证资源没有侵权行为。点击个人中心,根据操作填写并上传即可。资源所获收益完全归属上传者,每周可申请提现一次。
    如果您发现了本资源有侵权行为怎么办?
    及时联系客服QQ:2580505920,核实予以删除。

    参与讨论

    • 169会员总数(位)
    • 3735资源总数(个)
    • 1本周发布(个)
    • 0 今日发布(个)
    • 443稳定运行(天)

    欢迎加入「极客文库」,成为原创作者从这里开始!

    立即加入 了解更多
    成为赞助用户享有更多特权立即升级