反验AnyRequest()。denyall(),具有方法级别和类级别的安全注释

问题描述 投票:0回答:1
situation

开发Web应用程序时,拥有SANE安全默认值通常很有用。对于我的Web API,我想默认情况下关闭对所有资源的访问。没有人应该能够访问端点。

,但是,我想使用诸如

@Secured

@RolesAllowed
@PermitAll
@PreAuthorize
。 furthermore,我希望
/login

/register

路公开。

现在,我已经创建了遵循安全配置(我将其删除到最重要的部分):
fun securityFilterChain(http: HttpSecurity): SecurityFilterChain =
http
    .csrf { it.disable() }
    .authorizeHttpRequests {
        it
            .requestMatchers(HttpMethod.POST, "/auth/register", "/auth/login")
            .permitAll()
            .anyRequest()
            .denyAll()
    }
// ... further config
.build()

您可以看到,除了上面提到的路径外,我已经访问了所有路径。

问题

我的配置问题是
denyAll()
过早地取消过滤器链。也就是说,该框架根本无法评估我的控制器/方法级别注释。自动返回禁止的

403

我想要什么

示例1

现在我想在控制器中执行以下操作:
@RestController
class TodoController(private val todoService: TodoService) {
    
    // ONLY users with role admin
    @RolesAllowed(Role.ADMIN_VALUE)
    // @<Some HTTP mapping>
    fun method0()

    // ONLY users with roles admin and user
    @RolesAllowed(Role.ADMIN_VALUE, Role.USER_VALUE)
    // @<Some HTTP mapping>
    fun method1()

    // ANY "authn" user, independent of their "auhtz" status
    @PreAuthorize("isAuthenticated()")
    fun method2()

    // Anyone, independent of their "authn" / "authz" status
    @PermitAll
    // @<Some HTTP mapping>
    fun method3()

    // UUUUPPPPPPSSS..... Forgot to annotate? No problem, NO ONE can call this!
    // @<Some HTTP mapping>
    fun method4()
}

在上面可以看到的是,注释可以对端点进行颗粒状控制。如果开发人员忘记了正确注释端点方法,则不会造成损坏,因为系统默认拒绝所有内容。

示例2

plapsose我们有一个控制器,其中所有端点方法都需要相同的设置。在这些情况下,仅注释类本身,而方法继承了此设置将很有帮助。

// Endpoint methods in this controller can be called by anyone, regardless of "authn" / "authz" status @PermitAll @RestController class TodoController // Endpoint methods in this controller can ONLY be called by admins @RolesAllowed(Role.ADMIN_VALUE) @RestController class TodoController // Endpoint methods in this controller can ONLY be called admins and regular users @RolesAllowed(Role.ADMIN_VALUE, Role.USER_VALUE) @RestController class TodoController // Endpoint methods in this controller can ONLY be called by logged-in users (regardless of their roles) @PreAuthorize("isAuthenticated()") @RestController class TodoController /* Endpoint methods in this controller cannot be called by anyone, because neither the controller, nor the methods have security annotations. The default configuration of denying everything automatically kicks in. */ @RestController class TodoController

示例3

您可能想象的是,如果控制器和方法都是注释的,那么我希望方法注释过度统治控制器注释:

@PreAuthorize("isAuthenticated()") @RestController class TodoController { // Overrides "isAuthenticated": Now anyone can call this @PermitAll fun foo() // Has inherited "isAuthenticated" from the controller fun bar() // Overrides "isAuthenticated": Only users with role admin can access @Secured(Role.ADMIN_VALUE) fun baz() }

问题

如何实现这一目标?我知道这是在春季启动中有可能的事实,因为Vaadin框架遵循类似的方法。但是,由于这是一个常规的Spring Boot应用程序,而没有依赖Vaadin,因此我对如何执行此操作一无所知。我也找不到令人满意的答案。 lastly ...是的,我知道,我可以为每个端点方法设置

SecurityConfig

中的路径配置。但是,那不是我想要的。我想要对控制器/端点方法的明确控制。
	
我面对与Java应用程序所需的相同情况。经过漫步的弹簧安全文档和代码后,我决定实施

custom授权manager

,以替换默认的

preauthorizeauthorizationmanager

我自己的授权决定。 this Custom
PreAuthorizeAuthorizationManager
仅将决定委派给了共同的Spring Security实施,如果没有决定(所谓的方法没有JSR250/PREATUTHORIZE注释)返回拒绝请求的and。

AuthorizationDecision

,然后我们需要将带有点插的方法发布到应运行此自定义的何时。下面的示例是在春季的

poreapectorinterceptor

实现中启发的,该实现是针对用

@Component
public class CustomDelegatingPreAuthorizeAuthorizationManager implements AuthorizationManager<MethodInvocation> {

    private static final AuthorizationDecision DENIED_DECISION = new AuthorizationDecision(false);

    private final AuthorizationManager<MethodInvocation> preAuthorizeDelegate = new PreAuthorizeAuthorizationManager();
    private final AuthorizationManager<MethodInvocation> jsr250Delegate = new Jsr250AuthorizationManager();

    @Override
    public AuthorizationDecision check(final Supplier<Authentication> authentication, final MethodInvocation object) {
        return Optional.ofNullable(preAuthorizeDelegate.authorize(authentication, object))
            .or(() -> Optional.ofNullable(jsr250Delegate.authorize(authentication, object)))
            .filter(AuthorizationDecision.class::isInstance)
            .map(AuthorizationDecision.class::cast)
            .orElse(DENIED_DECISION);
    }

}
注释的方法的,我替换为用

AuthorizationManager
spring spring-boot kotlin spring-security vaadin
1个回答
0
投票
注:如果您观察到,我将委派JSR250授权管理器,而不是在

@PreAuthorize中启用。原因是在自定义管理人中,总是返回@RequestMapping,如果Mehtod没有注释,将是一个被拒绝的决定,这使得Spring未拨打下一个@RestController

@EnableMethodSecurity(jsr250Enabled = true)

最后但并非最不重要的一点是,我们需要更改
AuthorizationDecision
允许所有请求,这将使弹簧始终在滤链中呼叫

AuthorizationInterception
,并在
@Configuration @EnableMethodSecurity public class MethodSecurityConfig { @Bean @Role(BeanDefinition.ROLE_INFRASTRUCTURE) public Advisor preAuthorize(final CustomDelegatingPreAuthorizeAuthorizationManager manager) { final Pointcut pointcut = Pointcuts.union( new AnnotationMatchingPointcut(null, RequestMapping.class, true), new AnnotationMatchingPointcut(RequestMapping.class, true) ); final AuthorizationManagerBeforeMethodInterceptor interceptor = new AuthorizationManagerBeforeMethodInterceptor( pointcut, manager ); interceptor.setOrder(AuthorizationInterceptorsOrder.PRE_AUTHORIZE.getOrder()); return interceptor; } }

.

中做出决定。
SecurityFilterChain 不幸的是,我认为这种方法不会涵盖您给出的所有示例,尤其是在示例3中,您在班级级别上有一个PreAuthorizedMethodInterceptor
,并且可以覆盖方法级别。正如我之前提到的那样,
CustomAuthorizationManager
将始终返回一个
@EnableWebSecurity public class WebSecurityConfiguration { @Bean public SecurityFilterChain defaultSecurityFilterChain( final HttpSecurity http ) throws Exception { return http .authorizeHttpRequests(authorize -> authorize .anyRequest().permitAll() ) .build(); } }
,然后在控制器级别中找到一个
@PreAuthorize

当该方法无法执行JSR250。 对于我的场景,一旦我总是使用

@PermitAll

,这应该可以起作用。
CustomAuthorizationManager
我不确定这是否是正确的方法,而是对我有用的,希望可以帮助您。
    

最新问题
© www.soinside.com 2019 - 2025. All rights reserved.