查看原文
其他

Spring Boot 2.6之后,动态权限控制终于可以用起来了!

程序猿DD 2021-12-11

The following article is from 码农小胖哥 Author 请关注星标

Spring Security 5.6 发布有些时间了。随着Spring Boot 2.6的发布Spring Security 5.6终于有机会上生产了。在Spring Security 5.6中动态权限控制更加清晰简单了,今天就带你来尝尝鲜。

节奏快起来

是的,现在不光Java在提速,连Spring的速度现在也提起来了。新的东西越来越多。现在Spring Boot的版本生命周期缩短了到半年,每半年就发一个版本。而Spring Security的版本生命周期也有类似的改变。

Spring Security版本生命周期

作为Spring工程师而言,学习的节奏也不得不加快了。这是一个残酷的事实,这里简单提一下,好了,我们回归正题。

Spring Security动态权限

如果你的接口权限非常稳定,我推荐你使用注解方式;反之,使用动态权限控制。动态权限控制更加灵活和贴近现实,但是开发成本也高。

最常见的方式

之前Spring Security提供的动态权限控制门槛挺高的,需要实现一个FilterInvocationSecurityMetadataSource接口。而且目前网上大部分的教程还是这样的,因此就不再赘述了。

基于SpEL方式

上面方法的成本太高了,因此在后续的版本中基于Spring表达式语言又提供了一种可以实现动态权限的方式。这种方式有一定的要求:

  1. 首先要有一个Spring Bean。
  2. 这个Spring Bean必须包含一个公开方法;返回值为布尔值;参数列表有两个参数,第一个参数是当前认证的信息Authentication,第二个参数是当前请求HttpServletRequest。很好理解就是拿着当前请求去和当前认证信息中包含的角色进行访问控制判断。
  3. 然后按照@bean名称.方法名(authentication,request)的格式配置到HttpSecurity 对象中。

伪代码是这样的:

    @Bean
    RoleChecker roleChecker() {
        // 包含了一个符合SpEL要求的方法
        //  boolean check(Authentication authentication, HttpServletRequest request);
        return new JdbcRoleChecker();
    }

配置到HttpSecurity:

        httpSecurity.authorizeRequests()
                .anyRequest()
                .access("@roleChecker.check(authentication,request)");

在Spring Security 5.6之前这样做是最简单的,需要你深入了解Spring Security和SpEL才行。

AuthorizationManager

Spring Security 5.6 增加了一个新的授权管理器接口AuthorizationManager<T>,它让动态权限的控制接口化了。它用来检查当前认证信息Authentication是否可以访问特定对象T。上面的RoleChecker不就是AuthorizationManager<HttpServletRequest>么?AuthorizationManager将这种访问决策抽象的更加泛化。

@FunctionalInterface
public interface AuthorizationManager<T> {
 
 default void verify(Supplier<Authentication> authentication, T object) {
  AuthorizationDecision decision = check(authentication, object);
        // 授权决策没有经过允许就403
  if (decision != null && !decision.isGranted()) {
   throw new AccessDeniedException("Access Denied");
  }
        // todo 没有null 的情况
 }

    // 钩子方法。
 @Nullable
 AuthorizationDecision check(Supplier<Authentication> authentication, T object);

}

在Spring Security 5.6中,我们就可以这样去实现了:

        httpSecurity.authorizeHttpRequests()
                .anyRequest()
                .access((authenticationSupplier, requestAuthorizationContext) -> {
                    // 当前用户的权限信息 比如角色
                    Collection<? extends GrantedAuthority> authorities = authenticationSupplier.get().getAuthorities();
                    // 当前请求上下文
                    // 我们可以获取携带的参数
                    Map<String, String> variables = requestAuthorizationContext.getVariables();
                    // 我们可以获取原始request对象
                    HttpServletRequest request = requestAuthorizationContext.getRequest();
                    //todo 根据这些信息 和业务写逻辑即可 最终决定是否授权 isGranted
                    boolean isGranted = true;
                    return new AuthorizationDecision(isGranted);
                });

这样门槛是不是低多了呢?

你还会选择每次修改权限都要打jar包发版的注解权限控制吗?



往期推荐



OAuth 2.0中的scope和RBAC中的role有什么关系

Spring Boot 2.6 正式发布:循环依赖默认禁止、增加SameSite属性...

Spring OAuth2 授权服务器配置详解

使用 @Transactional 时常犯的N种错误

授权服务框架Spring Authorization Server的过滤器链



技术交流群

最近有很多人问,有没有读者交流群,想知道怎么加入。加入方式很简单,有兴趣的同学,只需要点击下方卡片,回复“加群“,即可免费加入我们的高质量技术交流群!

点击阅读原文,送你免费Spring Boot教程!

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存