当前位置: 首页 > 知识库问答 >
问题:

带有@Secured和@PreAuthorize的注释类不保护超级方法

齐英朗
2023-03-14

我创建了一个包含一些基本crud方法的CrudController。这很好用。当我想保护这个控制器时,我可以重写超类中的方法,这很好。然而,我不想仅仅为了安全而重写每个方法。为此,我想在类上使用@Secured或@PreAuthorize。

我使用的是Spring Boot 2.2.2(最新版本)。

示例Crud基类

public class CrudController<T, ID> {
    @GetMapping
    public ResponseEntity<List<T>> findAll() {
        // code for returning the list
    }
}

实现类

@RestController
@RequestMapping("/helloworld")
@Secured("ROLE_world.view") 
public class HelloWorld extends CrudController<World, Long> {

   @GetMapping("test")
   public ResponseEntity test() {
      // This method is secured by the annotation on the class
   }

   // the findAll from the super class is not secured

}

预期行为
当一个类被注释为@PreAuthorize或@安全时,我希望所有公共方法都是安全的。因此,扩展类中的所有公共方法也应该受到保护。在我的示例中,findAll是不安全的,这是一个很高的安全风险。

尝试
我已经尝试为配置设置以下注释:

在类本身上:

@Scope( proxyMode = ScopedProxyMode.TARGET_CLASS )

在configuration类上:

@Configuration
@EnableAspectJAutoProxy
@EnableWebSecurity
@EnableGlobalMethodSecurity(
        prePostEnabled = true,
        securedEnabled = true,
        jsr250Enabled = true,
        mode = AdviceMode.PROXY,
        proxyTargetClass = true
)

在应用程序中。属性:

spring.aop.proxy-target-class=true
spring.aop.auto=true

共有2个答案

壤驷喜
2023-03-14

作为解决方案,我创建了一个扩展HandlerInterceptorAdapter的类。这只适用于受保护的,因为这样更容易检查角色。

@Component
public class SecuredInterceptor extends HandlerInterceptorAdapter {
    private static final Logger LOGGER = getLogger(SecuredInterceptor.class);


    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        LOGGER.debug("preHandle {}", handler.getClass());

        if (!(handler instanceof HandlerMethod)) {
            return super.preHandle(request, response, handler);
        }

        HandlerMethod handlerMethod = (HandlerMethod) handler;
        String[] allowedRoles = getAllowedRoles(handlerMethod);

        // No allowed roles, so allow everything
        if (allowedRoles.length == 0) {
            return super.preHandle(request, response, handler);
        }

        // Check if we have the needed role
        for (String allowedRole : allowedRoles) {
            // SecurityUtil checks if an loggedIn keycloak user has the right role 
            if (SecurityUtil.hasRole(allowedRole)) {
                return super.preHandle(request, response, handler);
            }
        }

        // UnauthorizedException is a custom exception which is handle in an @AdviceController
        throw new UnauthorizedException("Forbidden");
    }

    private String[] getAllowedRoles(HandlerMethod method) {
        Class<?> targetClass = method.getBean().getClass();
        Secured[] annotationsByType = targetClass.getAnnotationsByType(Secured.class);
        Secured methodAnnotation = method.getMethodAnnotation(Secured.class);

        // Methods are overriding class annotations
        if (methodAnnotation != null) {
            return methodAnnotation.value();
        }

        // Get from the class
        if (annotationsByType.length > 0) {
            return annotationsByType[0].value();
        }

        // No annotations
        return new String[0];
    }
}

我在WebConfig中配置此拦截器:

@Configuration
public class WebConfig implements WebMvcConfigurer {
    @Override
    public void addInterceptors(InterceptorRegistry registry) {
        registry.addInterceptor(securedInterceptor);
    }
}

如果你认为我应该接受自己的答案,请投赞成票<欢迎提出意见或其他解决方案。

赫连飞沉
2023-03-14

安全的注释在类AbstractFallbackMethod odSecurityMetadataSource中处理,方法如下:

public Collection<ConfigAttribute> getAttributes(Method method, Class<?> targetClass) {
        // The method may be on an interface, but we need attributes from the target
        // class.
        // If the target class is null, the method will be unchanged.
        Method specificMethod = AopUtils.getMostSpecificMethod(method, targetClass);
        // First try is the method in the target class.
        Collection<ConfigAttribute> attr = findAttributes(specificMethod, targetClass);
        if (attr != null) {
            return attr;
        }

        // Second try is the config attribute on the target class.
        attr = findAttributes(specificMethod.getDeclaringClass());
        if (attr != null) {
            return attr;
        }

        if (specificMethod != method || targetClass == null) {
            // Fallback is to look at the original method.
            attr = findAttributes(method, method.getDeclaringClass());
            if (attr != null) {
                return attr;
            }
            // Last fallback is the class of the original method.
            return findAttributes(method.getDeclaringClass());
        }
        return Collections.emptyList();
}

因此,如果方法没有安全的注释,则在声明类findAttributes(method.getDeclaringClass())中搜索注释,对于您的情况,findAll的声明类是没有任何安全注释的CrudController。

要解决此问题,您应该提供自己的MethodSecurityMetadataSource实现。

下面是一个简单的方法:

>

public class CustomMethodSecurityMetadaSource extends
    SecuredAnnotationSecurityMetadataSource {

    public CustomMethodSecurityMetadaSource(){
        super();
    }
    @Override
    public Collection<ConfigAttribute> getAttributes(Method method,
    Class<?> targetClass) {
        Collection<ConfigAttribute> attr =  super.getAttributes(method, targetClass);
        if (CollectionUtils.isEmpty(attr)) {
            attr = findAttributes(targetClass);
            if (attr != null) return attr;
        }
        return Collections.emptyList();
    }
}

通过扩展GlobalMethod odSecurityConfiguration注入自定义实现:

@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true)
@Configuration
public class SecuredConfig extends GlobalMethodSecurityConfiguration {
    @Override
    protected MethodSecurityMetadataSource customMethodSecurityMetadataSource() {
        return new CustomMethodSecurityMetadaSource();
    }
}
 类似资料:
  • Spring.version:4.0.5.release Spring security Version:3.2.5.release Spring security oauth版本:2.0.2.release 球衣版本:1.18.1 我想使用Spring security的PreAuthorize注释来保护我的REST API,在这里我定义了被授权访问方法的角色: 当我使用角色为“role_adm

  • 我正在使用来控制的状态,但是我在执行过程中遇到了一个错误。 原因:org.greenrobot.eventbus.事件总线异常:订阅者类maa. Mainactive及其超类没有带有@Subcribe注释的公共方法 无线电经理。JAVA

  • 我有这个问题,无法理解如何修复它,任何帮助都将得到评估。我需要用一些身份验证来保护REST方法,并且我在我的应用程序中有几个角色。我在我的类中的方法中放置了注释,实现了一些接口和Spring没有创建没有任何日志消息的bean(在我的例子中)。但是如果类没有实现接口-bean创建得很好。 在代码中,它如下所示: 控制器: 接口: 在我的情况下,控制器bean没有创建。但是如果我删除一切都会正常工作,

  • 我正在实现来传递和获取来自任何类或片段的数据,并且还订阅了一个方法来获取即时更改的数据...但是我收到了以下错误消息: 组织。绿色机器人。事件巴士。EventBusException:订阅者类java。Boolean及其超类没有带有@Subscribe注释的公共方法 我已经订阅了github在这里展示的方法 代码片段 我只发布了应用程序所需的代码,因为这里不需要其他代码 适配器 更新活动类 新错误

  • 我有一个用Java Spring MVC构建的web应用程序,并使用Spring Security进行登录。登录/退出工作很好。有两个用户角色“role_admin”和“role_user”。 我想确保我的方法只能由具有“role_admin”角色的用户访问。 我添加了批注,如下所示...

  • 我正在使用EventBus创建一个Android应用程序,用于向其他类发布异步广播,但在执行过程中遇到了一个错误。 LogCat显示以下内容: 为什么会这样?我做错什么了吗?