如何为从 spring amqp 消息完成的事务建立安全上下文

how to establish security context for transactions done from spring amqp messages

我有一个 spring 引导应用程序,我使用 spring 安全注释为其保护方法,如下所示。

public interface UserService {

    @PreAuthorize("hasRole('ADMIN')")
    List<User> findAllUsers();

    @PostAuthorize ("returnObject.type == authentication.name")
    User findById(int id);

    @PreAuthorize("hasRole('ADMIN')")
    void updateUser(User user);

    @PreAuthorize("hasRole('ADMIN') AND hasRole('DBA')")
    void deleteUser(int id);

}

我在这里遇到的问题是,有些实现是通过 @RabbitListener 方法调用的,但没有任何安全上下文,因为它不是 Web 请求。

我希望客户端通过消息传递用户名 headers sp 我可以使用 message.getMessageProperties().getHeaders().get("username") 来获取该请求的用户名。

但我仍然相信不会有直接的方法,因为方法级注释不会被评估,因为它们不在安全上下文中。

有什么方法可以为 spring amqp 消息建立安全上下文吗?

只需添加上下文...

@SpringBootApplication
@EnableGlobalMethodSecurity(prePostEnabled = true)
public class So49957413Application extends GlobalAuthenticationConfigurerAdapter {

    public static void main(String[] args) {
        SpringApplication.run(So49957413Application.class, args);
    }

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth.inMemoryAuthentication()
            .withUser("foo").password("bar").roles("baz");
    }

    @Autowired
    private Foo foo;


    @RabbitListener(queues = "foo")
    public void listen(Message in) {
        try {
            SecurityContext ctx = SecurityContextHolder.createEmptyContext();
            ctx.setAuthentication(
                new UsernamePasswordAuthenticationToken(in.getMessageProperties().getHeaders().get("user"), "bar"));
            SecurityContextHolder.setContext(ctx);
            this.foo.method1();
            try {
                this.foo.method2();
            }
            catch (AccessDeniedException e) {
                System.out.println("Denied access to method2");
            }
        }
        finally {
            SecurityContextHolder.clearContext();
        }
    }

    @Bean
    public Foo foo() {
        return new Foo();
    }

    public static class Foo {

        @PreAuthorize("hasRole('baz')")
        public void method1() {
            System.out.println("in method1");
        }

        @PreAuthorize("hasRole('qux')")
        public void method2() {
            System.out.println("in method2");
        }

    }
}

in method1
Denied access to method2

最好在侦听器容器的通知链中 add/remove 通知中的安全上下文,以避免将安全代码与侦听器逻辑混合。