Spring Security专栏(Security 中的权限和角色)

·  阅读 151

小知识,大挑战!本文正在参与“程序员必备小知识”创作活动。

写在前面

通过前面几讲的介绍,相信你已经对 Spring Security 中的认证流程有了更全面的了解。认证是实现授权的前提和基础

通常我们在执行授权操作时需要明确目标用户,只有明确目标用户才能明确它所具备的角色和权限,用户、角色和权限也是 Spring Security 中所采用的授权模型,所以今天我们来学习Security中的权限和角色。

多说一句 欢迎大家点击我头像查看Security专栏,设计模式专栏已完结。

Spring Security 中的权限和角色

我们可以回顾下,配置方法的处理过程位于 WebSecurityConfigurerAdapter 类中,但使用的是另一个 configure(HttpSecurity http) 方法,示例代码如下所示:

protected void configure(HttpSecurity http) throws Exception {
        http
           .authorizeRequests().anyRequest().authenticated()
           .and()
           .formLogin()
           .and()
           .httpBasic();
}
复制代码

这是 Spring Security 中作用于访问授权的默认实现方法。

基于权限进行访问控制

image.png

上图中的 GrantedAuthority 对象代表的就是一种权限对象,而一个 UserDetails 对象具备一个或多个 GrantedAuthority 对象。通过这种关联关系,实际上我们就可以对用户的权限做一些限制,如下所示:

image.png

如果用代码来表示这种关联关系,可以采用如下所示的实现方法:

UserDetails user = User.withUsername("yn")
     .password("123456")
     .authorities("create", "delete")
     .build();
复制代码

可以看到,这里我们创建了一个名为“jianxiang”的用户,该用户具有“create”和“delete”这两个权限。在 Spring Security 中,提供了一组针对 GrantedAuthority 的配置方法。例如:

  • hasAuthority(String),允许具有特定权限的用户进行访问;

  • hasAnyAuthority(String),允许具有任一权限的用户进行访问。

可以使用上述两个方法来判断用户是否具备对应的访问权限,我们在WebSecurityConfigurerAdapter 的 configure 方法中添加如下代码:

@Override
protected void configure(HttpSecurity http) throws Exception {
        http.httpBasic();
    http.authorizeRequests().anyRequest().hasAuthority("CREATE");        
}
复制代码

这段代码的作用是对于任何请求,只有权限为“CREATE”才能采用访问。如果我们修改一下代码:

http.authorizeRequests().anyRequest().hasAnyAuthority("CREATE", "DELETE");
复制代码

此时,只要具备“CREATE”和“DELETE”中任意一种权限的用户都能进行访问。

这两个方法实现起来都比较简单,但局限性也很大,因为我们无法基于一些来自环境和业务的参数灵活控制访问规则。为此,Spring Security 还提供了一个 access() 方法,该方法允许开发人员传入一个表达式进行更加细粒度的权限控制。

这里,我们将引入 SpEL,它是 Spring Expression Language 的简称,是 Spring 框架提供的一种动态表达式语言。基于 SpEL,只要该表达式的返回值是 true,access() 方法就会允许用户访问。如下示例:

http.authorizeRequests().anyRequest().access("hasAuthority('CREATE')");
复制代码

上述代码与使用 hasAuthority() 方法的效果是完全一致的,但如果是更为复杂的场景,access() 方法的优势就很明显了。我们可以灵活创建一个表达式,然后通过 access() 方法确定最后的结果,示例代码如下所示:

String expression = "hasAuthority('CREATE') and !hasAuthority('Retrieve')"; 
http.authorizeRequests().anyRequest().access(expression);
复制代码

上述代码的效果是只有拥有“CREATE”权限且不拥有“Retrieve”权限的用户才能进行访问。

基于角色进行访问控制

讨论完权限,我们再来看角色,你可以把角色看成是拥有多个权限的一种数据载体,如下图所示,这里我们分别定义了两个不同的角色“User”和“Admin”,它们拥有不同的权限:

image.png

讲到这里,你可能会认为 Spring Security 应该提供了一个独立的数据结构来承载角色的含义。但事实上,在 Spring Security 中,并没有定义类似“GrantedRole”这种专门用来定义用户角色的对象,而是复用了 GrantedAuthority 对象。事实上,以“ROLE_”为前缀的 GrantedAuthority 就代表了一种角色,因此我们可以使用如下方式初始化用户的角色:

UserDetails user = User.withUsername("yn")
      .password("123456")
      .authorities("ROLE_ADMIN")
      .build();
复制代码

上述代码相当于为用户“jianxiang”指定了“ADMIN”这个角色。为了给开发人员提供更好的开发体验,Spring Security 还提供了另一种简化的方法来指定用户的角色,如下所示

UserDetails user = User.withUsername("yn")
      .password("123456")
      .roles("ADMIN")
      .build();
复制代码

和权限配置一样,Spring Security 也通过使用对应的 hasRole() 和 hasAnyRole() 方法来判断用户是否具有某个角色或某些角色,使用方法如下所示:

http.authorizeRequests().anyRequest().hasRole("ADMIN");
复制代码

当然,针对角色,我们也可以使用 access() 方法完成更为复杂的访问控制。而 Spring Security 还提供了其他很多有用的控制方法供开发人员进行灵活使用。作为总结,下表展示了常见的配置方法及其作用:

配置方法作用
anonymous()允许匿名访问
authenticated()允许认证用户访问
denyAll()无条件禁止一切访问
hasAnyAuthority(String)允许具有任一权限的用户进行访问
hasAnyRole(String)允许具有任一角色的用户进行访问
hasAuthority(String)允许具有特定权限的用户进行访问
hasIpAddress(String)允许来自特定 IP 地址的用户进行访问
hasRole(String)允许具有特定角色的用户进行访问
permitAll()无条件允许一切访问

Spring Security 中的配置方法列表

好了,今天Security 中的权限和角色就讲到这里。

总结

这一讲我们关注的是对请求访问进行授权,而这个过程需要明确 Spring Security 中的用户、权限和角色之间的关联关系。一旦我们对某个用户设置了对应的权限和角色,那么就可以通过各种配置方法来有效控制访问权限。下期我们讲权限的匹配器,下期见,加油。

弦外之音

感谢你的阅读,如果你感觉学到了东西,麻烦您点赞,关注。也欢迎有问题我们下面评论交流

加油! 我们下期再见!

给大家分享几个我前面写的几篇骚操作

聊聊不一样的策略模式(值得收藏)

copy对象,这个操作有点骚!

分类:
后端
标签:
分类:
后端
标签: